用 logrotate copytruncate 解决日志轮转后磁盘不释放

举报
yd_250998817 发表于 2026/10/30 00:14:24 2026/10/30
【摘要】 应用持续写旧日志文件句柄时,logrotate 默认 rename 会导致旧 inode 仍被占用、磁盘空间不释放。本文用 copytruncate 配置 daily、rotate 7,配合 ls -i 与 lsof 验证 inode 变化与空间回收,并给出 logrotate -d 调试步骤。

问题场景

应用进程启动后一直持有日志文件描述符,并且没有提供重新打开日志的接口。默认的 logrotate 配置通常使用 rename 策略:把 app.log 改名为 app.log.1,再创建新的 app.log。此时进程仍向旧 inode 追加写入,磁盘空间不会因为改名而释放;新文件可能一直是空的,旧文件却持续增长。用 ls -i 可以看到当前 app.log 的 inode 已经变化,而 lsof 仍显示进程持有旧 inode。

解决思路是让 logrotate 不换文件,而是复制一份归档后把原文件截断。这样进程继续写同一个 inode,文件大小归零,空间被回收。

最小配置

假设应用日志为 /opt/demo/logs/app.log,运行用户为 demo。新建 /etc/logrotate.d/demo-app:

/opt/demo/logs/app.log {
    daily
    rotate 7
    copytruncate
    missingok
    notifempty
    compress
    delaycompress
    su demo demo
}

关键项:daily 每天轮转;rotate 7 保留 7 份;copytruncate 先复制再截断原文件;su 指定读写日志的用户和组(按实际用户替换)。create 在 copytruncate 下不起作用,原文件保持原 inode。

可运行的验证示例

在测试机用临时目录复现,不依赖应用改造。创建持续持有文件描述符的写入脚本:

mkdir -p /tmp/logrotate-demo
cat > /tmp/logrotate-demo/writer.sh <<'EOF'
#!/usr/bin/env bash
set -eu
log=/tmp/logrotate-demo/app.log
exec 3>>$log
while true; do
  echo "$(date -Is) hello copytruncate" >&3
  sleep 1
done
EOF
chmod +x /tmp/logrotate-demo/writer.sh
/tmp/logrotate-demo/writer.sh &
echo $! > /tmp/logrotate-demo/writer.pid
sleep 3

创建测试配置:

/tmp/logrotate-demo/app.log {
    daily
    rotate 7
    copytruncate
    missingok
    notifempty
}

先做 dry-run,确认 logrotate 能解析配置并显示 copy/truncate 动作:

logrotate -d -s /tmp/logrotate-demo/state /tmp/logrotate-demo/logrotate.conf

再用 -f 强制执行一次轮转,便于立即验证:

logrotate -f -s /tmp/logrotate-demo/state /tmp/logrotate-demo/logrotate.conf
ls -i /tmp/logrotate-demo/app.log /tmp/logrotate-demo/app.log.1
lsof -p $(cat /tmp/logrotate-demo/writer.pid) | grep app.log
du -h /tmp/logrotate-demo/app.log /tmp/logrotate-demo/app.log.1

预期现象:app.log 的 inode 在轮转前后保持不变;app.log.1 是复制出来的归档文件,inode 不同;lsof 中写入进程的 fd 仍指向 app.log 的同一个 inode;app.log 大小被截断,后续写入从零开始增长。若换成默认 rename 策略,lsof 会显示进程仍占用已改名的旧 inode,这正是空间不释放的原因。

边界与限制

copytruncate 不是原子操作。复制完成到截断之间有一个很短的时间窗口,期间写入的少量日志可能丢失;对审计日志或不能丢行的场景,应优先让应用支持 reopen 信号,再使用 postrotate 触发重开。大文件复制会带来额外 I/O 和短暂磁盘占用,轮转时间应避开业务高峰。若日志目录权限或 su 用户配置不正确,logrotate 可能跳过该文件,需结合 logrotate -d 输出排查。rotate 7 只控制保留份数,不会自动清理配置之外的旧文件;压缩归档还会增加 CPU 开销。生产环境建议先用 dry-run 验证配置,再观察 ls -i、lsof 和目录占用情况。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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