logrotate 日志轮转实战:别让日志把磁盘悄悄撑满

举报
yd_281047095 发表于 2026/11/04 15:18:47 2026/11/04
【摘要】 很多服务器出故障,原因并不复杂:某个服务日志一直往同一个文件里写,几个月后磁盘被占满,数据库写不进去、服务起不来,SSH 登录都变慢。Linux 自带的 logrotate 就是专门解决这个问题的工具。这篇文章从配置结构讲起,结合一个自定义应用的例子,把轮转、压缩、保留天数和排查方法整理成一份可以直接照着做的清单。 一、logrotate 是怎么被触发的logrotate 本身不是常驻进程,...

很多服务器出故障,原因并不复杂:某个服务日志一直往同一个文件里写,几个月后磁盘被占满,数据库写不进去、服务起不来,SSH 登录都变慢。Linux 自带的 logrotate 就是专门解决这个问题的工具。这篇文章从配置结构讲起,结合一个自定义应用的例子,把轮转、压缩、保留天数和排查方法整理成一份可以直接照着做的清单。

一、logrotate 是怎么被触发的

logrotate 本身不是常驻进程,而是由定时任务每天调用一次。在多数发行版上可以这样确认:

systemctl list-timers | grep logrotate   # systemd timer 方式
ls /etc/cron.daily/ | grep logrotate     # cron 方式

主配置文件是 /etc/logrotate.conf,里面通常有一行 include /etc/logrotate.d,各个软件包把自己的规则放进 /etc/logrotate.d/ 目录。我们给自己的应用加规则,也推荐放在这个目录里,而不是改主配置。

二、先看懂一条完整规则

假设应用日志写在 /var/log/myapp/ 下,新建 /etc/logrotate.d/myapp:

/var/log/myapp/*.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d
    create 0640 myapp myapp
    sharedscripts
    postrotate
        systemctl kill -s USR1 myapp.service >/dev/null 2>&1 || true
    endscript
}

逐项解释:

  • daily:每天轮转一次,也可以用 weekly、monthly,或者配合 size 100M 按大小轮转。
  • rotate 14:保留 14 份旧日志,超过的自动删除,这是控制磁盘占用的关键。
  • missingok / notifempty:文件不存在不报错,文件为空不轮转。
  • compress + delaycompress:旧日志用 gzip 压缩,但最近一份先不压,方便直接 tail 查看,也避免进程还在写时被压缩。
  • dateext:用日期做后缀,比 .1 .2 .3 更直观。
  • create 0640 myapp myapp:轮转后新建空文件,并指定权限和属主,防止服务因为没权限写日志而报错。
  • sharedscripts + postrotate:所有文件轮转完只执行一次脚本,通知应用重新打开日志文件。

三、copytruncate 和 postrotate 怎么选

轮转的本质是把旧文件改名。问题在于,进程持有的是文件描述符,改名后它会继续往旧文件里写。处理方式有两种:

  1. 通知进程重新打开日志:Nginx 发 USR1 信号,很多服务支持 reload。这是首选方式,不丢日志。
  2. copytruncate:先复制一份,再把原文件清空。适合不支持重新打开日志的程序,但复制和清空之间写入的内容可能丢失,大文件复制也比较耗 IO。

经验是:能用信号就用信号,实在不行才用 copytruncate。

四、上线前一定要先演练

规则写好后不要等到第二天才看结果,先用调试模式检查语法和执行计划:

logrotate -d /etc/logrotate.d/myapp

-d 只打印将要做的动作,不会真的改文件。确认无误后可以强制执行一次:

logrotate -vf /etc/logrotate.d/myapp
ls -lh /var/log/myapp/

如果看到带日期后缀的旧文件和新的空日志文件,并且应用还在正常写入,说明配置生效。

五、常见坑和排查思路

  • 规则没生效:查看状态文件 /var/lib/logrotate/status(部分系统在 /var/lib/logrotate.status),里面记录了每个文件上次轮转的时间。logrotate 依据它判断是否“到期”,手动改过时间可能导致当天不轮转。
  • 报 parent directory has insecure permissions:日志目录对组或其他用户可写时会出现,加上 su myapp myapp 指定以哪个用户身份轮转即可。
  • 磁盘还是满:用 lsof +L1 查看已删除但仍被进程占用的文件。日志删了空间没释放,通常就是进程没重新打开日志。
  • 容器里的日志:Docker 默认的 json-file 日志不归 logrotate 管,应在 /etc/docker/daemon.json 里配置 "log-opts": {"max-size": "50m", "max-file": "3"}。

六、小结

一套稳妥的日志策略可以概括为三点:按时间或大小定期轮转,压缩并限制保留份数,轮转后让进程重新打开日志。花十分钟写好一条 logrotate 规则,再用 -d 演练一遍,就能避免很多“半夜磁盘告警”的情况。建议给每台新服务器的自定义服务都顺手加上这样一条规则,并把 df -h 纳入日常巡检。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。