先确认日志是否拖垮磁盘:用 iostat 和 iotop 定位高写入 nginx worker,再用 lsof 查其日志文件;禁用 log_if,改用缓冲 access_log + 自定义格式,剥离防盗链日志至独立缓冲路径,并关闭 debug 日志与非法请求体写入。

确认是不是日志在拖垮磁盘
先别猜,用工具锁定真实源头:
- 运行 iostat -x 1 3,重点关注 %util > 95% 且 await > 50ms、w/s 高但 r/s 很低 的设备——这说明写入排队严重
- 执行 sudo iotop -o -P,按 I/O% 排序,找 nginx worker 进程是否持续占前几位;再对 PID 执行 lsof -p $PID | grep log,确认它正在往哪个日志文件(如 /var/log/nginx/access.log)高频写入
- 检查 access_log 是否开了大量条件日志:比如
log_if $invalid_referer或if ($invalid_referer) { access_log /var/log/nginx/blocked.log; }——这类配置会让每个被拦截请求都触发一次独立 open/write/close,比普通日志更伤 IO
收紧防盗链日志的粒度和路径
防盗链本身要留痕,但不能每条都落盘:
- 把防盗链拒绝日志单独剥离:
error_log /var/log/nginx/referer_rej.log warn;,并配 limit_req_log_level warn(如果用了限流配合防盗链) - 禁用
log_if动态开关日志,改用统一 access_log + 自定义格式,在 log_format 中加入$invalid_referer和$sent_http_x_reject_reason等变量,让所有请求走同一条写入路径,便于缓冲聚合 - 对已确认的白名单 referer(如 CDN 域名、合作站点),用
map提前标记为$is_trusted 1,再在 log_format 中只记录$is_trusted == 0的请求,大幅减少日志体积
强制启用日志缓冲并隔离写入路径
让日志从“每请求刷盘”变成“攒批异步落盘”:
- 主 access_log 必须加缓冲:
access_log /var/log/nginx/access.log main buffer=64k flush=3s;(3–5 秒足够平衡延迟与可靠性) - 防盗链专用日志也缓冲:
access_log /var/log/nginx/referer_blocked.log blocked_fmt buffer=32k flush=2s; - 把日志目录挂到独立 SSD 分区(如 /data/logs/nginx),挂载参数加
noatime,nobarrier,避免元数据更新拖慢写入
关掉干扰项,防止雪上加霜
防盗链场景常伴随其他隐性 IO 源:
- 检查是否启用了
client_body_in_file_only on或大 body 上传,防盗链校验失败后仍会把非法请求体写临时文件——应设client_max_body_size 1m;并配client_body_timeout 5s;快速中断 - 确认没开
debug级 error_log:error_log /var/log/nginx/error.log error;即可,debug 级在 referer 匹配逻辑中会产生指数级日志 - 若用了
ngx_http_secure_link_module或自定义 Lua 防盗链,确保其日志输出也走 syslog 或异步通道,不直写文件


















