做运维这些年,最怕半夜被磁盘告警的短信吵醒。爬起来一看,不是数据库膨胀,也不是代码死循环,往往是某个服务的日志文件把磁盘啃干净了。有个客户的生产环境就出过这事,Nginx的access.log涨到20多个G,直接把根分区撑爆,前端页面全部502。当时我远程上去,df -h一敲,/ 那一行红得刺眼,再用 du -sh /var/log/nginx 一看,好家伙,全是日志。从那以后,我把自己负责的所有服务器都过了一遍日志轮转策略,该上logrotate的上logrotate,该写脚本的写脚本,再没让日志把磁盘搞崩过。
日志文件这东西,平时没人注意,出事就是大事。它不像代码bug,报错了立刻能看见;日志是慢性子,一天涨几百MB不觉得,攒一个月就是几十个G。而且很多应用进程会一直持有日志文件的句柄,你以为删了就完事,实际上磁盘空间压根没释放,必须重启进程或者用清空文件的方式处理。这篇文章我就把自己在Linux下自动管理日志文件的完整思路和实操记录下来,从logrotate配置到自写轮转脚本,从systemd journal限制到日常排查技巧,给需要的人一个能直接抄的作业。
1. 日志管理的核心痛点与方案选型
1.1 日志文件为什么会变成定时炸弹
先想明白一个问题:日志管理到底在防什么?我总结下来就三件事:磁盘空间被占满、日志文件过大导致检索困难、旧日志长期堆积泄露敏感信息。
磁盘被占满是最常见的。一台服务器上跑着Nginx、Tomcat、MySQL,每个应用都往自己的日志目录里写,系统自身的syslog、cron、secure也在写。这些文件通常只增不减,没人管的话,用不了几个月就能把磁盘写满。系统日志分区一旦满了,后果很直接:新日志写不进去、服务进程直接异常退出、甚至整个系统变得不稳定。我见过一台机器因为 /var/log 满了,sshd 都起不来,远程登录直接失败,只能去机房物理操作。
日志文件过大带来的检索问题同样让人头疼。一个20G的access.log,你想找某一天的某条请求,grep 一下要等好几分钟,甚至在机械硬盘上能把IO打满,拖垮整台服务器的其他服务。而且很多文本编辑器根本打不开这种超大文件,想手动分析都无从下手。
删日志也不是简单 rm 就完了。这里有个Linux文件系统的经典坑:如果一个进程还在往这个文件里写,你 rm 掉它,文件不会真正从磁盘上消失,因为文件句柄还开着,空间一直被占用,直到进程重启。我在排查一个磁盘明明满了但 du 却看不到大文件的问题时,才发现是一个Java进程的日志文件被误删,句柄没释放,空间全被吃住了。
1.2 主流方案怎么选:logrotate、手动脚本、journald控制
Linux下自动管理日志,成熟的路线有这么几条:系统自带的logrotate、自己写shell脚本配合crontab、针对systemd journal的限额清理。它们不是替代关系,而是各自适用的场景不同。
logrotate是Linux上最主流的日志轮转工具,几乎所有发行版都预装了。它的工作方式是定期(默认由cron驱动)检查日志文件,按你配置的规则把旧日志改名、压缩、删除。Nginx、Apache、syslog这些常见服务,装好后系统已经自带了对应的logrotate配置。它的优点是标准化程度高、配置简单、占用资源小,适合绝大多数普通日志文件。
自己写脚本的场景通常是logrotate覆盖不了的。比如某些应用日志带有特殊的时间戳后缀、需要按业务维度归档、或者需要在轮转的同时执行额外的清理操作。我之前接手过一套老系统,应用自己往固定的文件名里写日志,而且进程会持续持有句柄,用logrotate虽然有copytruncate选项可以解决,但应用那边还要求保留最近180天的日志并按照指定格式命名归档。这种定制化需求logrotate做起来很别扭,我就直接写了个脚本丢到crontab里。
systemd journal是新时代发行版自带的新日志系统。用systemd跑的服务,stdout和stderr默认都会进journal,时间长了journal文件照样会膨胀。它的优点是自带结构化日志、查询方便,但缺点也很明显:如果不设置限额,它会占用大量磁盘空间。这块需要单独配置。
我的建议是:能用logrotate解决的优先用logrotate,遇到定制化再补脚本,journal也要顺手设置好。三者搭配好了,日志管理基本就稳了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. logrotate深入解析与配置实战
2.1 logrotate工作机制与核心配置项
logrotate本身只是个工具,真正驱动它干活的是系统定时任务。在CentOS/RHEL系里,/etc/cron.daily/logrotate 这个每日任务会在每天凌晨自动执行;在Debian/Ubuntu系则是通过 /etc/cron.daily 下的类似机制。它的配置文件分两层:主配置 /etc/logrotate.conf 定义全局默认规则,/etc/logrotate.d/ 目录下的每个文件定义具体应用的规则,后者会覆盖前者的默认值。
logrotate的配置语法不复杂,但有几个参数直接决定你的日志轮转策略是否合理:
daily/weekly/monthly:指定轮转频率。我之前默认用daily,因为生产环境日志量往往比你预期的大,按周轮转风险太高。rotate N:保留多少个轮转后的旧日志文件。比如rotate 30表示保留最近30份归档,更早的自动删除。配合daily就是保留30天。compress:轮转后使用gzip压缩旧日志。建议开启,压缩后能省大量空间,特别是文本类日志压缩比极高,通常能到10%以下。dateext:给轮转后的文件加上日期后缀。比如access.log-20250115。这个强烈建议开,不然旧日志文件名都是access.log.1、access.log.2,过一个月你根本分不清哪份是哪天的。copytruncate:先复制当前
