智用指南
第二套高阶模板 · 更大气的阅读体验

日志轮转中copytruncate到底是什么意思

发布时间:2025-12-15 22:00:21 阅读:254 次

在运维或开发过程中,服务运行久了ref="/tag/415/" style="color:#479099;font-weight:bold;">日志文件会越来越大。比如一个 Web 服务器连续跑几天,日志可能就膨胀到几个GB。这时候就需要做日志轮转(log rotation),把旧日志归档,腾出空间给新日志用。

常见的轮转方式是直接移动(rename)日志文件,然后通知进程重新打开日志。但问题来了:有些程序不会监听文件变化,你一改名,它还在往原来的文件描述符写,结果新日志就“消失”了——其实是写到了被移动的文件里。

copytruncate 的作用

为了解决这个问题,logrotate 提供了一个叫 copytruncate 的选项。它的意思是:不重命名原文件,而是先复制一份当前日志内容到归档文件,然后清空原日志文件。

这样做有个明显好处:原始日志文件的 inode 和名字都没变,程序继续往里面写完全不受影响,不需要发 HUP 信号重启进程,也不用担心日志丢失。

怎么用 copytruncate

在 logrotate 配置里加上这一行就行:

/var/log/myapp.log {
    daily
    rotate 7
    copytruncate
    compress
    missingok
}

上面这段配置的意思是:每天轮转一次 /var/log/myapp.log,保留7份,使用 copytruncate 方式处理,压缩归档,并且即使日志不存在也不报错。

潜在风险要注意

虽然方便,但 copytruncate 有坑。在“复制”和“清空”之间存在时间差,如果程序正在写日志,可能会丢掉这期间产生的几行。对日志完整性要求高的场景,比如审计、安全监控,就得慎用。

举个例子,你家楼下便利店用系统记流水,如果正好在清空日志那瞬间有一笔扫码支付进来,这条记录可能就没了。虽然概率小,但真出了问题不好查。

所以,能支持 postrotate 脚本通知进程重载的,优先用 rename + signal 的方式。实在没法发信号,再考虑 copytruncate。