Java 服务报了 No space left on device。你清掉一个大日志,目录里已经找不到它,df 的可用空间却几乎没动。先查写日志的进程。Linux 删除的是文件名,如果还有进程开着这个文件,最后一个引用关闭前,它仍会占着磁盘。 Linux unlink(2) 手册
先看满的是哪个文件系统
下面以 Linux、Bash、GNU coreutils 和 lsof 为例。把路径换成日志实际所在的目录。日志写在容器里时,先确认路径落在容器可写层、宿主机挂载目录还是独立卷。后面取样要对应同一处存储。
log_dir=/srv/orders/logs
df -hT -- "$log_dir"
df -i -- "$log_dir"
du -xhd1 -- "$log_dir"
第一条告诉你这个路径所在文件系统的容量,第二条看 inode 余量。字节还有剩、inode 却用完时,应该先找大量小文件。第三条只统计日志目录下能遍历到的文件,遇到权限不足,读不到的部分要另算。
df 算的是整个文件系统,du 算的是你给定的目录。两者有差额很常见。看到“刚删了一个很大的文件,文件系统可用空间没回升”这个组合,再查删除后仍打开的文件。 GNU df 手册 · GNU du 手册
先找持有日志的 PID,再看 FD
下面的 12345 换成写日志的实际 Java PID。用能读取该进程详情的账号执行。容器内的 PID 和宿主机看到的可能不同,选好观察位置再跑命令。
pid=12345
ps -p "$pid" -o pid,user,comm
lsof -nP -a -p "$pid" +L1
+L1 选链接数小于 1 的打开文件,-a 把这个条件和指定 PID 合在一起。先找类型为 REG、链接数为 0 的大文件,看它在哪个设备上、原来大致是哪个路径。临时文件也可以在打开后删掉名字,小条目很常见。注意权限报错,空输出时先确认进程和权限。如果写日志的实际是另一个进程,就换成它的 PID。 lsof 手册
比如 FD 列是 57w,下一步用数字 57。读链接和文件属性这两条命令不会写入日志。取样时进程也可能刚好关掉或复用了这个 FD,所以要对照路径和设备一起看。
fd=57
readlink -- "/proc/$pid/fd/$fd"
stat -Lc 'links=%h logical_bytes=%s blocks=%b block_bytes=%B' -- "/proc/$pid/fd/$fd"
如果链接指向原日志并带 (deleted),同时 links=0,就找到一个仍被持有的文件。logical_bytes 是逻辑大小。要估算占用空间,用 blocks × block_bytes,稀疏文件这两种口径可能差很多。 Linux /proc/PID/fd 手册 · GNU stat 手册
在临时目录里试一次
有一台能跑 Linux 和 Bash 的练习机,临时目录有几十 MiB 余量时,可以自己观察。下面只操作 mktemp 创建的目录。让 Bash 持有日志的读描述符,再把刚创建的文件名删掉。
(
set -e
work=$(mktemp -d)
dd if=/dev/zero of="$work/demo.log" bs=1M count=16 status=none
exec 3<"$work/demo.log"
rm -- "$work/demo.log"
ls -la -- "$work"
readlink -- "/proc/$BASHPID/fd/3"
stat -Lc 'links=%h logical_bytes=%s' -- "/proc/$BASHPID/fd/3"
exec 3<&-
rmdir -- "$work"
)
看两处输出就够了。目录里没有 demo.log,但 FD 3 还能找到原文件,属性里链接数是 0。关掉 FD 3,最后一个引用就释放了。练习文件很小,df -h 的四舍五入不一定能显示出前后差值。
处理后,把磁盘和日志一起看
确定哪个进程持有大文件后,优先用应用或日志组件支持的轮转、重开方式让它关闭旧文件。应用没有这类入口时,按服务发布流程安排重启,多实例先确认流量能接走。重启进程要重新找 PID,再检查旧文件的引用是否消失。
回到同一路径再看一遍 df,也用一个正常请求确认新日志能写、采集端还能收到。空间一直没回升时,继续找同一文件的其他持有者,或检查同一文件系统里还有哪些大文件。用 Logback 的项目,可以顺手确认当前写文件的 appender 和轮转策略,再定归档保留量。 Logback RollingFileAppender 手册
如果同时出现的是 Too many open files,再对照进程 FD 数和软上限定位。 Java 报 Too many open files,先看谁占满了 FD
Java 日志删了,磁盘空间怎么没回来
https://java.li/archives/java-deleted-log-disk-space
评论