凌晨三点,监控告警声划破夜空:"/ 分区使用率 100%!"你登录服务器,df -h 一看,根分区红得发紫。更可怕的是,当你删掉几个日志文件后,df -h 显示空间一点都没释放!系统开始报错 No space left on device,新服务起不来,数据库连不上,业务直接瘫痪。
别慌。磁盘空间不足就像衣柜塞满了衣服------不是没地方了,是该扔的没扔,该叠好的乱堆着。本文将带你从快速诊断到深度清理,再到预防措施,系统性地解决Linux磁盘空间问题。
一、快速诊断:先搞清楚"谁吃了我的空间"
在动手清理之前,你需要像医生问诊一样,先诊断病因。
1.1 查看磁盘整体使用情况
df 命令是诊断的起点:
bash
df -h
输出示例:
[root@ansible-controller ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 4.0M 0 4.0M 0% /dev
tmpfs 1.8G 0 1.8G 0% /dev/shm
tmpfs 724M 9.1M 715M 2% /run
/dev/mapper/rl-root 17G 17G 453M 98% /
/dev/nvme0n1p1 960M 223M 738M 24% /boot
tmpfs 362M 0 362M 0% /run/user/0
Use% 接近100%,说明磁盘空间确实不足。但这里有个坑:有时候 Avail 显示还有空间,系统却报 No space left,那很可能是 inode 耗尽了。
1.2 检查 inode 使用情况
磁盘空间有两个维度:一个是存储空间(blocks),另一个是 inode 数量。每个文件都会占用一个 inode,如果磁盘上存在大量小文件,即使存储空间还有剩余,inode 也可能被耗尽,导致无法创建新文件。
bash
df -i
输出示例:
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda1 3276800 3276800 0 100% /
如果 IUse% 达到100%,说明 inode 资源已耗尽。此时删除大文件毫无意义,正确的动作是找到那些巨量小文件所在的目录进行清理。
1.3 定位大文件/大目录
df 是卫星云图,告诉你暴风雨在哪个区域聚集;du 是地面侦察,告诉你具体哪栋楼的哪个房间漏水了。
方法一:逐层排查(通用)
bash
# 查看根目录下各子目录的大小,从大到小排序
du -sh /* 2>/dev/null | sort -rh | head -20
找到最大的目录后,进入该目录继续执行相同命令,逐层下钻。
方法二:黄金组合命令(推荐)
bash
# 切换到问题挂载点
cd /
# 只统计当前目录下一级子目录,按大小排序取前10
du -h --max-depth=1 | sort -hr | head -n 10
方法三:查找大文件
bash
# 查找全盘大于100MB的文件
find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null
二、深度清理:对症下药
2.1 场景一:日志文件占满磁盘(最常见)
日志文件是磁盘空间的头号杀手。
找到占用空间大的日志文件后,不要急着 rm 。更稳妥的做法是清空文件内容,特别是对于没有做日志轮转一致持续写入的打日志文件:
bash
# 将空内容重定向到日志文件中,无需重启服务
echo "" > var/log/nginx/access.log
如果确定要删除,请确保该文件没有被任何进程正在写入。如果日志文件一直持续写入,rm删除文件会导致句柄不会释放,一直占着存储空间。
2.2 场景二:inode 耗尽(小文件过多)
找到小文件最多的目录
bash
# 查看指定目录下各子目录占用的 inode 数量
sudo du -sh --inodes /var/* | sort -rh | head -10
常见重灾区:
/var/spool/mail------ 邮件队列堆积大量小文件/tmp------ 临时文件碎片/var/lib/docker/overlay2------ Docker 容器层碎片文件
找到后,清理无用的缓存或临时文件即可释放 inode。
2.3 场景三:文件已删除但空间未释放(最隐蔽的坑)
这是很多新手的噩梦:明明用 rm 删除了 20G 的日志文件,df -h 一看,磁盘占用率还是 95%!,详见如下演示:


根本原因 :该文件正在被某个进程打开。rm 命令只是移除了文件名到 inode 的链接,但只要文件描述符(fd)没有被关闭,内核就不会真正回收该文件占用的数据块。
排查方法:
bash
# 列出所有被删除但还被进程占用的文件,按大小排序
sudo lsof +L1 | grep deleted | awk '{print $7, $9}' | sort -rh
+L1 是关键参数,表示只列出链接数小于1(即已被删除)的文件。重点关注那些 GB 级别的文件。

如上图/var/log/nginx/access.log已经被删除,但是句柄没有释放,一直占着磁盘空间超15G。
解决方案:
bash
# 1. 从 lsof 输出中找到进程 PID(第一列)
sudo lsof +L1 | grep 'deleted'
# 输出示例:nginx 21446 root 5w REG 253,0 15730335665 0 34462744 /var/log/nginx/access.log (deleted)
# 这里的 PID 是 21446
# 2. 重启或停止对应的服务进程
sudo kill -9 21446

进程终止后,内核会自动释放被占用的文件描述符,磁盘空间就会回来。

注意 :
kill -9 是强制终止,**在生产环境操作前请评估业务影响**。
2.4 场景四:其他可清理的空间
包管理器缓存
bash
# Ubuntu/Debian
sudo apt-get clean # 清理 /var/cache/apt/archives
sudo apt-get autoremove # 删除不再需要的依赖包
# CentOS/RHEL
sudo yum clean all
Docker 清理
bash
# 清理未使用的 Docker 资源
docker system prune -f
docker system prune -a -f # 更激进,清理所有未使用的镜像
三、预防措施:别让问题再复发
3.1 配置 logrotate 自动轮转
logrotate 是 Linux 系统自带的日志轮转工具,能自动压缩、删除旧日志。
查看配置:
bash
cat /etc/logrotate.conf # 主配置文件
ls /etc/logrotate.d/ # 各服务的日志配置
以 Nginx 为例,配置 /etc/logrotate.d/nginx:
/var/log/nginx/*.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 644 nginx nginx
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
3.2 建立监控告警
建议在磁盘使用率达到 80% 时就发出预警,而不是等到 100% 才被动响应。可以使用 Prometheus + Grafana 或云厂商自带的监控服务。
3.3 编写清理脚本自动化
可以将日常清理工作写成脚本,定期执行。例如每周日凌晨执行一次日志清理和缓存清理。
3.4 终极方案:扩容
如果清理后空间仍然不足,或者业务数据持续增长无法删除,那就需要考虑扩容云盘。在云环境下,这通常是最快的解决方案。
3.5 什么数据可以清理
一般来说/var/log/目录下*.log之类的日志是可以清理的,这些日志一般是纯文本形式;或者对应应用目录下的log或者logs目录下的存文本日志可以清理,但这只是一般情况,清理日志一定要特别谨慎,不能确认是否可以清理不要盲目的动数据,以免影响业务运行。
四、总结
遇到 Linux 磁盘 100% 的问题,记住这个流程:
- 先诊断 :
df -h看空间,df -i看 inode - 再定位 :
du逐层排查,find找大文件 - 查幽灵 :
lsof +L1 | grep deleted找已删未释放的文件 - 安全清理 :日志用
echo "" >清空 - 固化配置 :配置
logrotate,防止复发 - 终极方案:空间实在不够就扩容
核心原则就一条:不盲删,先诊断;找对因,再下手。希望这篇文章能帮你在下一次磁盘告警时,从一个手忙脚乱的"删库跑路"预备役,变成一个冷静专业的 SRE。
如果你有更好的清理技巧,欢迎在评论区分享交流!