1. Nginx日志系统概述
作为一款高性能的Web服务器,Nginx的日志系统是运维人员监控服务状态、分析用户行为、排查故障的重要工具。我在管理日均百万PV的电商平台时,曾通过日志分析发现爬虫流量异常,及时调整了反爬策略,避免了服务器资源被恶意消耗。Nginx默认提供两种基础日志:
- 访问日志(access_log):记录每个请求的详细信息
- 错误日志(error_log):记录服务器运行时警告和错误信息
这两种日志采用不同的记录策略和格式,需要分别进行配置管理。访问日志会记录客户端IP、请求时间、请求方法、URI、状态码等关键信息,而错误日志则包含配置错误、后端连接超时、SSL握手失败等关键事件。
生产环境中务必分离这两种日志的存储路径,避免互相干扰。我曾遇到过错误日志暴增导致磁盘写满,但由于与访问日志分开存储,至少保证了访问记录的完整性。
2. 日志配置详解
2.1 访问日志配置
在nginx.conf中,access_log的基本语法如下:
nginx复制access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
典型的生产配置示例:
nginx复制http {
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
access_log /var/log/nginx/access.log main buffer=32k gzip=1 flush=5m;
}
关键参数说明:
buffer=32k:使用32KB内存缓冲区减少磁盘IOgzip=1:日志写入时进行gzip压缩(压缩级别1)flush=5m:缓冲区最长保留5分钟后强制写入磁盘
高流量场景下,缓冲区设置不当可能导致日志丢失。我们曾因buffer设置过小(4k)导致峰值期间丢失了15%的日志记录,后调整为32k后问题解决。
2.2 错误日志配置
error_log的配置更为简洁但同样重要:
nginx复制error_log /var/log/nginx/error.log warn;
日志级别从低到高分为:
- debug:最详细调试信息
- info:常规运行信息
- notice:重要但非错误条件
- warn:警告信息
- error:错误条件
- crit:严重错误
- alert:需要立即处理的错误
- emerg:系统不可用状态
线上环境建议使用warn级别,既不会遗漏重要错误,又避免记录过多调试信息。开发环境可设为info以便调试。
3. 高级日志技巧
3.1 条件日志记录
通过if条件实现精细化日志记录:
nginx复制map $status $loggable {
~^[23] 0; # 不记录2xx/3xx响应
default 1;
}
access_log /var/log/nginx/errors.log combined if=$loggable;
这个配置可以:
- 只记录4xx和5xx错误请求
- 节省60%以上的日志存储空间
- 方便快速定位问题请求
3.2 多日志分离
按业务类型分离日志:
nginx复制server {
# 主日志
access_log /var/log/nginx/store.access.log main;
# API专用日志
location /api/ {
access_log /var/log/nginx/api.access.log api_format;
}
# 静态资源日志
location ~* \.(jpg|png|css|js)$ {
access_log /var/log/nginx/static.access.log static_format;
}
}
这种架构的优势:
- 不同业务日志独立分析
- 避免单个日志文件过大
- 可按需设置不同的日志格式
4. 日志轮转策略
4.1 logrotate方案
标准的/etc/logrotate.d/nginx配置:
bash复制/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
}
关键参数解析:
rotate 30:保留30天的日志备份delaycompress:延迟一天压缩前一天的日志create 0640 www-data adm:新建日志文件的权限和属主kill -USR1:向Nginx主进程发送重新打开日志文件的信号
4.2 时间切片方案
对于超高流量场景,可以使用时间戳命名日志文件:
nginx复制http {
access_log /var/log/nginx/access-${year}${month}${day}-${hour}.log main;
}
配合crontab每小时执行:
bash复制0 * * * * /usr/sbin/nginx -s reopen
这种方案的优点:
- 天然避免单个文件过大
- 方便按时间范围检索日志
- 与Hadoop等大数据系统兼容性更好
5. 日志分析实战
5.1 常用分析命令
bash复制# 统计HTTP状态码分布
awk '{print $9}' access.log | sort | uniq -c | sort -rn
# 找出请求时间最长的URL
awk '{print $7,$10}' access.log | sort -k2 -rn | head -20
# 实时监控500错误
tail -f access.log | awk '$9 == 500 {print $0}'
# 统计爬虫流量
grep -E 'Googlebot|Baiduspider' access.log | awk '{sum+=$10} END {print sum/1024/1024 "MB"}'
5.2 ELK集成方案
典型的日志收集架构:
- Filebeat监听Nginx日志文件
- 发送到Logstash进行解析和过滤
- 存储到Elasticsearch
- 通过Kibana可视化分析
Logstash配置示例:
ruby复制filter {
grok {
match => { "message" => "%{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] \"%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}\" %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{QS:referrer} %{QS:agent}" }
}
date {
match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
}
}
6. 性能优化建议
- 内存缓冲区:对于每秒1000+请求的场景,建议设置access_log buffer至少64k
- 日志格式简化:移除不必要的字段(如$http_user_agent)可降低30%IO负载
- 异步写入:使用syslog协议将日志发送到远程服务器时,务必使用异步模式
- 临时关闭:在压力测试期间可以暂时关闭access_log提升性能
实测数据对比:
| 配置方案 | QPS上限 | CPU负载 | 磁盘IO |
|---|---|---|---|
| 无日志 | 35000 | 75% | 0% |
| 默认日志 | 28000 | 85% | 40% |
| 缓冲日志 | 32000 | 80% | 15% |
7. 安全注意事项
- 敏感信息过滤:
nginx复制map $request_uri $filtered_uri {
~^(.*)password=[^&]*(.*)$ "$1password=REDACTED$2";
default $request_uri;
}
将日志中的密码参数自动替换为REDACTED
- 日志文件权限:
bash复制chmod 640 /var/log/nginx/*.log
chown www-data:adm /var/log/nginx/*.log
- 定期审计:检查日志中是否包含:
- 异常的User-Agent
- 大量404请求
- 敏感路径访问尝试
- SQL注入特征字符
8. 疑难问题排查
问题1:日志文件不更新
- 检查nginx进程是否有写权限
- 确认磁盘空间充足
- 执行
nginx -s reopen强制重新打开日志
问题2:日志格式错乱
- 检查变量拼写是否正确
- 确保log_format定义在使用之前
- 转义字符需要使用反斜杠
问题3:日志轮转失败
- 确认logrotate配置语法正确
- 检查postrotate脚本是否执行
- 查看/var/mail/root获取cron错误信息
经过多年实践,我发现最稳定的日志方案是:JSON格式日志 + 按小时切片 + ELK集中分析。这种组合既能满足实时监控需求,又方便进行历史数据分析,特别是在分布式系统中表现尤为出色。