一、引言:为什么需要日志轮转
在Linux服务器运维中,日志文件是排查问题、审计安全、分析性能的核心依据。然而,日志文件具有无限增长的特性——如果不加管理,单个日志文件可能在数月内膨胀至数十GB,最终导致:
- 磁盘空间耗尽:服务器因磁盘满而拒绝服务(No space left on device)
- 日志分析困难:超大文件导致文本编辑器崩溃,检索效率极低
- 性能下降:持续写入单个大文件增加I/O压力
- 合规风险:未定期归档的日志可能违反数据留存政策
logrotate 是Linux系统自带的日志管理工具,通过cron定时任务执行,支持日志的定期切割、压缩、删除与归档后动作。本文将从原理、配置、实战到最佳实践,全面解析logrotate的运作机制。
二、logrotate 核心架构与工作原理
2.1 Linux日志管理双层架构
在现代Linux系统中(尤其是使用Systemd的发行版),日志管理呈现双层架构:
graph LR
subgraph 应用层
A1["Nginx/Apache"]
A2["MySQL/PostgreSQL"]
A3["自定义应用"]
A4["Systemd服务"]
end
subgraph 日志收集层
B1["直接写入<br>/var/log/xxx.log"]
B2["rsyslog/syslog-ng"]
B3["systemd-journald"]
end
subgraph 日志管理层
C1["logrotate<br>文本日志轮转"]
C2["journald自管理<br>二进制日志清理"]
end
subgraph 存储层
D1["/var/log/*.log<br>文本文件"]
D2["/var/log/journal/<br>二进制文件"]
D3["归档/压缩文件<br>.gz/.bz2"]
end
A1 --> B1
A2 --> B1
A3 --> B1
A4 --> B3
B1 --> C1
B2 --> C1
B3 --> C2
C1 --> D1
C1 --> D3
C2 --> D2
style C1 fill:#e8f5e9
style C2 fill:#e1f5fe
关键认知:logrotate 管理的是文本日志文件(如Nginx的access.log、MySQL的error.log),而 systemd-journald 管理的是二进制结构化日志(位于 /var/log/journal/)。两者职责分离,不可互相替代。
2.2 logrotate 工作流程详解
logrotate通过定时任务(cron)每天自动执行,完整流程如下:
graph TD
A[定时触发<br>/etc/cron.daily/logrotate] --> B[加载配置<br>/etc/logrotate.conf<br>/etc/logrotate.d/*]
B --> C{检查轮转条件}
C -->|满足条件| D[执行轮转操作]
C -->|不满足| Z[跳过本次执行]
D --> E[重命名旧日志<br>access.log → access.log.1]
E --> F[压缩归档<br>access.log.1 → access.log.1.gz]
F --> G[创建新日志文件<br>create 0640 user group]
G --> H[执行postrotate脚本<br>kill -HUP/kill -USR1]
H --> I[清理超期日志<br>按rotate/maxage删除]
I --> J[记录状态<br>/var/lib/logrotate/status]
style A fill:#e1f5fe
style D fill:#fff3e0
style H fill:#e8f5e9
style J fill:#fce4ec
详细步骤解析:
- 定时触发:由
/etc/cron.daily/logrotate脚本调度,通常每日凌晨执行 - 加载配置:读取
/etc/logrotate.conf主配置和/etc/logrotate.d/*子配置 - 检查条件:判断日志是否满足轮转条件(时间周期、文件大小、文件年龄)
- 执行轮转:
- 重命名旧日志(如
access.log→access.log.1) - 若启用
dateext,则附加日期后缀(如access.log-20250609) - 压缩归档(如
access.log.1.gz) - 创建新的空日志文件(
create选项指定权限和属主)
- 重命名旧日志(如
- 执行钩子脚本:
postrotate块中发送信号通知应用重新打开日志文件 - 清理超期日志:按
rotate保留数量或maxage天数删除旧文件 - 记录状态:更新
/var/lib/logrotate/status状态文件
2.3 两种轮转机制对比
logrotate提供两种根本不同的日志轮转方案:
graph TB
subgraph "方案一: create (重命名+创建新文件)"
A1[原日志文件<br>access.log<br>inode: 1001] --> B1[重命名为<br>access.log.1<br>inode: 1001]
B1 --> C1[创建新文件<br>access.log<br>inode: 1002]
C1 --> D1[发送信号通知应用<br>重新打开日志文件]
D1 --> E1[应用写入新inode<br>无数据丢失]
end
subgraph "方案二: copytruncate (复制+截断)"
A2[原日志文件<br>access.log<br>inode: 1001] --> B2[复制内容到<br>access.log.1<br>inode: 1002]
B2 --> C2[截断原文件<br>access.log<br>inode: 1001 保留]
C2 --> D2[应用继续写入原inode<br>无需重启/信号]
D2 --> E2[可能丢失复制期间<br>的少量日志]
end
style E1 fill:#e8f5e9
style E2 fill:#ffebee
方案一:create(默认方案)
原理:基于Linux文件系统的inode机制。重命名文件只修改目录项,不改变inode编号,因此应用进程通过原inode继续写入;创建同名新文件后,通过信号通知应用重新打开日志文件,此时应用通过文件路径打开的是新inode。
优点:
- 无数据丢失,操作近乎原子性
- 支持压缩,节省磁盘空间
- 标准做法,社区支持完善
缺点:
- 需要应用支持信号重载(如Nginx的USR1、Apache的HUP)
- 若应用不支持,需重启服务,影响可用性
方案二:copytruncate
原理:先复制当前日志文件内容到归档文件,然后截断(清空)原文件。由于原文件的inode未改变,应用无需重新打开文件即可继续写入。
优点:
- 无需应用支持信号通知
- 无需重启服务,对高可用场景友好
缺点:
- 存在竞争条件:复制和截断之间的极短时间内,新写入的日志会丢失
- 大文件复制耗时较长,I/O开销大
- 不适用于金融、医疗等对数据完整性要求极高的场景
适用场景:应用不支持日志重开信号,且允许极少量日志丢失的场景(如内部调试日志)。
三、配置文件体系详解
3.1 配置文件结构
graph TD
A["/etc/logrotate.conf<br>主配置文件"] --> B["全局默认设置"]
A --> C["include /etc/logrotate.d"]
C --> D1["/etc/logrotate.d/nginx"]
C --> D2["/etc/logrotate.d/syslog"]
C --> D3["/etc/logrotate.d/mysql"]
C --> D4["/etc/logrotate.d/自定义应用"]
D1 --> E1["nginx专属规则<br>daily/rotate 14/compress"]
D2 --> E2["syslog专属规则<br>weekly/rotate 4/sharedscripts"]
D3 --> E3["mysql专属规则<br>size 100M/create 0640"]
D4 --> E4["应用专属规则<br>copytruncate/postrotate"]
style A fill:#e1f5fe
style C fill:#fff3e0
style D1 fill:#e8f5e9
style D2 fill:#e8f5e9
style D3 fill:#e8f5e9
style D4 fill:#e8f5e9
- 主配置文件
/etc/logrotate.conf:定义全局默认值 - 子配置目录
/etc/logrotate.d/:每个服务独立的配置文件,通过include指令加载 - 优先级:子配置中的参数会覆盖主配置的同名参数
3.2 主配置文件典型示例
# /etc/logrotate.conf
weekly # 默认每周轮转
rotate 4 # 默认保留4个旧日志
compress # 默认启用压缩
delaycompress # 延迟压缩(下次轮转时压缩上一次的)
missingok # 日志不存在时不报错
notifempty # 空日志不轮转
create 0640 root adm # 默认创建新文件的权限和属主
include /etc/logrotate.d # 加载子配置目录
# 针对特定文件的局部规则(覆盖全局设置)
/var/log/wtmp {
monthly
create 0664 root utmp
minsize 1M
rotate 1
}
3.3 核心配置参数速查表
| 参数 | 功能说明 | 示例 |
|---|---|---|
daily/weekly/monthly/yearly |
轮转周期 | daily |
rotate N |
保留N个旧日志文件 | rotate 7 |
size 100M |
超过指定大小时轮转 | size 500M |
minsize 50M |
最小达到此大小才轮转 | minsize 1M |
maxage 30 |
删除超过30天的旧日志 | maxage 365 |
compress |
启用gzip压缩旧日志 | compress |
delaycompress |
延迟一个周期压缩 | delaycompress |
missingok |
日志不存在时不报错 | missingok |
notifempty |
空文件不轮转 | notifempty |
create 0640 user group |
创建新文件并设置权限 | create 0640 www-data adm |
dateext |
使用日期作为后缀 | dateext |
dateformat -%Y%m%d |
自定义日期格式 | dateformat -%Y%m%d-%s |
copytruncate |
复制并截断原文件 | copytruncate |
olddir /backup/logs |
归档到指定目录 | olddir /var/log/archive |
sharedscripts |
多个日志共享一次脚本 | sharedscripts |
prerotate...endscript |
轮转前执行脚本 | 见下方示例 |
postrotate...endscript |
轮转后执行脚本 | 见下方示例 |
su user group |
以指定用户身份执行 | su root syslog |
四、生产环境配置实战
4.1 Nginx 日志轮转配置
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily # 每日轮转
missingok # 日志缺失不报错
rotate 14 # 保留14天
compress # 启用压缩
delaycompress # 延迟压缩(确保Nginx有时间切换)
notifempty # 空文件不轮转
create 0640 www-data adm # 创建新文件权限
sharedscripts # 所有日志轮转后只执行一次脚本
postrotate
# 向Nginx主进程发送USR1信号,使其重新打开日志文件
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
关键点:
delaycompress确保Nginx在收到USR1信号后,有时间将剩余内容写入旧日志文件,避免压缩不完整的日志sharedscripts避免对access.log和error.log分别执行reload,减少服务抖动
4.2 系统日志(rsyslog)轮转配置
# /etc/logrotate.d/syslog
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
{
missingok
sharedscripts
postrotate
# 重新加载rsyslog配置(HUP信号)
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}
4.3 高频日志(按大小触发)
# /etc/logrotate.d/high-frequency-app
/var/log/myapp/*.log {
size 100M # 超过100MB立即轮转(不等daily)
rotate 30 # 保留30个(约3GB总量控制)
compress
missingok
notifempty
create 0644 appuser appgroup
dateext
dateformat -%Y%m%d-%H%M%S # 带时间戳,精确到秒
sharedscripts
postrotate
# 可选:轮转后触发日志分析或上传
/usr/local/bin/process_rotated_logs.sh $1
endscript
}
4.4 Java应用(copytruncate方案)
# /etc/logrotate.d/java-app
/var/log/java-app/*.log {
daily
rotate 7
size 500M
compress
missingok
notifempty
copytruncate # 无需重启JVM
create 0644 appuser appgroup
}
注意:Java应用通常不支持信号重载日志文件,使用 copytruncate 是常见做法,但需接受极少量日志丢失的风险。
4.5 安全敏感日志配置
# /etc/logrotate.d/secure-logs
/var/log/audit/*.log {
daily
rotate 90 # 保留90天,满足合规要求
compress
delaycompress
missingok
notifempty
create 0600 root root # 严格权限,仅root可读写
shred # 使用shred安全删除(覆盖后删除)
shredcycles 3 # 覆盖3次
olddir /var/log/audit/archive # 归档到独立目录
prerotate
# 轮转前解除不可变属性(如有)
/usr/bin/chattr -a /var/log/audit/*.log 2>/dev/null || true
endscript
postrotate
# 轮转后恢复不可变属性
/usr/bin/chattr +a /var/log/audit/*.log 2>/dev/null || true
endscript
}
五、高级机制深度解析
5.1 状态文件(status)机制
graph LR
A[状态文件<br>/var/lib/logrotate/status] --> B[格式: 路径 日期]
B --> C1["/var/log/nginx/access.log" 2026-6-9]
B --> C2["/var/log/syslog" 2026-6-8]
B --> C3["/var/log/mysql/error.log" 2026-6-9]
D[作用] --> E1[记录上次轮转时间]
D --> E2[防止重复轮转]
D --> E3[支持force强制覆盖]
style A fill:#fce4ec
logrotate通过 /var/lib/logrotate/status 记录每个日志文件的上次轮转日期,确保:
- 防重复:同一天不会重复轮转同一日志
- 状态持久:即使系统重启,也能正确判断是否需要轮转
- 手动干预:可通过
-s指定自定义状态文件,或删除状态文件强制重新评估
5.2 prerotate 与 postrotate 脚本机制
这两个钩子脚本是logrotate最强大的扩展能力:
-
prerotate:在轮转之前执行。常用于:
- 解除文件特殊属性(如
chattr -a) - 备份当前日志到远程服务器
- 停止相关服务(极端场景)
- 解除文件特殊属性(如
-
postrotate:在轮转之后执行。常用于:
- 发送信号通知应用重新打开日志(
kill -HUP/kill -USR1) - 恢复文件特殊属性(如
chattr +a) - 触发日志分析、上传、告警
- 发送信号通知应用重新打开日志(
-
sharedscripts:当配置块匹配多个日志文件时,确保脚本只执行一次而非每个文件都执行。这对Nginx等多日志场景至关重要,避免多次reload服务。
5.3 与 systemd-journald 的协同与区别
| 对比维度 | logrotate | systemd-journald |
|---|---|---|
| 管理对象 | 文本日志文件(.log) | 二进制结构化日志(.journal) |
| 存储位置 | /var/log/*.log |
/var/log/journal/ |
| 日志格式 | 纯文本,人类可读 | 二进制,需journalctl查看 |
| 触发机制 | cron定时(通常每日) | 实时写入,自动按大小/时间清理 |
| 配置方式 | /etc/logrotate.conf |
/etc/systemd/journald.conf |
| 压缩能力 | 支持(gzip/bzip2) | 内置压缩 |
| 查询能力 | grep/awk等文本工具 | journalctl结构化查询 |
| 适用场景 | 应用自定义日志、传统syslog | systemd服务日志、系统启动日志 |
核心结论:两者是互补关系而非替代关系。生产环境中,journald管理systemd体系日志,logrotate管理独立文本日志,rsyslog在需要时做中转和持久化。
六、调试与故障排查
6.1 常用命令
# 调试模式:模拟执行,不真正轮转(强烈推荐配置后先测试)
logrotate -d /etc/logrotate.d/nginx
# 强制轮转:立即执行(谨慎使用)
logrotate -f /etc/logrotate.d/nginx
# 详细模式:显示执行过程
logrotate -vf /etc/logrotate.d/nginx
# 查看状态文件
cat /var/lib/logrotate/status
# 检查cron任务是否正常
ls -la /etc/cron.daily/logrotate
cat /etc/cron.daily/logrotate
6.2 常见问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 日志未轮转 | cron未执行/配置错误 | 检查cron服务;手动执行测试 |
| 轮转后服务不写入新日志 | postrotate信号未生效 | 验证PID文件路径;检查信号类型 |
| 权限拒绝 | 文件属主/权限不匹配 | 调整 create 参数或 su 参数 |
| 旧日志未删除 | rotate数量设置过大 | 检查 rotate 和 maxage 配置 |
| copytruncate后日志有乱码 | 应用未使用O_APPEND打开文件 | 改用create方案,或修改应用 |
| 状态文件损坏 | 异常断电/磁盘故障 | 删除 /var/lib/logrotate/status 后重建 |
七、生产环境最佳实践
7.1 权限与安全
- 日志文件权限:常规日志设为
640(属主可写,组可读,其他无权限);敏感日志(如认证、支付)设为600 - 防止误删:对关键日志使用
chattr +a(仅追加属性),在prerotate中临时解除,postrotate中恢复 - 敏感信息脱敏:严禁在日志中输出密码、Token、身份证号等,应用层应实现脱敏
- 安全删除:对审计日志启用
shred选项,防止恢复
7.2 性能优化
- 高频日志:使用
size触发而非纯时间触发,避免单文件过大 - I/O错峰:将logrotate执行时间调整到业务低峰期(如凌晨3:00)
- 独立分区:使用
olddir将归档日志存储到独立分区或挂载点,避免影响根分区 - 延迟压缩:对正在写入的日志使用
delaycompress,避免压缩不完整的文件
7.3 监控与告警
# 检查磁盘使用情况
df -h /var/log
du -sh /var/log/* | sort -hr
# 检查logrotate执行状态(查看系统日志)
grep logrotate /var/log/syslog
grep logrotate /var/log/messages
# 检查特定日志的轮转历史
ls -lt /var/log/nginx/access.log*
7.4 与集中式日志平台集成
# 示例:轮转后触发Logstash处理
/var/log/app/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 0644 appuser appgroup
postrotate
# 通知Logstash重新加载配置或处理新文件
curl -XPOST http://logstash:9600/_node/reload 2>/dev/null || true
endscript
}
八、总结
logrotate是Linux日志管理的基石工具,其设计哲学是**“配置即策略,自动化运维”**。掌握其核心要点:
- 理解双层架构:logrotate管文本,journald管二进制,各司其职
- 选对轮转方案:优先
create+ 信号通知,不得已再用copytruncate - 善用钩子脚本:
prerotate/postrotate是实现复杂日志管理逻辑的关键 - 重视安全与权限:最小权限原则,敏感日志严格管控
- 先调试再上线:
-d调试模式是避免生产事故的最佳保险
通过合理配置logrotate,可以确保日志既不会撑爆磁盘,又能在需要时快速定位问题,实现 “有日志可查,无冗余之患” 的运维理想状态。
原文 https://blog.csdn.net/2301_79518550/article/details/161859918