一、 日志轮转:系统自带的“清洁工”

想象一下,你的服务器就像一台24小时运转的机器,每时每刻都在产生运行记录,这些记录就是日志。如果放任不管,日志文件会像滚雪球一样越滚越大,最终把硬盘空间全部占满,导致服务崩溃。

Linux系统很贴心,自带了一个叫 logrotate 的“清洁工”。它的工作很简单:定期检查日志文件的大小或存在时间,当满足条件时,就把当前的日志文件“打包”归档(比如重命名为 xxx.log.1),然后让服务重新创建一个新的空日志文件继续记录。这样,我们既保留了历史记录,又控制了单个文件的大小。

这个“清洁工”的排班表和操作手册,就写在 /etc/logrotate.conf/etc/logrotate.d/ 目录下的各个配置文件中。我们接下来要做的,就是学会如何修改这份“操作手册”,让清洁工更高效地工作。

二、 看懂并优化默认配置

我们先看看总配置文件,它定义了全局的“工作准则”。

技术栈:Linux logrotate

# 查看logrotate的主配置文件
cat /etc/logrotate.conf

# 示例输出及关键参数解释(注释部分为优化讲解)
# 每周执行一次轮转
weekly
# 保留过去4周的日志归档文件(默认值,通常建议增加)
rotate 4
# 即使日志文件是空的,也创建新的轮转文件
create
# 使用当前日期作为轮转文件的后缀名,而不是简单的递增数字(如.1, .2)
dateext
# 压缩除当前轮转周期外的所有旧日志文件(.gz格式),节省空间
compress
# 压缩延时:轮转后,下一次轮转时再压缩上一个文件(节省CPU,但会临时多占用空间)
delaycompress
# 如果日志文件丢失,不报错,继续处理下一个
missingok
# 即使日志文件为空,也进行轮转(与上面的`create`配合)
notifempty
# 包含 /etc/logrotate.d 目录下的所有子配置文件
include /etc/logrotate.d
# 某些日志文件,如wtmp和btmp,使用特定的轮转规则
/var/log/wtmp {
    monthly
    create 0664 root utmp
    minsize 1M
    rotate 1
}
/var/log/btmp {
    missingok
    monthly
    create 0600 root utmp
    rotate 1
}

优化点分析:

  1. rotate 4:对于生产环境的核心服务(如Nginx、应用日志),保留4份(比如4周)可能不够。排查问题时可能需要回溯更久。可以针对具体服务,在子配置中调大这个值,比如 rotate 12(保留一年)。
  2. weekly / monthly:这是时间周期触发。但对于高流量的服务,日志增长很快,可能等不到一周就几个G了。我们需要结合 size 参数来触发轮转。
  3. delaycompress:这是一个权衡。启用后,最新的一份归档日志(如 access.log.1)不会被立即压缩,方便你随时查看(比如用 grep)。下次轮转时它(变成了 access.log.2)才会被压缩。如果磁盘空间非常紧张,可以去掉这个参数,让压缩立即进行。

三、 为具体服务定制轮转规则(实战示例)

/etc/logrotate.d/ 目录下的文件,就是针对每个服务的“专属操作手册”。我们以最常见的 Nginx 和自定义应用日志为例。

技术栈:Linux logrotate

示例1:优化Nginx日志轮转 通常系统会自带一个 nginx 文件,如果没有,我们可以创建一个 /etc/logrotate.d/nginx

# 编辑或创建Nginx日志轮转配置
vim /etc/logrotate.d/nginx

# 文件内容如下(包含详细注释):
/var/log/nginx/*.log {
    # 按日轮转,而不是全局的每周。更频繁,管理更精细。
    daily
    # 或者按大小轮转:当日志文件超过100兆时立即轮转,不等待daily检查。
    size 100M
    # 保留30份归档日志(例如30天),这比全局的4份要多得多。
    rotate 30
    # 启用压缩以节省存储空间(继承全局配置,这里显式写出以示强调)。
    compress
    # 启用延迟压缩,方便快速查看前一天的日志。
    delaycompress
    # 如果日志文件不存在,不报错。
    missingok
    # 即使日志文件为空,也进行轮转。
    notifempty
    # 轮转后,创建新的空日志文件,并设置所有者、组和权限为nginx用户可写。
    create 0640 nginx adm
    # 在轮转动作结束后,发送信号给Nginx主进程,让其重新打开日志文件。
    # 这是关键一步!确保Nginx将新日志写入新创建的文件,而不是已轮转的旧文件。
    postrotate
        # 判断Nginx主进程文件是否存在
        if [ -f /var/run/nginx.pid ]; then
            # 向Nginx主进程发送USR1信号,使其重新打开日志文件
            kill -USR1 `cat /var/run/nginx.pid`
        fi
    endscript
    # 在轮转动作开始前,如果日志文件大于1G,即使没到daily或size条件也强制轮转(额外保险)。
    # 这是一个高级用法,确保单个文件不会失控。
    maxsize 1G
}

示例2:管理自定义Java应用日志 假设你的Spring Boot应用使用Logback,日志输出到 /opt/myapp/logs/application.log

# 创建自定义应用日志的轮转配置
vim /etc/logrotate.d/myapp

# 文件内容如下:
/opt/myapp/logs/*.log {
    # 按大小轮转,优先于时间。生产环境日志量不可控,按大小更安全。
    size 200M
    # 如果日志增长不快,也可以作为备用触发条件:至少每天检查一次。
    daily
    # 保留50个归档文件。结合size 200M,意味着最多保留约10G的日志。
    rotate 50
    # 立即压缩,因为应用日志通常不需要频繁查看前一天的原文件。
    compress
    nodelaycompress
    missingok
    notifempty
    # 创建新文件,用户和组根据你的应用运行用户来定,例如 appuser。
    create 0640 appuser appuser
    # 对于Java应用,通常需要重启或重载应用才能重新打开日志文件,这不一定可行。
    # 更佳实践是配置Logback使用 `TimeBasedRollingPolicy` 并设置 `cleanHistoryOnStart`,让日志框架自己管理。
    # 因此,这里可能不需要postrotate脚本。logrotate只负责归档“静止”的旧文件。
    # 重要:确保应用日志配置和logrotate配置不会冲突(例如都去轮转同一个正在写的文件)。
    # 推荐方案:应用日志框架按天或按大小生成带日期的文件(如 app.log.2023-10-27),
    # logrotate则用来压缩和删除更早的、应用已不再写入的文件。
    # 下面的配置是针对“应用只写一个固定文件名,依赖外部轮转”的场景:
    # postrotate
    #    # 发送信号或调用接口让应用重新加载日志配置(如果支持)
    #    # 例如:kill -HUP `cat /opt/myapp/run.pid`
    # endscript
    # 更推荐的做法是,注释掉上面的postrotate,采用下面的“复制截断”模式。
}

关联技术:copytruncate 模式 对于不支持接收信号重新打开日志文件的程序(很多老旧或自定义程序),可以使用 copytruncate 参数。它的工作方式是:先复制一份当前日志文件作为归档,然后清空(截断)原日志文件,而不是移动它。这样程序可以继续向原文件描述符写入。

/opt/oldapp/logs/output.log {
    daily
    rotate 7
    compress
    missingok
    # 使用复制截断模式,无需重启应用
    copytruncate
    # 注意:在复制和清空的极短间隙内,可能会丢失少量日志。
}

四、 高级策略与存储空间管理

仅仅配置轮转还不够,我们需要一个整体的存储管理策略。

1. 分层存储与归档

  • 近期日志:保留在高速本地磁盘(如SSD),方便快速查询。通过 logrotate 控制数量(如 rotate 30)。
  • 长期归档:使用 logrotatepostrotate 脚本,将压缩后的旧日志包(如 .tar.gz)自动传输到对象存储(如AWS S3、阿里云OSS)或专门的日志服务器/大容量硬盘。然后在本机删除它们。
# 在logrotate配置中可能的postrotate脚本片段示例
postrotate
    # ... 重新打开日志的命令 ...
    # 查找7天前的.gz压缩日志文件,移动到备份目录或直接上传
    find /var/log/nginx -name "*.gz" -mtime +7 -exec rsync -av {} backup-server:/log-archive/ \;
    # 本地删除已备份的、超过30天的.gz文件
    find /var/log/nginx -name "*.gz" -mtime +30 -delete
endscript

2. 使用 find 命令进行清理兜底 logrotate 通常是按计划任务(cron)每天运行一次。如果因为某些原因(如配置错误、磁盘写入暴增)它没有正常工作,日志文件可能会异常膨胀。一个安全的兜底做法是设置一个额外的定期清理任务。

# 编辑root用户的cron任务
crontab -e

# 添加一行,每天凌晨3点,清理超过指定大小或天数的“漏网之鱼”
# 例如:删除/var/log/下超过10G的.log文件(紧急情况)
# 0 3 * * * find /var/log -name "*.log" -type f -size +10G -exec truncate -s 0 {} \;
# 警告:直接truncate可能丢日志,优先应排查logrotate问题。

# 更安全的做法:删除修改时间超过60天的.tar.gz归档包
0 2 * * * find /opt/app/logs/ -name "*.tar.gz" -mtime +60 -delete

3. 监控与告警

  • 监控磁盘使用率:使用 df -h,或通过监控系统(如Prometheus)对 /var/log 所在分区设置告警(如 >85%)。
  • 监控日志增长速率:观察关键日志文件(如应用错误日志)的大小变化,异常增长可能意味着程序bug。

五、 应用场景、优缺点与注意事项

应用场景:

  • 任何Linux服务器:从个人VPS到企业级数据中心,只要产生日志,就需要管理。
  • 高流量Web服务:如Nginx/Apache访问日志,增长极快。
  • 数据库服务:如MySQL的慢查询日志、错误日志。
  • 容器化环境:虽然容器本身无状态,但宿主机的Docker引擎日志和通过卷挂载持久化的应用日志仍需轮转。
  • 安全审计:如 /var/log/secureaudit.log,需要长期保留但可以压缩归档。

技术优缺点:

  • 优点
    • 原生内置:无需安装额外软件。
    • 高度可配置:可以精细控制每个日志文件的轮转策略。
    • 稳定可靠:经过长期实践检验,是Linux生态的标准组件。
    • 与cron集成:通过系统的cron任务调度,简单有效。
  • 缺点
    • 最小粒度是“天”:虽然可以用size触发,但检查频率依赖cron(默认每天一次)。
    • 处理正在写入的日志文件需要协作:需要应用支持信号重载或使用有损的copytruncate
    • 分布式环境管理不便:每台服务器需单独配置,不如集中式日志方案(如ELK)统一。

重要注意事项:

  1. 测试配置:使用 logrotate -d /etc/logrotate.d/yourapp 进行调试,-f 参数强制立即运行一次测试。务必先在测试环境操作!
  2. 信号与进程:搞清楚你的服务如何重新打开日志文件(kill -USR1 还是 kill -HUP?或者根本不支持)。错误信号可能导致服务停止。
  3. 权限问题create 指令设置的新文件权限和属主,必须确保运行服务的进程有写入权限。
  4. 避免冲突:如果应用自己也有日志切割功能(如Java的Logback),务必只让一方负责,否则会导致日志损坏或丢失。通常建议让应用框架做切割,logrotate做压缩和清理。
  5. 保留期限合规:根据行业规定(如等保、GDPR)或公司内部审计要求,确定日志的最短保留时间,并相应设置 rotate 值或归档策略。

六、 总结

管理Linux日志,核心是理解并用好 logrotate 这个工具。它就像你系统的自动管家,但你需要给它一份清晰的“家务清单”(配置文件)。这份清单要因地制宜:对于重要的、增长快的日志,缩短轮转周期、增加保留份数、启用压缩;对于不支持信号的服务,谨慎使用 copytruncate

优化配置只是第一步,更重要的是形成管理习惯:定期检查轮转是否正常运行、设置磁盘空间告警、为历史日志规划归档和清理策略。在云原生时代,虽然越来越多的日志被收集到像ELK、Loki这样的中心化平台,但在日志产生的源头——服务器上,做好基础的轮转和空间管理,仍然是保证系统稳定性的第一道,也是必不可少的一道防线。记住,一个被日志撑爆的磁盘,足以让最华丽的微服务架构瞬间停摆。从今天起,给你的日志管家一份更优的“工作指南”吧。