# Linux 服务器磁盘已满: 找出占用空间的内容

磁盘占满通常只有一两个明显的原因。请自上而下逐步排查,先查看再删除;除非清楚某个目录归哪个服务所有,否则不要手动删除 /var/lib 下的文件。

## 1. 确认哪个文件系统已满

运行 df -h。查看 Use% 列和 Mounted on 列:已满的文件系统可能是 /,也可能是单独挂载的 /var、/home 或 /data,清理错了对象不会有任何效果。
同时运行 df -i。文件系统可能还有可用空间,却没有可用的 inode,这种情况通常是数以百万计的小文件堆积造成的(会话文件、邮件队列、缓存文件)。如果 IUse% 接近 100%,要找的就是大量小文件,而不是少数大文件。

## 2. 找出最大的目录

运行 sudo du -xh --max-depth=1 / | sort -h,并查看最后几行。-x 选项只在同一个文件系统内统计,因此已挂载的磁盘和虚拟文件系统不会干扰结果。在最大的目录内重复此操作,例如 sudo du -xh --max-depth=1 /var | sort -h。
如果已安装 ncdu(在 Debian 和 Ubuntu 上使用 sudo apt install ncdu),可以用 sudo ncdu -x / 以交互方式浏览同样的数据。

## 3. 检查已删除但仍被打开的文件

如果 du 显示的用量远小于 df,可能是某个进程仍然打开着一个已删除的文件,通常是体积很大的日志。sudo lsof +L1 会列出链接数为零的已打开文件。该进程关闭文件后,空间才会释放,这通常意味着需要重启占用该文件的服务。请在空闲时段操作,不要在请求高峰期进行。

## 4. 检查常见的占用来源

日志:查看 /var/log,并用 journalctl --disk-usage 检查日志。如果占用很大,请参阅我们关于限制 journald 大小的指南。
软件包:sudo apt clean 会删除已下载的软件包文件;sudo apt autoremove 会列出不再需要的软件包和旧内核,并在你确认之前显示将要删除的内容。请保留当前运行的内核和上一个版本。
Docker:docker system df 会显示镜像、容器、卷和构建缓存。docker system prune 会删除已停止的容器、未使用的网络和悬空镜像;除非添加 --volumes,否则不会删除卷,因此请在回答前仔细阅读提示。
Snap:snap list --all 会显示已禁用的 snap 旧版本,可以用 snap remove NAME --revision=NUMBER 逐个删除。

## 5. 释放空间之后

再次运行 df -h,并检查因磁盘已满而停止的服务是否已恢复运行(systemctl --failed)。遇到磁盘已满的数据库,在你信任它之前,可能需要重启或检查。
然后设置限制,避免问题再次发生:日志轮转、journald 限制,以及在磁盘使用率达到 90% 之前发出告警。

## FAQ

**可以安全删除 /var/log 中的文件吗?**

已轮转并压缩的日志(例如 syslog.1 或 .gz 文件)在不再需要时通常可以删除。不要删除正在运行的服务的当前日志文件;请谨慎地将其截断,或交给 logrotate 处理,并先确认该服务的要求。

**为什么 df 显示磁盘已满,而 du 的统计却对不上?**

通常是因为已删除的文件仍被某个正在运行的进程打开着(参见 lsof +L1),或者这两个数字来自不同的文件系统。请使用 du -x,并针对同一挂载点与 df 进行比较。

**我应该在生产服务器上运行 docker system prune 吗?**

只有在运行 docker system df 并查看哪些内容未被使用之后才可以。它可能会删除你仍打算启动的镜像。卷默认会保留,但请确保重要数据已有备份。

Source: https://raincleaner.eu/zh/guides/linux-server-disk-full-find-what-is-using-space