服务器突然告警:磁盘使用率 100%。网站打不开,数据库写不进去,连 SSH 登录都卡半天才进。这种事每个运维都遇到过,处理思路其实很固定:先定位谁占了空间,再决定删什么。
磁盘占用排查命令速查
| 命令 | 作用 | 示例 |
|---|---|---|
| df -h | 看整体磁盘使用 | df -h / |
| du -sh * | 看目录大小 | du -sh /var/* |
| ncdu | 交互式磁盘分析 | ncdu /var |
| find -size | 找大文件 | find / -size +500M |
| lsof | grep deleted | 找已删但未释放 | lsof +L1 |
第一步:看整体使用情况
登录上去先跑 df -h,看是哪个分区满了。大部分时候是根分区 / 或者数据分区 /var 撑爆了。输出长这样:
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 40G 38G 20K 100% /
Use% 100%,Avail 几乎为零。记住这个分区,后面所有排查都围绕它。
第二步:找大目录
用 du 从根目录逐层找谁最占空间:
du -h --max-depth=1 / 2>/dev/null | sort -rh | head -20
这会列出根目录下每个子目录的大小,从大到小排序。找到最大的那个,进去再跑一次同样的命令,一层层缩小范围。一般几步就能定位到具体目录。
常见的重灾区:
/var/log— 日志文件没做轮转,或者某个服务疯狂报错刷日志/var/lib/docker— Docker 镜像和容器层堆积/tmp— 临时文件没清理/home/用户名— 用户数据或者备份文件堆积/var/www— 网站上传的附件、缓存文件
第三步:找大文件
目录定位了,再看具体哪个文件最大:
find /var/log -type f -size +100M -exec ls -lh {} \; | awk '{print $5, $9}' | sort -rh
这条命令找指定目录下大于 100MB 的文件,按大小排序。把 /var/log 换成你定位到的大目录。
日志文件占满怎么处理
这是最常见的情况。先看是哪个日志文件膨胀:
ls -lhS /var/log/ | head -10
如果有个文件比如 syslog 或者 nginx/error.log 涨到了几个 G,直接清空它:
truncate -s 0 /var/log/nginx/error.log
用 truncate 而不是 rm,因为有些服务持有文件句柄,直接删文件空间不会释放,得重启服务才行。truncate 清空内容但保留文件句柄,服务不受影响。
然后检查为什么日志暴涨。通常是某个服务在疯狂报错,比如 MySQL 连接失败、PHP fatal error。看日志内容找到根因,修掉它,否则过几天又会涨满。
长期方案是配置 logrotate。检查 /etc/logrotate.d/ 下有没有对应服务的配置,没有就加一个。
Docker 占满怎么处理
如果 /var/lib/docker 是大头,用 Docker 自带的清理命令:
docker system prune -a --volumes
这条命令删掉所有停止的容器、无用的网络、悬空的镜像和卷。如果有些容器还在运行但你确定不需要了,先 docker stop 再删。
注意 --volumes 会删除未被任何容器引用的卷,如果有数据卷你不舍得丢,先 docker volume ls 看一眼,确认没有重要数据再执行。
已删除但空间没释放
有时候你删了文件,df 显示空间没变。这是因为有进程还在持有被删文件的句柄。用这条命令找出来:
lsof +L1 | grep deleted
输出会显示哪个进程持有已删除的文件。重启对应进程(或者 kill 掉),空间就会释放。
清理包管理缓存
两个常见的缓存清理:
apt clean && apt autoclean && apt autoremove -y
对 CentOS/RHEL:
yum clean all && dnf autoremove
一般能省几百 MB,不多但聊胜于无。
更多服务器运维实操,请访问 fenij.com。
常见问题
问:删了文件 df 还是显示 100% 怎么办?
答:有进程持有已删除文件的句柄。运行 lsof +L1 | grep deleted 找到进程,重启或 kill 该进程即可释放空间。
问:logrotate 已经配了但日志还是很大?
答:检查 logrotate 是否真的在跑。logrotate -d /etc/logrotate.d/你的配置 做一次 dry-run。如果配置没报错,看 /var/log/syslog 里有没有 logrotate 的执行记录。cron 可能没装或者没启动。
问:inode 用完了但磁盘空间还有?
答:小文件太多会耗尽 inode。运行 df -i 看 inode 使用率。用 find / -xdev -printf '%h\n' | sort | uniq -c | sort -k1 -n | tail -5 找哪个目录下文件最多,然后清理。
进阶:云盘扩容不生效与预防监控
现在的服务器大多在云上,磁盘是「云盘」,光在系统里扩容不够。你在阿里云/腾讯云/AWS 控制台把盘从 40G 加到 100G,回头 df -h 还是 40G——因为分区表和文件系统还没扩。步骤分两层:
# 1. 扩分区(把第 1 个分区撑满整块盘)
growpart /dev/vda 1
# 2. 扩文件系统
resize2fs /dev/vda1 # ext4
xfs_growfs / # xfs 自动撑满
LVM 场景不一样:先 pvresize /dev/vda1 让物理卷认新空间,再 lvextend -r -l +100%FREE /dev/mapper/xxx。
| 文件系统 | 扩分区 | 扩文件系统 |
|---|---|---|
| ext4 | growpart /dev/vda 1 | resize2fs /dev/vda1 |
| xfs | growpart /dev/vda 1 | xfs_growfs / |
| LVM | pvresize | lvextend -r |
别一满就删文件救急,治本要预防。写个 cron 脚本每天查使用率,超过 80% 就发告警(邮件或企业微信/钉钉 Webhook):
df -h | awk 'NR>1 && int($5) > 80 {print $0}'
把这条塞进 /etc/cron.daily/ 或配个监控面板(如 Netdata、node_exporter+Grafana)。等磁盘 100% 才处理,数据库往往已经崩了。另外提醒:删大文件前一定先 lsof +L1 | grep deleted 确认没进程占用,否则空间不释放(前面讲过);日志类文件用 truncate -s 0 而不是 rm。
延伸答疑
控制台扩了容,df 还是老大小?
只扩了云盘,没扩分区和文件系统。按上面 growpart + resize2fs 两步补齐。
Docker 占的空间想单独挂盘?
把 /var/lib/docker 迁到新挂载点,或建盘后改 docker 的 data-root 配置,重启 docker 服务生效。
df 显示有空间但写不进文件?
看 inode:df -i。小文件太多 inode 耗尽也会写失败,按前面方法找文件最多的目录清理。
怎么长期监控磁盘?
cron + df 阈值告警最轻量;正经点用 Netdata、node_exporter+Grafana,能看历史趋势提前扩容。