磁盘空间耗尽是最常见的线上故障之一。症状包括服务无法写入数据、程序报“No space left on device”错误、数据库停止响应等。处理这类问题有一套标准的排查和解决流程,核心思路是:先快速确认空间占用概况,再精准定位占用源,最后根据情况选择清理或扩容。
1. 快速确认磁盘使用概况
当怀疑磁盘满了,第一步用 df 查看所有挂载分区的使用情况:
df -h
输出类似:
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 50G 48G 0G 100% /
重点看 Use% 达到 100% 的分区,并记录其挂载点(如 / 或 /data)。如果发现某个分区已满,下一步就要找出到底是什么文件占用了空间。
有时 df 显示满了,但用 du 统计文件总大小却远小于分区容量。这种情况通常是文件已被删除但进程仍持有句柄导致的——删除文件并不会立即释放磁盘空间,只有当所有使用该文件的进程关闭它或重启后,空间才会回收。可以用 lsof 查找这类“幽灵文件”:
lsof | grep deleted
然后重启对应的服务或进程,空间即可恢复。
2. 定位大文件和大目录
进入疑似占满的目录(例如根目录 /),使用 du 逐层排查:
# 查看根目录下各子目录的总大小,按大小排序,只取前10个
du -sh /* 2>/dev/null | sort -rh | head -10
du -sh 会汇总每个参数的总大小,sort -rh 按人类可读格式反向排序(大的在上)。通过不断进入大目录重复上述命令,可以快速收敛到具体的大文件或日志目录。
如果想直接在某个目录下找出所有大于 100MB 的文件,可以用 find:
find /var -type f -size +100M -exec ls -lh {} \; 2>/dev/null
或者使用更直观的交互式工具 ncdu(多数发行版需单独安装):
ncdu / # 进入交互界面,用方向键浏览,按 d 删除文件
在实际操作中,切忌在根分区已满的情况下进行大量不必要写入(甚至删除操作本身也可能因无法创建临时文件而失败)。先清理出少量空间(如几 MB)让系统恢复基本功能,再进行大规模清理。
3. 清理日志文件
日志是空间消耗的“重灾区”,常见位置在 /var/log。可以直接查看该目录的大小:
du -sh /var/log/*
常见的清理场景和处理方式:
- 系统日志(
/var/log/syslog、/var/log/messages等):如果发现单个日志文件异常庞大(几十 GB),说明某个服务在疯狂写错误信息。先定位来源(阅读日志尾部几百行),修复根本问题后再清空。清空某个大日志最快的方式是:
# 用 echo 重定向空内容,比 rm 再 touch 更安全,进程不需要重新打开文件
echo > /var/log/syslog
或者使用 truncate:
truncate -s 0 /var/log/syslog
注意不要直接 rm 然后手动 touch,这可能导致日志服务丢失文件描述符,需要重启服务才能恢复正常写入。
- journald 日志(使用
systemd的发行版):日志存放在二进制文件中,用journalctl查看和清理。
journalctl --disk-usage # 查看当前日志占用磁盘大小
# 清理保留最近 2 天的日志
journalctl --vacuum-time=2d
# 或限制日志总占用不超过 500MB
journalctl --vacuum-size=500M
- 应用日志(如
/var/log/nginx/、/var/log/mysql/):这些目录常因没有配置日志轮转(logrotate)而无限增长。应检查是否有对应的 logrotate 配置(/etc/logrotate.d/),并手动执行一次轮转:
logrotate -f /etc/logrotate.d/nginx
如果没有配置,可参照现有配置模板快速创建一个,确保日志定期被归档和清理。
清理后立即用 df -h 确认 Use% 是否下降。如果空间没有释放,大概率就是前面提到的“删除文件但句柄未释放”问题,需要重启相关服务。
4. 扩容处理
如果清理后空间仍然不足,或应用本身就确实需要更大容量,就需要扩容磁盘。方式取决于环境:
(1)物理机/虚拟机(LVM 逻辑卷)
现在大多数服务器安装时使用 LVM(逻辑卷管理器),扩容非常灵活:
- 如果卷组(VG)还有剩余空间,直接扩展逻辑卷和文件系统:
# 给 /dev/mapper/vg0-root 增加 10GB
lvextend -L +10G /dev/mapper/vg0-root
# 扩展 ext4 文件系统以使用新空间(xfs 用 xfs_growfs /)
resize2fs /dev/mapper/vg0-root
- 如果卷组没有剩余空间,需要先添加一块新磁盘(或云端挂载新云盘),将其创建为物理卷(PV),扩展到卷组中,再扩逻辑卷和文件系统。
(2)云服务器(云盘)
主流云平台支持直接在线扩容云盘:
- 在控制台调整云盘容量(例如从 50GB 扩到 100GB)。
- 登录服务器,让系统重新扫描磁盘(或重启),然后用
fdisk或growpart扩展分区,最后扩展文件系统。
以扩展根分区为例(假设分区为 /dev/sda1):
growpart /dev/sda 1 # 扩展分区(注意设备名和分区编号)
resize2fs /dev/sda1 # 扩展文件系统(xfs 用 xfs_growfs /)
(3)非 LVM 的传统分区
如果根分区是普通分区且磁盘已无空闲空间,操作会比较棘手。一般需要在相同磁盘上删除相邻分区来腾出空间,或者将数据迁移到更大的磁盘。对于生产环境,建议趁维护窗口直接迁移至 LVM 架构,从根本上解决弹性扩容的问题。
5. 预防措施
处理完故障后,应建立预防机制,避免同样事情再发生:
- 为关键分区设置监控告警,例如当使用率超过 80% 时发送通知(Prometheus + node_exporter、Zabbix 等都能轻松实现)。
- 确保
/var/log下所有应用都有合理的 logrotate 配置,并测试轮转是否生效。 - 对于会持续增长的数据应用,提前做好容量规划,使用 LVM 或云盘弹性扩容能力预留余量。
- 定期清理无用的旧内核、软件包缓存(
apt autoremove、yum autoremove)、Docker 镜像等。
磁盘空间满虽然紧急,但只要按照“df 确认→du/find 定位→清理/扩容→预防”的思路,通常可以在几分钟内恢复服务,并将影响降到最低。