亲眼看轮转到底丢了什么
目标
亲手构造日志轮转的两种方式,观察它们各自会丢失什么。 阅读说明与亲眼看到文件仍为 0 字节,效果完全不同。
为什么重要
错误配置日志轮转会导致以下两种情况之一。
- 使用
create却不发送 SIGHUP → 新日志文件永远是 0 字节, 实际日志继续写入.1文件。数据没有丢失,但没人找得到 - 使用
copytruncate→ 复制与截断之间产生的日志会消失
无论哪一种,如果在调查事故时才发现,都已经太晚。
步骤
- 持续写入的进程 →
/root/log/01-pid.txt - 删除后空间未释放 →
/root/log/02-deleted.txt - 通过重启清理 →
/root/log/03-restart.txt - 模拟 rename 方式 →
/root/log/04-rename.txt - 模拟 copytruncate 方式 →
/root/log/05-truncate.txt - 编写 logrotate 配置 →
/root/log/06-app.conf - 说明会丢失什么 →
/root/log/07-tradeoff.md - 清理 →
/root/log/08-clean.txt
参考
- 使用
echo $!获取后台进程的 PID。 : > 파일会把文件截断为 0 字节(truncate)。- 容器中通常不使用 logrotate。输出到 stdout 后,容器 runtime 会代为轮转; 这也是本实验需要确认的概念。
创建持续写入的进程
持续写入的进程 → /root/log/01-pid.txt
在后台启动一个持续写日志的进程。它必须始终保持文件打开并写入,因为本实验展示的现象全部由“打开的文件”引起。
mkdir -p /root/log
( i=0; while true; do i=$((i+1)); echo "line $i"; sleep 0.05; done ) >> /root/log/app.log &
echo $! > /root/log/01-pid.txt
关键在于将重定向放在循环外部。如果像 echo ... >> 파일 一样放在内部,每次都会打开再关闭;这样即使删除文件也不会留下 handle,rename 后也会写入新文件。真实 daemon 会打开文件一次后持续写入。
观察删除后空间仍未释放
删除后空间未释放 → /root/log/02-deleted.txt
执行 rm /root/log/app.log 后,查看 ls -l /proc/<PID>/fd | grep deleted。将结果保存到 /root/log/02-deleted.txt。文件虽然消失,进程却仍在写入,对应 block 也不会释放。
重新启动以完成清理
通过重启清理 → /root/log/03-restart.txt
终止该进程(kill <PID>)并重新启动。在 /root/log/03-restart.txt 中写两行:终止后 ls -l /proc/*/fd 2>/dev/null | grep -c deleted 的结果,以及说明重启为什么能解决问题的一行文字。
模拟 rename 方式
模拟 rename 方式 → /root/log/04-rename.txt
启动新的 writer 后,执行 mv /root/log/app.log /root/log/app.log.1,等待 5 秒,再用 wc -l 查看两个文件的行数。在 /root/log/04-rename.txt 中记录两者的行数。新的 app.log 可能根本没有创建,这正是需要 SIGHUP 的原因。
模拟 copytruncate 方式
模拟 copytruncate 方式 → /root/log/05-truncate.txt
使用 cp /root/log/app.log.1 /root/log/app.log.2 && : > /root/log/app.log.1 先复制后截断。5 秒后查看 wc -l /root/log/app.log.1。在 /root/log/05-truncate.txt 中记录刚截断后和 5 秒后的行数。目的是确认进程仍在继续写入。
编写 logrotate 配置
编写 logrotate 配置 → /root/log/06-app.conf
在 /root/log/06-app.conf 中编写 logrotate 配置。需要包含:path pattern、daily、rotate 14、compress、delaycompress、missingok、notifempty,以及 create 或 copytruncate 二选一。即使没有 logrotate 命令也没关系,目标是能够读写配置。
写明会丢失什么
说明会丢失什么 → /root/log/07-tradeoff.md
在 /root/log/07-tradeoff.md 中写四行:create 会丢失什么、copytruncate 会丢失什么、你选择的方式及其理由。本实验的结论是两者都并非没有代价。
清理
清理 → /root/log/08-clean.txt
使用记录的 PID 终止进程:kill $(cat /root/log/01-pid.txt)。然后使用 rm -f /root/log/app.log* 删除文件,并用 pgrep -f sleep | wc -l 之类的方法确认没有残留,将结果写入 /root/log/08-clean.txt。
⚠️ 不要使用 pkill -f 'while true'。pkill 的 -f 会把自身命令行也纳入检查对象,因此会杀死包含该字符串的 shell 自身。实际工作中,使用 pkill -f 断开自己 session 的事故也很常见。始终记录 PID 并据此终止,才更安全。