上一篇 下一篇 分享链接 返回 返回顶部

Linux磁盘明明满了,du却找不到大文件?真正吃空间的可能不是普通文件

发布人:Minchunlin 发布时间:2026-05-03 08:25 阅读量:610

一、df 显示 100%,du 却看不到“大文件”

Linux服务器运维里,有一种问题特别容易让人误判:

df -h

看到 / 根分区已经 100%:

Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme0n1p2 100G 100G 0 100% /

于是你马上执行:

du -sh /*

结果发现每个目录加起来好像也没多少,根本找不到那个“吃掉几十 GB 空间的大文件”。

这时候很多人第一反应是:是不是 du 不准?是不是磁盘坏了?是不是系统被入侵了?

其实大多数情况下,不是 du 不准,而是磁盘空间被一些“普通 du 看不到的东西”占用了

二、先说结论:du 查不到大文件,常见有 6 类原因

现象 常见原因 典型场景
df 满了,du 看不到 已删除文件仍被进程占用 Nginx / PHP / MySQL / Java 日志被删但进程未重启
du 目录大小正常,但 df 仍高 mount 挂载点覆盖了原目录 原目录下面有旧文件,被新磁盘挂载遮住
df 显示空间不足,但文件不多 inode 用完 小文件、缓存、Session、邮件队列过多
根分区增长很快 Docker overlay2、容器日志 Docker、宝塔、面板环境常见
du 查不到快照占用 LVM / Btrfs / ZFS 快照 自动快照、备份快照没清理
普通用户写不进,root 还能写 ext4 保留空间 ext4 默认给 root 预留一部分空间

这篇文章不讲太多概念,我直接按真实运维现场的排查顺序来写。


三、适用服务器场景与配置参考

这类问题在香港服务器、美国服务器、跨境电商独立站、WordPress 网站、接口服务器、日志型业务上都很常见。尤其是业务访问量上来以后,日志、缓存、数据库 binlog、备份文件都会快速膨胀。

以一台常见香港物理服务器为例:

项目 配置
CPU AMD EPYC 4585PX,16核32线程
内存 64GB DDR5
系统盘 960GB NVMe SSD
带宽 100M BGP,含 25M CN2 直连
系统 Ubuntu 22.04 LTS / CentOS 7.x
适用业务 WordPress、外贸独立站、API接口、图片站、企业官网、轻量电商

如果是日志量比较大的业务,比如高并发接口、下载站、短视频站、游戏后端,我更建议:

项目 推荐配置
CPU AMD EPYC 7402P,24核48线程
内存 128GB DDR4
系统盘 960GB NVMe SSD
数据盘 2 × 1.92TB NVMe 或 4TB SSD
带宽 100M / 1G BGP,按业务流量选择
建议分区 //data/var/log 尽量拆分

很多磁盘满的问题,不是服务器性能不够,而是系统盘、日志盘、数据盘没有规划清楚


四、第一步:先确认到底是哪个分区满了

不要一上来就 du -sh /*,先看分区。

df -hT

重点看这几列:

Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme0n1p2 ext4 100G 98G 0 100% /
/dev/nvme1n1 ext4 900G 300G 600G 34% /data

如果是 / 满了,排查根分区。

如果是 /data 满了,排查业务数据。

如果是 /var 单独分区满了,重点看日志、缓存、数据库。

很多人犯的第一个错误是:看到磁盘满了,就在整个系统里乱找大文件。实际上你要先知道满的是哪个挂载点

五、原因一:文件已经被删除,但进程还在占用

这是最常见,也是最容易被忽略的情况。

比如 Nginx 访问日志 /var/log/nginx/access.log 有 30GB,你直接执行:

rm -f /var/log/nginx/access.log

从目录里看,文件确实没了。

但是如果 Nginx 进程还没有释放这个文件句柄,Linux 内核仍然认为这个文件占用的磁盘空间还在。

所以你会看到:

du -sh /var/log/nginx

目录不大。

但:

df -h

磁盘还是满的。

排查命令

lsof | grep deleted

如果输出类似:

nginx   1234 www-data  5w REG  259,2 32212254720 /var/log/nginx/access.log (deleted)
mysql 2231 mysql 7w REG 259,2 12884901888 /var/lib/mysql/mysql-bin.000123 (deleted)

说明这些文件已经从目录中删除了,但进程还在占用。

解决方法

如果是 Nginx:

systemctl reload nginx

如果 reload 不释放,可以重启:

systemctl restart nginx

如果是 PHP-FPM:

systemctl restart php-fpm

Ubuntu 环境可能是:

systemctl restart php8.1-fpm

如果是 MySQL,要谨慎,不要直接乱杀进程。建议先确认业务低峰期,再执行:

systemctl restart mysqld

或:

systemctl restart mysql

更稳妥的处理方式

不要直接删除正在写入的日志文件,而是清空它:

: > /var/log/nginx/access.log

或者:

truncate -s 0 /var/log/nginx/access.log

这样文件句柄还在,空间也能释放。

六、原因二:挂载点覆盖了原目录,du 看不到底层旧文件

这个问题在加数据盘、挂载 /data、迁移网站目录时很常见。

比如你原来在 /data 目录里放了 200GB 文件。

后来你把一块新硬盘挂载到了 /data

mount /dev/nvme1n1 /data

这时候 /data 下面看到的是新硬盘里的内容,原来根分区 /data 目录下那 200GB 文件被“遮住”了。

你执行:

du -sh /data

看到的是新磁盘里的内容,不是被遮住的旧文件。

但这些旧文件仍然占着根分区空间。

排查思路

先看挂载情况:

findmnt

或者:

mount | column -t

重点看 /data/www/home/var/lib/mysql/var/www/html 是否是挂载点。

解决方法

需要在维护窗口操作。

先停业务:

systemctl stop nginx
systemctl stop php-fpm

卸载挂载点:

umount /data

然后查看原目录:

du -sh /data/*

如果发现里面有旧文件,确认无用后再清理:

rm -rf /data/old-backup/*

然后重新挂载:

mount /data

这个问题不能盲目操作,尤其是生产环境,建议先备份和确认挂载关系。

七、原因三:inode 用完了,不是容量用完了

有时候 df -h 看起来空间还有,但系统仍然提示:

No space left on device

这可能不是磁盘容量满,而是 inode 满了。

inode 可以简单理解为“文件数量指标”。哪怕每个文件只有 1KB,只要文件数量特别多,也可能把 inode 用完。

查看 inode

df -i

示例:

Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/nvme0n1p2 6553600 6553000 600 100% /

如果 IUse% 是 100%,说明 inode 满了。

常见目录

/var/lib/php/session
/tmp
/var/tmp
/var/spool/postfix
/var/cache
/www/wwwroot/某些缓存目录

查找小文件数量最多的目录

for i in /*; do echo $i; find $i -xdev -type f 2>/dev/null | wc -l; done

进一步排查:

find /var -xdev -type f | cut -d/ -f1-4 | sort | uniq -c | sort -nr | head

清理示例

清理 7 天前的 PHP session:

find /var/lib/php/session -type f -mtime +7 -delete

清理临时目录:

find /tmp -type f -mtime +3 -delete

注意,不要直接 rm -rf /tmp/*,有些服务可能正在使用临时文件。

八、原因四:Docker 容器日志或 overlay2 吃满磁盘

如果服务器上跑了 Docker,磁盘满了但你用普通方式找不到明显大文件,建议重点查:

/var/lib/docker

尤其是:

/var/lib/docker/containers
/var/lib/docker/overlay2

查看 Docker 占用

docker system df

查看容器日志大小:

find /var/lib/docker/containers -name "*-json.log" -exec ls -lh {} \;

如果看到几十 GB 的 json 日志文件,就很明确了。

清空容器日志

truncate -s 0 /var/lib/docker/containers/*/*-json.log

设置 Docker 日志限制

编辑:

vim /etc/docker/daemon.json

加入:

{
"log-driver": "json-file",
"log-opts": {
"max-size": "200m",
"max-file": "3"
}
}

重启 Docker:

systemctl restart docker

注意,重启 Docker 会影响容器业务,生产环境要安排维护窗口。

九、原因五:systemd journal 日志占用过大

Ubuntu 22.04、Debian、CentOS 7.x 都可能遇到 journal 日志增长的问题。

查看占用:

journalctl --disk-usage

如果显示:

Archived and active journals take up 12.0G in the file system.

就说明 journal 占用不小。

清理 journal 日志

保留最近 7 天:

journalctl --vacuum-time=7d

限制最大 1GB:

journalctl --vacuum-size=1G

设置长期限制

编辑:

vim /etc/systemd/journald.conf

建议配置:

SystemMaxUse=1G
SystemKeepFree=2G
MaxRetentionSec=7day

重启服务:

systemctl restart systemd-journald
 

十、原因六:数据库 binlog、慢日志、错误日志膨胀

很多网站服务器磁盘满,并不是网站文件变大,而是数据库日志把磁盘吃满。

常见目录:

/var/lib/mysql
/www/server/data

宝塔环境经常在:

/www/server/data

查看 MySQL 目录:

du -sh /var/lib/mysql/*

或:

du -sh /www/server/data/*

常见大文件:

mysql-bin.000001
mysql-bin.000002
slow.log
error.log

查看 binlog

进入 MySQL:

SHOW BINARY LOGS;

查看当前使用的 binlog:

SHOW MASTER STATUS;

清理旧 binlog

例如清理到某个时间之前:

PURGE BINARY LOGS BEFORE '2026-05-01 00:00:00';

或者清理到某个文件之前:

PURGE BINARY LOGS TO 'mysql-bin.000120';

不要直接 rm -f mysql-bin.*,这样可能导致 MySQL 状态不一致。

设置保留时间

MySQL 8:

binlog_expire_logs_seconds=604800

表示保留 7 天。

MySQL 5.7:

expire_logs_days=7

十一、原因七:ext4 保留空间导致普通用户写不进去

如果服务器使用 ext4 文件系统,默认可能会保留 5% 空间给 root。

在 100GB 系统盘上,5% 也就是 5GB。

在 1TB 数据盘上,5% 就是 50GB。

这会导致普通用户或服务进程提示磁盘满,但 root 看起来还能操作。

查看保留空间

先找分区:

df -hT

例如是:

/dev/nvme0n1p2

查看:

tune2fs -l /dev/nvme0n1p2 | grep -i "Reserved block"

调低保留比例

如果是数据盘,可以调低到 1%:

tune2fs -m 1 /dev/nvme0n1p2

如果是纯数据盘,甚至可以设为 0:

tune2fs -m 0 /dev/nvme1n1

系统盘不建议随便设为 0,至少保留一点空间,避免系统在异常情况下完全不可操作。

十二、推荐排查顺序:不要一开始就乱删文件

遇到“磁盘满但 du 查不到大文件”,我一般按这个顺序排查。

1. 看哪个分区满了

df -hT

2. 看 inode 有没有满

df -i

3. 查已删除但仍被占用的文件

lsof | grep deleted

如果服务器没有 lsof:

yum install -y lsof

或:

apt install -y lsof

4. 限制在当前文件系统内查大目录

du -xh / --max-depth=1 | sort -h

注意这里的 -x 很重要,它表示不跨文件系统。

继续深入:

du -xh /var --max-depth=1 | sort -h
du -xh /www --max-depth=1 | sort -h
du -xh /data --max-depth=1 | sort -h

5. 查大文件

find / -xdev -type f -size +500M -exec ls -lh {} \; 2>/dev/null

6. 查 Docker

docker system df
find /var/lib/docker/containers -name "*-json.log" -exec ls -lh {} \;

7. 查 journal

journalctl --disk-usage

8. 查数据库日志

du -sh /var/lib/mysql/*
du -sh /www/server/data/*

十三、生产环境处理建议:先止血,再根治

1. 先释放安全空间

可以优先处理这些相对安全的内容:

journalctl --vacuum-size=1G
find /tmp -type f -mtime +3 -delete
truncate -s 0 /var/log/nginx/access.log
truncate -s 0 /var/log/nginx/error.log

但数据库文件、业务上传文件、网站目录不要乱删。

2. 再处理占用源头

比如日志太大,就加 logrotate。

Nginx 日志轮转示例:

/var/log/nginx/*.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
systemctl reload nginx >/dev/null 2>&1 || true
endscript
}

3. 最后做磁盘规划

如果业务已经稳定增长,不建议长期靠清理维持。

对于香港服务器上的网站业务,我更推荐这样拆:

分区 用途 建议
/ 系统、基础服务 80GB - 150GB
/www 网站程序 单独数据盘或大容量分区
/data 上传文件、业务数据 SSD / NVMe
/var/log 日志 可独立分区,避免拖垮系统盘
/backup 备份 不建议和业务盘放一起

十四、不同业务的配置建议

1. 普通企业官网 / WordPress 站

推荐配置:

项目 建议
CPU Intel Xeon E-2334 / AMD EPYC 4585PX
内存 32GB - 64GB
硬盘 960GB NVMe SSD
带宽 100M BGP,含 25M CN2
系统 Ubuntu 22.04 LTS

重点优化:

  • 控制 Nginx 日志保留周期;
  • WordPress 缓存目录设置自动清理;
  • 数据库 binlog 不要无限保留;
  • 上传目录和备份目录不要放在系统盘。

2. 跨境电商 / 外贸独立站

推荐配置:

项目 建议
CPU AMD EPYC 4585PX,16核32线程
内存 64GB DDR5
硬盘 960GB NVMe SSD + 1.92TB SSD
带宽 100M BGP + CN2 优化
适合场景 WooCommerce、Magento、Shopify 外部落地页、ERP接口

重点优化:

  • MySQL 慢日志限制大小;
  • 图片缓存目录独立;
  • 备份不要和网站目录混放;
  • /var/log 建议单独监控。

3. 高并发接口 / 日志量大的业务

推荐配置:

项目 建议
CPU AMD EPYC 7402P,24核48线程
内存 128GB
硬盘 2 × 1.92TB NVMe SSD
带宽 300M / 1G BGP
系统 Ubuntu 22.04 LTS

重点优化:

  • 日志异步写入;
  • 接入 ELK / Loki / ClickHouse;
  • 本机只保留 3 - 7 天日志;
  • 按天切割日志,避免单文件过大;
  • 关键目录单独挂载,防止根分区被写满。

十五、一个比较完整的排查脚本

可以临时保存为:

vim disk-check.sh

内容如下:

#!/bin/bash

echo "===== 1. Disk Usage ====="
df -hT

echo
echo "===== 2. Inode Usage ====="
df -i

echo
echo "===== 3. Top Level Directory Usage ====="
du -xh / --max-depth=1 2>/dev/null | sort -h

echo
echo "===== 4. Deleted But Open Files ====="
lsof | grep deleted | head -50

echo
echo "===== 5. Large Files Over 500MB ====="
find / -xdev -type f -size +500M -exec ls -lh {} \; 2>/dev/null | sort -k5 -h

echo
echo "===== 6. Journal Usage ====="
journalctl --disk-usage 2>/dev/null

echo
echo "===== 7. Docker Usage ====="
docker system df 2>/dev/null

echo
echo "===== 8. Docker Logs ====="
find /var/lib/docker/containers -name "*-json.log" -exec ls -lh {} \; 2>/dev/null

执行:

chmod +x disk-check.sh
./disk-check.sh

这个脚本不会删除文件,只用于排查,适合先看现场情况。

十六、我不建议的几个操作

遇到磁盘满,千万不要急着执行这些命令:

rm -rf /var/log/*
rm -rf /tmp/*
rm -rf /var/lib/mysql/mysql-bin.*
rm -rf /var/lib/docker/overlay2/*

这些操作很容易导致服务异常、数据库损坏、容器无法启动。

正确做法是:先确认文件来源、确认是否正在被进程占用、确认是否可以安全清理,再处理。

十七、总结:du 查不到,不代表磁盘没有被占用

Linux 服务器磁盘满了,但 du 查不到大文件,最常见的不是系统异常,而是以下几类问题:

  1. 文件被删除了,但进程还在占用;
  2. 挂载点覆盖了旧目录;
  3. inode 被小文件耗尽;
  4. Docker 容器日志或 overlay2 占用过大;
  5. systemd journal 没有限制;
  6. MySQL binlog、慢日志、错误日志持续膨胀;
  7. ext4 保留空间导致普通用户无法写入。

真正专业的处理方式,不是看到大文件就删,而是先用:

df -hT
df -i
lsof | grep deleted
du -xh / --max-depth=1
find / -xdev -type f -size +500M

把问题定位清楚。

对于网站业务、跨境电商、接口服务和高并发应用来说,磁盘规划和日志策略比临时清理更重要。尤其是香港服务器这类承载外贸站、WordPress、API、图片站的业务环境,建议一开始就把系统盘、数据盘、日志目录、备份目录分开设计,这样即使某个业务日志突然暴涨,也不至于把整台服务器拖到无法登录、数据库无法写入的状态。

目录结构
全文