1. 日志轮转的必要性与核心挑战
日志文件就像系统的"黑匣子",记录着每个关键操作和异常事件。但如果不加控制,单个日志文件可能膨胀到几十GB,不仅占用磁盘空间,还会拖慢日志查询速度。去年我们线上系统就遇到过因单个日志文件过大导致日志分析工具崩溃的情况,最终不得不手动分割处理。
日志轮转的核心要解决三个问题:
- 空间控制:防止单个日志文件无限增长
- 历史保留:保留有价值的旧日志供审计排查
- 访问连续:确保日志分析工具能无缝衔接新旧日志
2. 轮转方案选型:时间 vs 大小
2.1 按时间轮转的典型场景
bash复制# 每天轮转一次日志
mv app.log app.log.$(date +%Y%m%d)
touch app.log
适合场景:
- 日志量稳定可预测
- 需要按自然日/周/月归档
- 审计合规要求严格的时间分段
优势在于计划性强,但突发流量可能导致单日日志过大。某电商大促时就曾因按日轮转导致单个日志突破20GB。
2.2 按大小轮转的精准控制
bash复制# 当日志超过100MB时轮转
if [ $(stat -c%s app.log) -gt 100000000 ]; then
mv app.log app.log.$(date +%s)
touch app.log
fi
更适合:
- 日志量波动大
- 对单文件大小敏感的系统
- 容器等受限环境
实测在K8s环境中,将日志控制在50MB以内可使ELK采集效率提升40%。
3. 完整轮转脚本实现
3.1 基础轮转逻辑
bash复制#!/bin/bash
LOG_FILE="/var/log/myapp/app.log"
MAX_SIZE=100000000 # 100MB
TIMESTAMP=$(date +%Y%m%d%H%M%S)
# 检查日志大小
current_size=$(stat -c%s "$LOG_FILE")
if [ "$current_size" -ge "$MAX_SIZE" ]; then
# 压缩旧日志
gzip -c "${LOG_FILE}.1" > "${LOG_FILE}.${TIMESTAMP}.gz"
# 轮转日志
mv "$LOG_FILE" "${LOG_FILE}.1"
touch "$LOG_FILE"
# 保留最近7个压缩包
ls -t ${LOG_FILE}.*.gz | tail -n +8 | xargs rm -f
fi
3.2 增强功能实现
- 日志压缩:使用gzip压缩率可达70%以上
- 权限保持:通过
chmod --reference保持原权限 - 信号处理:添加
trap确保脚本中断时不损坏日志
4. 生产环境进阶方案
4.1 多条件复合轮转
bash复制# 满足任一条件即触发轮转
if [ $(stat -c%s "$LOG_FILE") -ge "$MAX_SIZE" ] ||
[ $(date +%H) -eq 0 -a $(date +%M) -lt 5 ]; then
# 轮转操作...
fi
4.2 日志切割的原子操作
- 使用
copytruncate模式避免日志丢失:bash复制cp app.log app.log.1 : > app.log - 通过
flock加锁防止并发写入冲突
4.3 与日志收集器集成
当使用Filebeat或Fluentd时,需要处理以下特殊场景:
- 轮转后需要通知采集器重新打开文件描述符
- 避免采集器重复发送已轮转的日志内容
- 保持inode变化后的追踪连续性
5. 性能优化实测数据
在AWS c5.large实例上测试不同方案的CPU消耗:
| 方案 | 日志量 | 轮转耗时 | CPU峰值 |
|---|---|---|---|
| 纯mv轮转 | 1GB | 0.8s | 15% |
| gzip压缩 | 1GB | 12s | 90% |
| parallel gzip | 1GB | 4s | 180% |
| zstd压缩 | 1GB | 3s | 110% |
关键发现:在非SSD存储上,压缩操作可能成为I/O瓶颈
6. 异常处理与监控
6.1 常见故障模式
- 磁盘空间不足:轮转前检查
df -h - 文件句柄泄漏:通过
lsof检查未关闭的FD - 权限问题:脚本用户需有日志目录写权限
6.2 监控指标建议
bash复制# 日志增长速率监控
echo "log_growth_rate $(du -b app.log | cut -f1)" >> /var/log/monitor.log
# 轮转次数统计
echo "log_rotation_count $(ls -1 app.log.* | wc -l)" >> /var/log/monitor.log
7. 与专业工具对比
相比logrotate的优势:
- 无需root权限
- 定制化程度高
- 可集成到应用内部
劣势:
- 缺少邮件通知等企业级功能
- 需要自行实现日志清理策略
- 错误处理机制不够完善
实际选择建议:简单场景用Shell脚本,复杂需求用logrotate+自定义钩子脚本