1. 为什么需要按天分割Nginx日志
Nginx作为一款高性能的Web服务器,默认会将所有访问日志记录在单个文件中(通常是access.log和error.log)。当网站流量较大时,这些日志文件会迅速膨胀到GB级别,带来三个明显问题:
- 文件管理困难:单日日志可能包含数十万条记录,在排查问题时需要处理超大文件
- 历史分析不便:所有日期数据混杂在一起,无法快速定位特定时间段的日志
- 磁盘空间压力:未经分割的日志可能占满磁盘空间,导致服务异常
我在管理日均PV百万级的电商站点时,就遇到过单月日志文件突破50GB的情况。通过实现按天自动分割,不仅将单个日志文件控制在合理大小(约200MB/天),还能配合日志分析工具实现按日期快速检索。
2. 日志分割方案选型对比
2.1 常见实现方式
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| logrotate(系统自带) | 配置简单,与系统集成度高 | 切割不及时,依赖cron精度 | 中小流量站点 |
| Nginx信号控制 | 实时性强,无日志丢失风险 | 需要自行处理文件移动和压缩 | 高并发关键业务 |
| 第三方工具(如cronolog) | 功能丰富,支持复杂分割规则 | 增加外部依赖,可能成为单点故障 | 特殊格式需求场景 |
2.2 推荐方案选择
对于大多数生产环境,我建议采用logrotate+USR1信号组合方案。这是经过多个千万级PV项目验证的稳定方案:
- 利用logrotate进行每日定时切割和压缩
- 通过USR1信号通知Nginx重新打开日志文件
- 添加异常处理机制防止信号丢失
重要提示:绝对不要使用kill -9强制重启Nginx,这会导致最后的日志记录丢失。USR1信号是Nginx官方推荐的日志滚动方式。
3. 详细配置实现步骤
3.1 基础环境准备
首先确认Nginx日志配置格式(通常在nginx.conf中):
nginx复制http {
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;
}
3.2 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
}
关键参数解析:
daily:按天切割rotate 30:保留30天日志compress:使用gzip压缩历史日志delaycompress:延迟压缩前一个日志文件create 0640 www-data adm:设置新日志文件权限和属主
3.3 手动测试配置
执行以下命令验证配置:
bash复制# 测试配置是否正确
logrotate -d /etc/logrotate.d/nginx
# 强制立即执行分割(测试用)
logrotate -vf /etc/logrotate.d/nginx
预期会看到类似输出:
code复制rotating pattern: /var/log/nginx/*.log after 1 days (30 rotations)
empty log files are not rotated, old logs are removed
considering log /var/log/nginx/access.log
log needs rotating
considering log /var/log/nginx/error.log
log needs rotating
4. 高级优化技巧
4.1 按小时分割(大流量场景)
对于超高频访问场景,可以修改logrotate配置:
bash复制/var/log/nginx/*.log {
hourly
rotate 168 # 保留7天(24*7)
...
}
同时需要调整cron任务频率:
bash复制# 编辑crontab
0 * * * * /usr/sbin/logrotate /etc/logrotate.d/nginx
4.2 日志文件命名优化
在nginx配置中使用变量实现动态命名:
nginx复制http {
set $logdate $year-$month-$day;
access_log /var/log/nginx/access-$logdate.log main;
}
4.3 日志自动分析集成
配合ELK栈实现自动化分析:
bash复制# Filebeat配置示例
filebeat.inputs:
- type: log
paths:
- /var/log/nginx/access-*.log
fields:
type: nginx-access
5. 常见问题排查
5.1 日志未按预期分割
检查步骤:
- 确认logrotate服务正常运行:
bash复制
systemctl status cron - 查看最后一次执行记录:
bash复制grep logrotate /var/log/syslog | tail -n 5 - 检查Nginx进程是否收到USR1信号:
bash复制strace -p `cat /var/run/nginx.pid` -e trace=signal
5.2 磁盘空间未释放
即使分割后,已删除的大日志文件可能仍被Nginx进程占用。解决方案:
bash复制# 方法1:优雅重启Nginx
nginx -s reload
# 方法2:手动释放空间
> /var/log/nginx/access.log
5.3 权限问题处理
遇到权限拒绝错误时:
bash复制# 查看当前权限
ls -l /var/log/nginx/
# 修正权限
chown -R www-data:adm /var/log/nginx
chmod -R 640 /var/log/nginx/*.log
6. 生产环境注意事项
- 监控日志增长:设置Zabbix或Prometheus监控日志目录大小
- 保留策略:根据磁盘容量合理设置rotate值(通常30-90天)
- 信号丢失防护:在postrotate脚本中添加重试机制
- 测试恢复流程:定期验证日志压缩文件的完整性
我在某次大促期间就遇到过logrotate执行失败的情况。后来增加了以下防护措施:
bash复制postrotate
for i in {1..3}; do
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` && break
sleep 5
done
endscript
对于特别关键的日志,可以考虑使用Nginx的open_log_file_cache指令提升性能,同时降低日志丢失风险:
nginx复制open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
