journalctl 磁盘占用 —— vacuum 只会舀水,SystemMaxUse 关阀断流
journalctl 磁盘占用实测附收据:--disk-usage 到底统计什么,--vacuum-size 为什么删完又自己涨回来,以及那个一劳永逸关上水龙头的 drop-in。
SystemMaxUse 就是管道上的那只阀。journalctl --disk-usage 到底统计的是什么?
结论先行:journalctl --disk-usage 报告磁盘上日志文件的大小——归档的和活动中的——在持久化安装里它们位于 /var/log/journal。它只是一次读取:不删任何东西,不重启任何东西。在测试 VM 上,还没加任何日志之前:
$ sudo journalctl --disk-usage
Archived and active journals take up 48.2M in the file system.
$ ls /var/log/journal/
fd766b9ea5a540e68e6c43ea74f98a15 ← one directory per machine-id
验证:Arch 出厂自带 /var/log/journal——Storage=auto(默认的注释态 #Storage=persistent)意味着从首次启动起就是持久化。用 sudo 运行:若不在 adm/systemd-journal/wheel 组里,普通用户的读取只覆盖自己的文件——测试机在同一秒里以用户身份量到 16M、以 root 量到 48.2M。
有两件事最容易绊倒人。第一,这个数字包含活动中的日志——journald 此刻正在写入的那个文件——所以哪怕刚开机也绝不是零。第二,如果 /var/log/journal 不存在,journald 就是易失的:一切都活在 /run/log/journal(tmpfs)里,读取接近零,重启即亡。那不是“日志很小”——那是根本没有日志历史。sudo mkdir -p /var/log/journal && sudo systemctl restart systemd-journald 把你切到持久化。
日志为什么一直在涨?
因为水龙头在设计上就开着。出厂的 /etc/systemd/journald.conf 把每个大小开关都注释着:
$ grep -E '^#(Storage|Compress|SystemMaxUse)' /etc/systemd/journald.conf
#Storage=persistent
#Compress=yes
#SystemMaxUse=
验证:逐字来自测试机——SystemMaxUse 在文件里只以注释存在;journald 视之为未设置,不执行任何上限。
没有上限,就什么都不淘汰、什么都不封顶:一个话痨服务或一个吵闹的 cron 每天添上几 MB,永无止境。测试机用最诚实的方式量出了这条斜率——灌满它,强制轮转,再读一次表:
$ for i in $(seq 1 400); do logger -t benchflood "entry $i: …~1KB line…"; done
$ sudo journalctl -t benchflood --no-pager | wc -l # all 400 landed
400
$ sudo journalctl --rotate # close the active file
$ sudo journalctl --disk-usage
Archived and active journals take up 56.2M in the file system.
验证:48.2M → 56.2M,只来自一小波灌入。里面藏着两张收据:增长只有在轮转时才可见——journald 把活动文件按 8M 的块预分配,所以文件中途的灌入在文件关闭前不会动表——而且 du -sh /var/log/journal(57M)在舍入范围内与 journald 自己的数字一致。
这波灌入是 400 行每行一千字节——对真实机器的日常噪音而言只是个舍入误差。大小不是重点;方向才是:不封顶意味着唯一的稳态就是“更多”,以你从未选定的 8M 步进。
journalctl --vacuum-size 能把它一劳永逸地删掉吗?
不能——而且招供就印在命令自己的输出里。vacuum 就是舀水的桶:舀一勺,立刻解气,结构上什么都没改变:
$ sudo journalctl --vacuum-size=1M
Deleted archived journal …/system@…-adf16c8ac48706f4.journal~ (8M).
Deleted archived journal …/system@d1d286….journal (8.2M).
Deleted archived journal …/user-1000@…journal~ (8M).
Deleted archived journal …/system@…c3f9281226bbfdc4.journal~ (8M).
Deleted archived journal …/system@…5244-….journal (4.4M).
Deleted archived journal …/user-1000@…57b6-….journal (3.4M).
Deleted archived journal …/system@…59c8-….journal (976K).
Deleted archived journal …/user-1000@…59cb-….journal (296K).
Vacuuming done, freed 41.4M of archived journals from /var/log/journal/fd766b9e….
$ sudo journalctl --disk-usage
Archived and active journals take up 16M in the file system.
验证:删除列表和“Vacuuming done, freed 41.4M”是 --vacuum-size 自己的 stdout,逐字粘贴——56.2M 跌到了 16M。
盯紧那个地板,因为它是 cron 任务从来注意不到的部分:16M 原地不动。那是两个活动中的日志文件——system.journal 和 user-1000.journal,各预分配 8M——而 --vacuum-size 只删归档文件。无论你传多小的数字,vacuum 都切不到 journald 正在写入的内容以下。
然后是回涨测试——没人去跑的那部分。同一波灌入再来一遍,轮转,读数:
$ sudo journalctl --disk-usage
Archived and active journals take up 20.3M in the file system.
$ sudo du -sh /var/log/journal
21M /var/log/journal
验证:16M → 20.3M,来自完全相同的 400 行灌入——vacuum 删掉的是历史;它对明天没有改变任何事。
这就是为什么 vacuum cron 是一个从未真正见效的民间偏方:它按时间表、用一只桶、永远地和水龙头搏斗。如果 cron 每周跑一次 --vacuum-size=100M,而日志在周中冲到 1G,读者整周都在为那 1G 买单。而且每一趟都是一次悄无声息的数据丢失——被释放的行是最旧的那些,恰恰是事故当天你要伸手去翻的历史。
怎样永久限制日志大小?
一个 drop-in,一次重启——然后 journald 自己在每一次轮转上执行上限,永远:
$ sudo mkdir -p /etc/systemd/journald.conf.d
$ sudo tee /etc/systemd/journald.conf.d/size.conf >/dev/null <<'EOF'
[Journal]
SystemMaxUse=5M
EOF
$ sudo systemctl restart systemd-journald
$ sudo systemd-analyze cat-config systemd/journald.conf | grep SystemMaxUse
SystemMaxUse=5M
验证:systemd-analyze cat-config 打印的是合并后的配置——drop-in 的 SystemMaxUse=5M 已生效,而不只是写进一个没人读的文件。
现在上同一波灌入——就是刚才把 vacuum 过的日志抬到 20.3M 的那一波:
$ for i in $(seq 1 400); do logger -t benchflood "entry $i: …"; done
$ sudo journalctl --rotate
$ sudo journalctl --disk-usage
Archived and active journals take up 1.2M in the file system.
$ sudo ls -lh /var/log/journal/*/ | awk '{print $5, $9}'
640K system.journal
640K user-1000.journal
$ sudo journalctl -t benchflood --no-pager | wc -l
0
验证:让未封顶日志涨到 20.3M 的同一波灌入,让封顶的那份停在 1.2M——journald 轮转、执行上限、直接删掉灌入:400 条进去,0 条留下,没有 cron,没人监督。
注意上限做到了 vacuum 做不到的事:它切到了 16M 地板的下方。vacuum 从不碰活动文件,但上限管的是轮转本身——上限生效后,journald 会重建更小的活动文件。这就是舀水与改管道的区别。
按余量选数字,不按口味:先用 journalctl --disk-usage 看今天的占用,再把 SystemMaxUse 设成你最多想保留的大致量——工作站 100M 或 200M 足矣;繁忙的服务器可能想要 1G。SystemKeepFree=1G 是双保险的兄弟:既给日志封顶,又向文件系统承诺一块地板。被删的内容永远是最旧的归档文件——journald 保留活动文件和你上限之内的部分。
解法,按顺序
舀水对关阀,一眼看清
| 工具 | 它做什么 | 何时有用 | 测试机实测 |
|---|---|---|---|
--vacuum-size=1M | 按大小删掉最旧的归档日志,一次性 | 应急:磁盘此刻已满 | 56.2M → 16M(释放 41.4M),被下一波同样的灌入回涨到 20.3M |
--vacuum-time=2weeks | 同上,按时间而非大小 | 一次性归档清理 | 同样的一锤子买卖——没有任何东西阻止再次生长 |
SystemMaxUse=5M drop-in | journald 在每次轮转时自我执行上限 | 永久:水龙头关上了 | 同样的灌入稳在 1.2M——灌入条目被直接删除(进 400 条,留 0 条) |
SystemKeepFree=1G | 无论上限多少,向文件系统承诺空闲空间 | 小磁盘,与上限并用 | 出厂默认的精神,如今写明 |
“vacuum 舀浴缸里的水;SystemMaxUse 关水龙头。人人都在舀水——而浴缸默认获胜。”
实测机没有覆盖的情况
实测范围:一台全新 Arch VM(systemd 262, 262.1-1-arch)——基线占用、一次 400 行灌入加强制轮转、--vacuum-size=1M 及其完整 stdout、一次相同的回涨灌入、SystemMaxUse=5M drop-in + 重启并读回合并配置、上限之下的同一波灌入,以及每一步的文件级 du/ls 见证。未实测:SystemMaxFileSize/文件数在上限下的相互作用、每单元的 LogNamespace= 日志、远程日志(systemd-journal-remote)、前向安全封印(Seal=)以及基于时间的保留(MaxRetentionSec)。灌入的行走的是 syslog 套接字,它会截断过长的行(落盘约 1 KB)——对照账无关紧要,因为上面的每个数字都是 journald 自己的 --disk-usage 并与 du 交叉核对过的。基线带着上一次启动的归档(一个住了人的 48.2M,跟任何真实机器一样)。一台机器,一次构建:水龙头对水桶的读法才是可移植的部分;你自己的 --disk-usage 才是裁决。
人工实测台架 · systemd 262 (262.1-1-arch) · 全新 Arch VM · 最后测试 2026-11-12
一个数字告诉你真相——journalctl --disk-usage。一行配置守住真相——SystemMaxUse。关上水龙头;让桶退役。■