1. Nginx日志基础:从入门到精通
作为一名运维老兵,我处理过的Nginx日志文件连起来能绕机房三圈。日志看似简单,却是排查问题的第一现场。不同于教科书式的概念堆砌,咱们直接切入实战视角——当你第一次打开Nginx日志文件时,迎面而来的可能是这样的混乱场景:
code复制192.168.1.105 - - [15/Jul/2023:14:23:45 +0800] "GET /static/css/main.css HTTP/1.1" 200 4832 "https://example.com/login" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
这行日志包含了11个关键信息字段,但默认配置下它们挤在一起像春运火车站。理解每个字段的含义是日志分析的基本功:
192.168.1.105:客户端IP地址(可能是真实IP或代理服务器IP)- 第一个
-:远程用户标识(通常未启用identd服务) - 第二个
-:认证用户名(如果启用HTTP Basic Auth) [15/Jul/2023:14:23:45 +0800]:请求时间戳(服务器本地时区)"GET /static/css/main.css HTTP/1.1":请求方法+URI+协议版本200:HTTP状态码(这里是成功响应)4832:响应体字节数(不包含响应头)"https://example.com/login":Referer来源页"Mozilla/5.0...":User-Agent客户端信息
关键技巧:用
awk快速提取关键字段。例如提取所有404请求的URI:
awk '$9==404 {print $7}' access.log | sort | uniq -c | sort -nr
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 深度定制日志格式:log_format的进阶玩法
Nginx的log_format指令就像乐高积木,能组合出各种监控方案。在/etc/nginx/nginx.conf中,默认的combined格式长这样:
nginx复制log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
但真实业务场景中,这些远远不够。去年我们电商大促时,就靠自定义日志发现了爬虫攻击:
nginx复制log_format security '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent $request_time '
'"$http_referer" "$http_user_agent" '
'$http_x_forwarded_for $upstream_addr $upstream_response_time';
几个高价值变量说明:
$request_time:请求处理总耗时(秒级精度)$http_x_forwarded_for:获取真实IP(当Nginx前有CDN时)$upstream_*:反向代理时的后端服务指标
实测案例:通过$request_time发现某API接口平均耗时从50ms突增到2s,最终定位到Redis连接池泄漏。
2.1 JSON日志:ELK系统的黄金搭档
现代日志系统普遍采用JSON格式,在Nginx中只需:
nginx复制log_format json_analytics escape=json
'{"timestamp":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"body_bytes":$body_bytes_sent,'
'"request_time":$request_time,'
'"upstream_time":"$upstream_response_time",'
'"referer":"$http_referer",'
'"agent":"$http_user_agent"}';
这样Filebeat可以直接解析字段,省去Grok正则的折磨。注意escape=json防止特殊字符破坏JSON结构。
3. 日志文件切割:避免单个文件撑爆磁盘
去年某次凌晨三点,我被报警短信吵醒——磁盘满了。检查发现是某个Nginx access.log文件达到了87GB。从此我成了logrotate的忠实信徒。
3.1 官方推荐的logrotate方案
在/etc/logrotate.d/nginx添加配置:
conf复制/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
关键参数解析:
daily:按天切割(还有weekly/monthly/yearly)rotate 30:保留30个历史版本compress:用gzip压缩旧日志(省70%空间)delaycompress:延迟压缩最近一个日志文件create 0640 www-data adm:新日志文件权限和属主
血泪教训:务必测试postrotate脚本!有次权限配置错误导致Nginx无法写入新日志,线上服务直接503。
3.2 高阶玩家的时间戳切割法
对于需要对接日志分析系统的场景,可以用cron+mv实现精准切割:
bash复制# 每天0点执行
0 0 * * * mv /var/log/nginx/access.log /var/log/nginx/access_$(date -d "yesterday" +"%Y%m%d").log && kill -USR1 $(cat /var/run/nginx.pid)
这样生成的日志文件名包含完整日期(如access_20230714.log),方便后续处理。
4. 日志分析实战:从原始数据到业务洞察
有了规范的日志后,真正的魔法开始了。分享几个我常用的分析套路:
4.1 高频错误监控
bash复制# 统计5分钟内HTTP 500错误
tail -n 10000 access.log | awk -v d1="$(date -d '5 minutes ago' +[%d/%b/%Y:%H:%M:%S)" -v d2="$(date +[%d/%b/%Y:%H:%M:%S)" '$4 >= d1 && $4 <= d2 && $9==500 {print $7}' | sort | uniq -c | sort -nr
4.2 慢请求分析
bash复制# 找出耗时超过3秒的请求
awk -F'"' '$6>3 {print $1,$6,$2,$3}' access.log | column -t
4.3 恶意IP封禁
bash复制# 统计1小时内访问量超1000次的IP
awk -v d1="$(date -d '1 hour ago' +[%d/%b/%Y:%H:%M:%S)" -v d2="$(date +[%d/%b/%Y:%H:%M:%S)" '$4 >= d1 && $4 <= d2 {print $1}' access.log | sort | uniq -c | sort -nr | awk '$1>1000 {print "deny " $2 ";"}'
输出结果可以直接加到Nginx配置的deny列表里。
5. 避坑指南:那些年我踩过的日志坑
5.1 缓冲区导致日志延迟
Nginx默认启用日志缓冲(每32KB或1秒刷盘)。当服务器突然崩溃时,可能丢失最后几条关键日志。解决方法:
nginx复制access_log /var/log/nginx/access.log combined buffer=16k flush=5s;
buffer=16k:减小缓冲区大小flush=5s:最多5秒强制刷盘
5.2 日志文件权限问题
新创建的日志文件可能因权限问题导致Nginx无法写入。确保:
bash复制chown www-data:adm /var/log/nginx/
chmod 0750 /var/log/nginx/
5.3 动态域名日志分离
当同时托管多个域名时,建议按域名分离日志:
nginx复制map $host $logname {
default "access";
"~*.example.com" "example_com";
"~*.api.example.com" "example_api";
}
access_log /var/log/nginx/${logname}.log combined;
这样不同业务的日志互不干扰,分析时也更聚焦。
