Fork me on GitHub

服务器磁盘爆满,但是面板看只有三十多G问题

宝塔面板磁盘爆满排查实录:du 只看到 35G,df 却显示 184G

一次典型的 Linux「幽灵空间」排查:磁盘显示 99% 占满,但所有文件加起来只有 35G,差距整整 150G。
结论:不是文件占了空间,是进程占着已删除的文件不放。


一、问题现象

宝塔面板显示 /www 挂载点使用率 99%(184.63G / 196.74G),但在文件管理器的根目录列表里,/www 文件夹只有 32.88 GB。
image

进一步执行目录统计:

du -sh /www/* | sort -rh

结果大致是:

目录 大小
/www/server 25G
/www/wwwroot 8.6G
其他若干目录 0.4G + 0.2G + …
合计 约 35G

image

核心矛盾:du 统计约 35G,df 与面板显示 184G,差了 150G。

补充:根目录列表里 /proc 显示 128.00TB 是正常的,它是虚拟文件系统,不代表真实磁盘占用。


二、为什么会不一致:两类统计口径

命令 统计对象 特点
du 目录树中存在的文件 文件被删除后就看不到了
df 文件系统已分配的磁盘块 只要还有进程持有句柄,块就不会释放

因此当出现「df 远大于 du」时,90% 以上是 僵尸文件(已删除但仍被进程占用的文件)。

僵尸文件的产生过程

  1. 进程(如 Nginx、MySQL、Java)打开日志文件并持续写入(1w 标准输出、2w 标准错误)。
  2. 你在面板里删除了该日志,或被移进 /www/.Recycle_bin 回收站后清空。
  3. Linux 中 rm 删除的只是目录里的「名字」,只要进程还持有该文件的文件描述符,内核就会一直保留它的 inode 和数据块。
  4. 结果:du 查不到这个文件,df 却仍然把它算作已占用空间。
  5. 只有当进程关闭(重启 / kill)时,句柄释放,空间才会真正回收。

其他次要可能原因:

  • 挂载点覆盖:数据盘挂载到 /www 之前,该目录已在系统盘写入大量数据,挂载后被隐藏但仍占用系统盘。
  • inode 耗尽:df -i 的 IUse% 到 100%,即使有剩余空间也写不进文件(常见于 PHP session、缓存小文件)。
  • ext4 保留空间:默认 5%,196G 盘约 10G,无法解释 150G 的差距。

三、排查步骤

1. 确认分区与统计差异

df -h /www      # 挂载点总体使用情况
df -i /www      # inode 使用情况
du -sh /www/* | sort -rh   # 各子目录大小(倒序)

2. 找出僵尸文件(关键一步)

lsof | grep deleted | sort -k7 -rn | head -n 20
# 或
lsof +L1

本次实际输出(节选):

java  10009  www  2w  REG  253,17  73447508052  787225  /www/.Recycle_bin/.../springboot/dillon-server.log (deleted)

关键字段解读:

  • 第 7 列 73447508052 为文件大小,约 73GB,后面还有 45GB、43GB 的条目;
  • 路径显示文件原本在 /www/wwwlogs/,后被移入 .Recycle_bin 再删除;
  • 状态为 (deleted),且被 java 进程以 1w / 2w 方式持续打开;
  • 合计轻松超过 150G,完美解释了 35G 与 184G 的差额。

image

3. 深挖 /www/server(25G 的重点对象)

du -sh /www/server/* | sort -rh

重点看 /www/server/data(MySQL 数据目录)里是否有异常巨大的 mysql-bin.0000xx,以及 /www/server/php/*/tmp 下的临时文件。


四、解决方案:重启占用进程即可

方法一:宝塔面板操作(推荐)

  1. 宝塔面板 → 【网站】 → 【Java 项目】
  2. 找到 dillon-server、wvp-pro、terminalTcpServer 等项目
  3. 点击【重启】(或先停止再启动)
  4. 回到终端执行 df -h 验证

方法二:SSH 终端操作

# 查看 java 进程
ps -ef | grep java

# 通过 systemd 管理的服务
systemctl restart 你的服务名

# 或直接结束占用已删除文件的进程(会造成业务闪断,谨慎)
kill -9 10009 1536 13109 8604 11489

kill -9 后若有守护进程(如宝塔守护),会自动拉起新的 Java 进程,空间同样会释放,但优先建议在面板点重启,更优雅。

效果验证

本次关闭两个 Java 项目后:

99%(184.63G) → 77%(143.18G),释放 41.45G

image

说明:lsof 中的数值可能包含稀疏文件(sparse file)或按偏移量计算,显示 73GB 的条目实际物理占用可能更小,因此释放 41G 与几个大日志文件完全匹配。


五、常见占满空间的目录清单

类别 检查目录
网站访问/错误日志 /www/wwwlogs
MySQL 二进制日志 /www/server/data(mysql-bin.*)
宝塔本地备份 /www/backup
回收站 /www/.Recycle_bin
Docker 镜像与日志 /var/lib/docker、/www/docker
站点上传附件、运行缓存 /www/wwwroot/项目/uploads、/runtime
PHP 会话/临时文件 /www/server/php/*/tmp
系统日志 /var/log(尤其 journal)

对应清理动作:

# 清空日志内容(保留文件句柄),不要直接 rm
> /www/wwwlogs/某个日志.log

# MySQL binlog 清理:面板 数据库 → 性能调整,或执行 SQL
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 3 DAY;

# 清理 Docker 无用镜像与缓存
docker system prune -a

# 只保留 3 天系统日志
journalctl --vacuum-time=3d

六、后续预防措施

  1. 不要在运行期直接删除日志
    用 > /www/wwwlogs/xxx.log 清空内容,或先停服务/重启后再删。直接 rm 或移入宝塔回收站,都不会释放空间。

  2. 配置日志轮转
    Spring Boot 项目在 logback-spring.xml 中配置 RollingFileAppender:

    <!-- 按天或按大小切割 -->
    <maxHistory>7</maxHistory>        <!-- 最多保留 7 天 -->
    <totalSizeCap>5GB</totalSizeCap>  <!-- 总大小上限 -->
    

    避免单个日志文件长到 73GB。也可使用系统 logrotate。

  3. 谨慎清空宝塔回收站
    回收站中仍被进程占用的文件,清空也不会释放空间。清理日志前先停服务或用清空法。

  4. 定期巡检
    检查 /www/backup(旧备份)、/www/server/data(binlog)、回收站,并设置 MySQL expire_logs_days = 7 自动清理。


七、避坑提醒

  • 千万不要执行 rm -rf /www/* 这类危险命令,必须定位到具体目录后再精准删除。
  • 磁盘 100% 满时可能导致 MySQL 无法启动、网站无法访问甚至 SSH 无法登录,可先清空几个明显的超大日志应急。
  • 不要在运行网站的机器上随意 umount /www,会导致站点立即宕机。
  • 重启 Java 服务会造成短暂中断,请在业务低峰期操作。

一句话总结

df 看的是磁盘块,du 看的是文件名。文件被删了但进程还开着,空间就不会回来——lsof | grep deleted 找到它,重启对应进程即可。

posted @ 2026-09-29 21:26  秋夜雨巷  阅读(6)  评论(0)    收藏  举报