Linux日志轮替(日志转储):从原理到最佳实践
日志是Linux系统和应用的"黑匣子",记录了系统运行状态、错误信息和用户行为。但无限制增长的日志文件会带来三大问题:
- 磁盘空间耗尽:比如
/var/log/syslog可能几天内膨胀到几十GB,导致系统崩溃; - 查询效率低下:超大日志文件无法快速定位问题;
- 备份困难:单一日志文件难以按时间粒度备份和归档。
日志轮替(Log Rotation) 是解决这些问题的核心方案:它将日志文件按时间/大小分割为多个备份文件,压缩旧日志,并自动删除过期备份。本文将深入讲解Linux下日志轮替的核心工具(logrotate)、配置语法、常见场景示例和最佳实践,帮助你实现日志的自动化管理。
目录#
1. 日志轮替的基础概念#
日志轮替的目标是平衡日志的可读性、存储成本和可追溯性,关键术语如下:
| 术语 | 说明 |
|---|---|
| 轮替周期 | 按时间(daily/weekly/monthly)或大小(size 100M)触发轮替 |
| 保留份数(Rotate) | 保留多少份旧日志(如rotate 7保留7天的备份) |
| 压缩(Compress) | 对旧日志进行gzip/bzip2压缩,减少存储空间 |
| 复制截断(Copytruncate) | 先复制旧日志到备份文件,再截断原日志(避免重启应用,但可能丢日志) |
| 日期后缀(Dateext) | 用日期(如syslog-20240520)代替数字后缀(如syslog.1),更直观 |
2. Linux主流日志轮替工具:logrotate#
Linux下最常用的日志轮替工具是logrotate(几乎所有发行版默认安装),其他工具如newsyslog(BSD系)、logadm(Solaris)使用场景有限。
2.1 logrotate的安装与运行机制#
- 安装:
apt install logrotate(Debian/Ubuntu)或yum install logrotate(CentOS/RHEL); - 运行机制:通过
cron定时任务触发(默认每天执行一次,路径/etc/cron.daily/logrotate); - 手动执行:
logrotate [选项] 配置文件(如logrotate -f /etc/logrotate.d/nginx强制轮替Nginx日志)。
2.2 logrotate的配置文件结构#
logrotate采用主配置+子配置的模式:
- 主配置文件:
/etc/logrotate.conf(定义全局默认规则,如weekly、rotate 4); - 子配置目录:
/etc/logrotate.d/(存放各服务的单独配置,如nginx、rsyslog,优先级高于主配置)。
主配置文件示例:
# /etc/logrotate.conf
weekly # 默认每周轮替
rotate 4 # 保留4份旧日志
create # 轮替后创建新日志文件
dateext # 使用日期后缀(如syslog-20240520)
compress # 压缩旧日志
include /etc/logrotate.d # 引入子配置目录3. logrotate核心配置指令详解#
logrotate的配置指令可分为触发条件、轮替操作、压缩设置、脚本执行四大类,以下是高频指令的说明:
3.1 轮替触发条件#
控制日志何时被轮替:
| 指令 | 说明 |
|---|---|
daily/weekly/monthly/yearly | 按时间周期轮替 |
size 100M | 日志文件达到100M时触发轮替 |
maxsize 50M | 即使未到周期,超过50M也轮替(如daily + maxsize 50M:每天或超50M轮替) |
minsize 10M | 日志至少10M才轮替(避免频繁轮替小文件) |
notifempty | 日志为空时不轮替 |
3.2 轮替操作指令#
定义轮替后的行为:
| 指令 | 说明 |
|---|---|
rotate 7 | 保留7份旧日志(超过则删除最旧的) |
olddir /var/log/old | 将旧日志移动到指定目录(需提前创建,权限要正确) |
create 0640 root adm | 轮替后创建新日志文件,权限0640,所有者root,组adm |
copytruncate | 先复制旧日志到备份,再截断原日志(适用于无法重启的应用,如某些Java服务) |
dateext | 使用日期后缀(如syslog-20240520)代替数字后缀(syslog.1) |
dateformat .%Y-%m-%d-%H%M%S | 自定义日期格式(如syslog-2024-05-20-143000,解决同一天多次轮替的冲突) |
3.3 压缩设置#
控制旧日志的压缩策略:
| 指令 | 说明 |
|---|---|
compress | 压缩旧日志(默认gzip,后缀.gz) |
nocompress | 不压缩 |
delaycompress | 延迟压缩(第一次轮替生成syslog.1(未压缩),第二次轮替时压缩为syslog.2.gz,方便查看最近日志) |
compressext .bz2 | 指定压缩文件扩展名(如用bzip2压缩,需配合compresscmd /usr/bin/bzip2) |
3.4 脚本执行(关键!避免丢日志)#
轮替前后执行自定义脚本,解决应用无法写入新日志的问题(如Nginx日志轮替后需重新打开文件描述符)。
常用脚本块:
prerotate/endscript:轮替前执行(如备份前检查日志完整性);postrotate/endscript:轮替后执行(如重启应用或发送日志重开信号);sharedscripts:多个日志文件共享同一个脚本(如Nginx的access.log和error.log只需执行一次reload)。
示例(Nginx日志轮替后重开日志):
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid) # 发送USR1信号,Nginx会重新打开日志文件
fi
endscript4. 常见场景的logrotate配置示例#
以下是企业中最常用的3类场景配置,直接复制即可使用。
4.1 系统日志(rsyslog)#
系统日志(如/var/log/syslog)是核心日志,需保留7天以便排查问题:
# /etc/logrotate.d/rsyslog
/var/log/syslog
/var/log/mail.log
{
daily # 每天轮替
rotate 7 # 保留7天
missingok # 日志不存在时不报错
notifempty # 空日志不轮替
compress # 压缩旧日志
delaycompress # 延迟压缩(.1未压缩,.2.gz及以后压缩)
dateext # 日期后缀
create 0640 root adm # 新日志权限:所有者root,组adm,权限0640
sharedscripts # 多个日志共享脚本
postrotate
/usr/lib/rsyslog/rsyslog-rotate # 重启rsyslog,避免丢日志
endscript
}4.2 Nginx日志#
Nginx日志(access.log/error.log)增长快,需结合时间+大小触发轮替:
# /etc/logrotate.d/nginx
/var/log/nginx/*.log
{
daily # 每天轮替
rotate 14 # 保留14天
size 50M # 超过50M强制轮替(避免单日志过大)
missingok
notifempty
compress
delaycompress
dateext
create 0640 www-data adm # 新日志所有者:www-data(Nginx运行用户)
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid) # Nginx日志重开信号
fi
endscript
}4.3 自定义应用日志(Java应用)#
Java应用日志(如/opt/app/logs/app.log)无法重启时,使用copytruncate(注意:可能丢少量日志):
# /etc/logrotate.d/myapp
/opt/app/logs/app.log
{
hourly # 每小时轮替(适用于高频率日志)
rotate 24 # 保留24小时(1天)
size 100M # 超过100M轮替
missingok
notifempty
compress
copytruncate # 复制旧日志后截断原日志(无需重启应用)
create 0644 appuser appgroup # 新日志权限:应用用户appuser
}4.4 无法重启的应用日志(Copytruncate的替代方案)#
如果应用支持日志重开API(如Java的Log4j2),优先使用postrotate而非copytruncate,避免丢日志:
# Log4j2日志轮替示例
/opt/app/logs/app.log
{
daily
rotate 7
postrotate
curl -X POST http://localhost:8080/log/reopen # 调用应用的日志重开API
endscript
}5. 日志轮替的最佳实践#
结合企业经验,以下7条实践能避免90%的日志轮替问题:
5.1 按服务分离配置#
将每个服务的日志配置放在/etc/logrotate.d/下(如nginx.conf、mysql.conf),避免主配置文件过于臃肿。
5.2 优先使用日期后缀(dateext)#
数字后缀(如syslog.1)无法直观判断日志时间,日期后缀(syslog-20240520)更友好,配合dateformat可解决同一天多次轮替的冲突。
5.3 结合时间与大小触发轮替#
仅按时间轮替可能导致日志过大(如某服务突然爆发请求,access.log一天内达到100G),需添加size或maxsize限制(如daily + maxsize 50M)。
5.4 避免使用copytruncate(除非万不得已)#
copytruncate的原理是先复制旧日志,再截断原日志,复制和截断之间的时间差会丢失少量日志(约几毫秒)。如果应用支持reload或日志重开信号(如Nginx的USR1、Apache的reload),优先使用postrotate。
5.5 测试配置(dry run)#
修改配置后,用logrotate -d 配置文件进行干跑测试,确保无语法错误:
logrotate -d /etc/logrotate.d/nginx # 模拟轮替Nginx日志,不实际执行5.6 监控日志轮替状态#
- 查看logrotate日志:
/var/log/logrotate.log(记录轮替结果,如rotating pattern: /var/log/nginx/*.log daily (14 rotations)); - 监控磁盘空间:用
df -h /var/log或Prometheus+Node Exporter监控/var/log目录大小; - 检查应用日志写入:轮替后查看新日志文件是否有内容(如
tail -f /var/log/nginx/access.log)。
5.7 合理设置保留份数#
保留份数需平衡磁盘空间和可追溯性:
- 系统日志:保留7天;
- 应用日志:保留14~30天;
- 审计日志:保留90天以上(需符合合规要求)。
6. 故障排查:常见问题与解决#
6.1 日志未被轮替#
- 检查
cron服务是否运行:systemctl status cron; - 检查配置文件语法:
logrotate -d 配置文件; - 检查触发条件:
du -sh /var/log/nginx/access.log确认大小是否达到size阈值。
6.2 轮替后应用无法写入新日志#
- 检查新日志文件的权限:
ls -l /var/log/nginx/access.log(Nginx日志需www-data所有); - 修复方法:修改
create指令(如create 0640 www-data adm)。
6.3 日志轮替后丢失数据#
- 原因1:
copytruncate导致的丢日志(复制和截断之间的时间差); - 解决:改用
postrotate发送日志重开信号(如Nginx的USR1); - 原因2:应用未重启,继续写旧日志(如
mv旧日志后,应用仍持有旧文件的文件描述符); - 解决:
postrotate中重启应用(如systemctl reload nginx)。
7. 总结#
日志轮替是Linux系统运维的基础技能,核心目标是控制日志大小、保留历史、避免丢日志。关键要点:
- 优先使用
logrotate,掌握其配置语法; - 结合时间+大小触发轮替,避免日志过大;
- 用
postrotate重启应用或发送日志重开信号,避免丢日志; - 测试配置并监控轮替状态,确保稳定运行。
8. 参考资料#
- logrotate官方文档:
man logrotate; - Nginx日志轮替:https://nginx.org/en/docs/control.html#log_rotation;
- Red Hat日志管理指南:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-logging;
- Ubuntu logrotate教程:https://help.ubuntu.com/community/Logrotate。