1. 为什么我们需要关心日志滚动?
第一次接触服务器运维时,我盯着监控面板上那个不断闪烁的"磁盘空间不足"警告手足无措。登录服务器用df -h一看,/var/log目录居然占用了90%的空间——原来Nginx的access.log已经膨胀到20GB。这个教训让我明白:日志管理不是可选项,而是服务器运维的生命线。
日志滚动(Log Rotation)本质上是个"空间换时间"的游戏。想象你的日志是个不断变长的卷轴,日志滚动就是定期把这个卷轴截断存档,同时启用新卷轴继续记录。这样做有三个核心价值:防止单个日志文件过大导致检索困难;避免日志占满磁盘引发系统故障;通过归档压缩节省存储空间。
在Linux生态中,90%的发行版默认使用logrotate工具管理日志。它就像个智能管家,能根据时间(daily/weekly/monthly)或大小(size 100M)自动触发滚动,还能自动压缩旧日志(gzip)、清理过期存档(rotate 4)。但现实往往比理想复杂——当你的应用是24/7运行的服务时,简单的默认配置可能会导致日志丢失或服务中断。
2. logrotate的核心工作机制剖析
2.1 配置文件的双层结构
logrotate采用"基础配置+应用配置"的双层结构。基础配置/etc/logrotate.conf定义全局默认值,比如:
weekly # 默认每周滚动 rotate 4 # 保留4个历史版本 create # 滚动后创建新文件 dateext # 使用日期作为后缀 compress # 压缩历史日志而/etc/logrotate.d/目录下的应用级配置(如nginx、mysql)则会覆盖这些默认值。这种设计既保证了统一性,又能满足个性化需求。我曾见过一个典型错误:有人在nginx配置里写了daily却忘了注释掉全局的weekly,结果滚动周期以谁为准?答案是就近原则——应用配置优先。
2.2 触发时机与执行流程
logrotate的定时执行依赖cron实现,默认通过/etc/cron.daily/logrotate每天触发。但这里有个隐藏知识点:各Linux发行版的cron.daily执行时间不同(CentOS是凌晨3点,Ubuntu是早上6点)。如果需要精确控制执行时间,应该直接在crontab中添加任务:
# 每天0点执行日志滚动 0 0 * * * /usr/sbin/logrotate /etc/logrotate.d/nginx当logrotate运行时,它会严格按照以下顺序处理每个日志文件:
- 检查触发条件(时间/大小)
- 执行prerotate脚本(如停止服务)
- 重命名或复制当前日志
- 创建新日志文件
- 执行postrotate脚本(如重启服务)
- 压缩/删除过期日志
3. 生产环境配置进阶技巧
3.1 关键参数选型指南
面对copytruncate和create这两个互斥参数,很多新手会陷入选择困难。我的经验法则是:
- 使用create模式(默认)当你的应用支持HUP信号重载日志时(如Nginx、Apache)
- 使用copytruncate当应用无法优雅重载日志(如某些Java应用)
实测对比两种模式性能:
| 参数 | 日志丢失风险 | 服务影响 | 适用场景 |
|---|---|---|---|
| create | 低 | 需要HUP | 主流Web服务 |
| copytruncate | 中(毫秒级) | 无 | 顽固的遗留系统 |
另一个常被忽视的参数是su,它解决权限问题的神器。比如当Nginx以www-data用户运行时,必须添加:
su www-data www-data # 以指定用户/组操作日志否则可能因权限问题导致日志创建失败。
3.2 多维度滚动策略设计
纯时间维度(daily/weekly)的滚动在流量波动大的场景下会翻车。我建议采用时间+大小双触发机制:
/var/log/tomcat/catalina.out { daily # 每日至少一次 size 1G # 超过1G立即滚动 rotate 30 # 保留30个版本 missingok # 文件不存在时不报错 compress # 启用压缩 delaycompress # 延迟压缩(节省CPU) dateformat -%Y%m%d # 自定义日期格式 }对于关键业务日志,还可以增加邮件报警功能:
mail alice@example.com # 当日志被删除时发送通知4. 疑难杂症排查手册
4.1 常见故障现象与修复
问题一:日志滚动后应用停止写入
- 检查点:文件描述符是否未释放
- 解决方案:在postrotate中添加
kill -USR1 <pid>
问题二:磁盘空间未释放
- 检查点:
lsof | grep deleted查找被删除但未关闭的文件 - 解决方案:重启持有文件描述符的进程
问题三:滚动时间不符合预期
- 检查点:
/var/lib/logrotate/status中的最后执行时间 - 解决方案:手动执行
logrotate -vf /path/to/config
4.2 调试技巧三板斧
模拟运行:加
-d参数空跑测试logrotate -d /etc/logrotate.d/nginx强制运行:忽略时间条件立即执行
logrotate -f /etc/logrotate.d/mysql状态检查:查看历史记录
cat /var/lib/logrotate/status
5. 高阶实战:自定义日志流水线
当默认功能无法满足需求时,可以构建更复杂的处理流水线。比如我们需要将滚动后的日志自动上传到S3:
postrotate # 压缩最新滚动文件 gzip /var/log/app/app.log.1 # 使用awscli上传 aws s3 cp /var/log/app/app.log.1.gz s3://my-bucket/$(date +%Y%m%d).gz # 清理本地副本 rm -f /var/log/app/app.log.1.gz endscript对于需要审计的场景,还可以增加日志指纹校验:
prerotate # 计算原始日志的SHA256 sha256sum /var/log/audit.log > /var/log/audit.log.sha256 endscript在Kubernetes环境中,日志滚动需要特别处理。由于容器文件系统特性,建议:
- 使用
copytruncate模式 - 设置
rotate 7和size 100M - 通过sidecar容器收集滚动后的日志