数据库写入失败,磁盘却没有新增业务文件,常见原因是错误日志反复输出,把系统分区先写满。日志容量治理不是定时删除目录,而是分别控制写入、轮转与保留,并验证空间确实回收。本文以 Debian 12 为例,处理系统 journal 与短任务文件日志,不修改数据库文件或现有存储布局。
CloudSFP 的物理主机标配两块各自直连的 1TB NVMe,没有硬件 RAID。两块盘的容量不能直接当作日志所在文件系统的余量;日志预算必须以实际挂载点为准。以下容量都是操作示例,不是服务默认设置。
一、先定位占用,区分磁盘块与 inode
付款后在控制台查看凭据,通过 SSH 登录。机器有多个地址时使用第一个地址。先执行只读检查:
df -hT / /var/log
df -i / /var/log
findmnt -T /var/log
sudo du -xhd1 /var/log
sudo journalctl --disk-usage
df 显示文件系统占用,du 统计目录中可见文件,两者不必相等。-x 避免跨越其他文件系统,减少把独立挂载卷混入结果的风险。若 /var/log 不是独立分区,它会与系统文件共同消耗根分区空间。
空间充足但 inode 接近耗尽时,应查大量小文件,而不是只找最大日志。记录文件系统、可用空间、inode 使用量和增长最快的目录,再决定处理对象。诊断记录不要继续写入已经接近满载的分区。
不要直接删除整个
/var/log,也不要截断尚未保全的故障日志。清理前应保存相关时间范围的证据,并确认目标不是数据库数据、事务日志或备份文件。
二、给 journald 设置独立容量预算
持久化 journal 通常位于 /var/log/journal。通过 drop-in 配置管理限制,比直接覆盖主配置更容易审计和撤销。以下示例设置日志容量预算及文件系统保留空间:
sudo install -d -m 0755 /etc/systemd/journald.conf.d
sudo tee /etc/systemd/journald.conf.d/60-capacity.conf >/dev/null <<'EOF'
[Journal]
Storage=persistent
SystemMaxUse=1G
SystemKeepFree=4G
MaxFileSec=1day
EOF
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
sudo journalctl --flush
sudo journalctl --disk-usage
sudo systemctl status systemd-journald --no-pager
SystemMaxUse 控制 journal 使用预算,SystemKeepFree 要求为同一文件系统保留空间,实际行为还受当前剩余容量影响。它们不约束应用自行写出的文件。MaxFileSec 控制活动文件的最长时间跨度,不等于只保留一天日志。
若其他程序同时把相同消息写到文本日志,限制 journal 并不能消除那份副本。需要检查日志链路,分别治理,不要未经核对停用系统日志服务。
清理前先轮转,再核对结果
sudo journalctl --rotate
sudo journalctl --vacuum-size=1G
sudo journalctl --disk-usage
df -h /var/log
vacuum 只删除归档文件,不直接删除活动文件,所以最终占用不保证恰好等于指定值。重启 journald 属于配置变更,应先确认当前服务状态,并在执行后检查是否有新错误及业务日志是否继续进入 journal。
三、为文件日志建立明确的轮转责任
先确认程序由谁写日志、是否长期保持文件打开,以及已有规则是否覆盖该路径。同一个文件不能由应用内置轮转与 logrotate 同时管理,也不要给系统已有规则重复增加宽泛匹配。
安装检查工具:
sudo apt-get update
sudo apt-get install logrotate lsof
假设短任务每次启动都重新打开 /var/log/local-batch/run.log,结束后关闭文件,可在 /etc/logrotate.d/local-batch 写入:
/var/log/local-batch/run.log {
daily
maxsize 100M
rotate 7
compress
delaycompress
missingok
notifempty
create 0640
}
目录及原始日志应预先存在,所有权与任务账户匹配。create 0640 未指定属主时沿用原文件的属主和属组。目录若允许非特权账户写入,应另外评估 su 指令及目录权限,不能直接照搬规则。
sudo logrotate -d /etc/logrotate.conf
systemctl list-timers --all --no-pager
-d 只输出模拟结果,不执行轮转。检查定时器或 cron 的真实执行频率:maxsize 只在 logrotate 被调用时检查,不是实时硬上限;rotate 7 是保留七份归档,也不必然等于七天。
长驻进程需要应用支持的日志重新打开机制。文件被改名后,进程可能继续写入旧文件。不要猜测信号,也不要默认使用 copytruncate;后者在复制与截断之间存在丢失日志的窗口。
四、在隔离目录演练轮转与权限
不要对全局配置执行强制轮转来测试新规则。以下实验使用独立目录和状态文件,不接触生产日志:
umask 077
test_dir=$(mktemp -d)
printf '%0200d\n' $(seq 1 20) >"$test_dir/run.log"
cat >"$test_dir/rules" <<EOF
"$test_dir/run.log" {
size 1k
rotate 2
create 0640
}
EOF
logrotate -d -s "$test_dir/state" "$test_dir/rules"
logrotate -s "$test_dir/state" "$test_dir/rules"
ls -l "$test_dir"
printf 'after rotation\n' >>"$test_dir/run.log"
cat "$test_dir/run.log"
应看到归档文件、新建活动文件以及预期权限。最后一条写入只证明重新打开路径可以成功,不能证明长驻应用会自动切换文件。生产验收还必须让真实任务产生一条可识别记录,确认它出现在新活动文件中。
保留实验目录检查结果,确认后删除。生产规则仍由系统原有状态文件管理,不要让手工调用与定时任务同时执行,也不要以两个状态文件长期管理同一日志。
五、验收回收结果,并治理重复错误
删除文件后空间未增加,先检查仍被进程持有的文件:
sudo lsof +L1
df -h /var/log
df -i /var/log
sudo du -xhd1 /var/log
lsof +L1 会列出链接数小于一的打开文件。结合路径、大小和进程判断,不要把所有结果都当作日志。确认目标后,按应用文档重新打开日志,必要时重启对应服务,再复查 df。不要通过结束不明进程或写入其文件描述符来强行回收空间。
验收至少保留四项结果:新记录进入活动文件、归档数量符合规则、账户能够继续写入、文件系统空间没有持续异常下降。错误消息若仍成批重复,应修复失败重试、无效请求或调试输出源头,轮转不能代替故障处理。
容量预算也不能保证固定时间跨度的历史记录。高峰期日志增长更快,同样预算会更早淘汰旧记录。需要长期留存的证据,应另行设计传输、访问控制与备份,并实际验证读取;本机日志轮转只负责限制本机占用,不承担备份职责。
常见问题
journalctl 的 vacuum 能把全部日志立即压到指定大小吗?
不能。vacuum 只清理归档日志,不直接删除当前活动文件。可先执行 journalctl --rotate,再执行 journalctl --vacuum-size=1G,并用 journalctl --disk-usage 与 df 分别检查日志占用和文件系统空间。
删除日志后,df 为什么没有显示空间增加?
进程可能仍持有已删除文件的描述符。用 sudo lsof +L1 检查文件大小、进程和文件描述符,再按应用支持的方式重新打开日志或重启对应服务;不要直接结束不明进程。