Linux磁盘空间告警排查:从df/du差异到安全清理与扩容
1. 问题定位你的磁盘真的满了吗遇到/dev/sda1磁盘空间告急屏幕上跳出 “No space left on device” 的提示这几乎是每个Linux运维和开发人员都会经历的“心跳时刻”。别急着删文件第一步永远是精准定位。很多人一上来就用rm -rf结果可能删错了日志导致服务异常或者发现删了文件空间也没释放白白折腾。我处理过无数次类似问题核心经验就一条先搞清楚空间被谁、以什么方式占用了。最常用的工具是df和du但它们的差异常常让人困惑。df是从文件系统层面看空间报告的是磁盘块的分配情况而du是统计文件和目录实际占用的磁盘空间。两者出现巨大差异比如df显示用了90%du统计总和只有50%是问题的关键线索这通常指向了“幽灵空间”——已被删除但未被释放的文件或者隐藏的磁盘“黑洞”。一个快速定位的命令组合拳如下# 1. 查看整体磁盘使用情况确认是哪个挂载点满了 df -h你会看到类似输出Filesystem Size Used Avail Use% Mounted on /dev/sda1 50G 48G 0G 100% /这里明确是根分区/dev/sda1满了。注意-h参数表示以人类可读的格式G、M显示比直接看字节数直观得多。接着我们需要钻到文件系统里看看是哪些目录在“吃”空间# 2. 找出根目录下占用空间最大的前10个目录 sudo du -h --max-depth1 / 2/dev/null | sort -hr | head -n 10解释一下这个命令链sudo因为有些目录需要 root 权限才能访问。du -h --max-depth1 /计算根目录/下直接子目录的磁盘使用情况--max-depth1只统计一层避免输出过于冗长。2/dev/null将访问错误如权限不足的信息丢弃让输出更干净。sort -hr-h能正确排序人类可读的数值如 10K, 2M, 1G-r是反向排序从大到小。head -n 10只显示前10行结果。这个命令能迅速帮你锁定目标比如输出可能是45G /var 2.5G /usr 1.2G /home ...如果/var占了45G那问题八成就在这里面了。1.1 揪出“元凶”深入可疑目录假设我们发现/var是罪魁祸首下一步就是继续深入。但/var目录下子目录众多手动一个个查效率太低。可以写个简单的循环命令或者使用ncdu这个交互式工具如果系统已安装。这里展示命令行的方式# 3. 逐层深入直到找到最大的文件或目录 sudo du -h --max-depth1 /var 2/dev/null | sort -hr | head -n 10 # 假设发现 /var/log 很大 sudo du -h --max-depth1 /var/log 2/dev/null | sort -hr | head -n 10 # 假设发现某个应用日志文件特别大 ls -lh /var/log/myapp/ | grep -E \.log$ | sort -hr -k5 | head -n 5通过这样层层递进你很快就能定位到具体的超大日志文件比如一个叫application.log的文件竟然有20G、缓存目录或者docker镜像/容器数据。1.2 当du和df结果对不上时这是最棘手的状况之一。df显示磁盘快满了但du统计所有文件加起来远没那么多。这通常意味着有进程打开了某个大文件然后这个文件被删除了。在Linux中如果一个文件正在被进程使用你即使用rm删除它其占用的磁盘空间也不会立即释放直到所有打开它的进程都关闭文件句柄。这些空间对du不可见但对df依然有效。检查这种情况的命令是lsof# 4. 查找已被删除但仍被进程占用的文件 sudo lsof L1 2/dev/null | grep deleted或者更精准地针对某个满的挂载点sudo lsof / | grep deleted输出会显示进程PID、命令名以及被删除的文件路径和大小。找到这些进程后你可以选择重启它们如重启Web服务器、数据库服务来释放空间或者更优雅地通过向进程发送信号让其重新打开日志文件例如对Nginx执行nginx -s reopen。实操心得在生产环境中不要轻易kill -9这些进程尤其是数据库或核心服务。优先考虑优雅重启或联系应用负责人处理。我曾见过有人直接杀掉了正在写数据的MySQL进程导致数据文件损坏恢复起来非常麻烦。2. 清理策略安全高效地释放空间定位到问题根源后就可以着手清理了。但清理不是蛮干必须有策略否则可能引发服务中断或数据丢失。2.1 清理日志文件日志是空间的第一大杀手。对于系统日志/var/log/可以使用logrotate工具它默认已配置并定期运行。但有时应用日志不受其管理。对于单个巨大的日志文件直接rm可能影响正在写入的进程。更安全的方法是清空文件内容# 5. 清空大日志文件确保不需要其内容后 sudo truncate -s 0 /var/log/myapp/giant.log # 或者使用 cat /dev/null sudo cat /dev/null /var/log/myapp/giant.logtruncate命令比rm后重启服务更安全因为它保持了文件的 inode 和打开状态进程可以继续写入。对于按日期滚动的日志可以删除过旧的日志文件# 6. 删除 /var/log 下超过30天的 .log 和 .gz 文件 sudo find /var/log -name *.log -mtime 30 -delete sudo find /var/log -name *.gz -mtime 30 -delete-mtime 30表示修改时间在30天以前。执行前务必用-ls代替-delete先确认要删除的文件列表这是一个好习惯。2.2 处理包管理缓存对于使用apt(Debian/Ubuntu) 或yum/dnf(RHEL/CentOS/Fedora) 的系统包管理器的缓存也可能占用几个G的空间。# 对于 apt 系统 sudo apt clean # 清理所有已下载的 .deb 包缓存 sudo apt autoclean # 仅清理过时版本的 .deb 包缓存 # 对于 yum/dnf 系统 sudo yum clean all # 清理所有缓存元数据和包文件 sudo dnf clean all # dnf 同上清理缓存是安全的不会影响已安装的软件只是下次安装新软件时需要重新下载。2.3 Docker 磁盘空间管理如果你在服务器上运行 Docker它的镜像、容器、卷和构建缓存可能是隐藏的“空间吞噬者”。即使你删除了镜像如果还有容器在引用其层或者有悬空dangling镜像空间也不会释放。# 7. 查看 Docker 磁盘使用概况 docker system df # 8. 清理所有悬空镜像未被任何容器引用的中间层 docker image prune -f # 9. 清理所有停止的容器、未使用的网络、悬空镜像和构建缓存谨慎 docker system prune -a -f警告docker system prune -a会删除所有未被使用的镜像包括可能被其他镜像依赖但未打标签的中间层以及停止的容器、卷和网络。执行前请确保理解其影响。对于生产环境建议定期手动清理而不是依赖这个“核弹”命令。2.4 查找并删除特定类型的大文件有时我们需要全局搜索大文件。# 10. 在整个根目录下查找大于100M的文件 sudo find / -type f -size 100M 2/dev/null | xargs ls -lh | sort -k5,5hr | head -202/dev/null同样是为了忽略权限错误和访问/proc,/sys等虚拟文件系统的噪音。找到不需要的大文件如旧的备份文件、崩溃转储 core 文件、下载的临时文件后再手动决定删除。3. 扩容与高级管理治本之道清理是应急扩容和管理才是长治久安。如果/dev/sda1是物理磁盘分区并且磁盘还有未分配空间可以考虑在线扩容。这通常发生在虚拟机或云主机上。3.1 LVM 逻辑卷扩容如果使用的是LVM如果你的根文件系统建立在LVM之上那么扩容会相对灵活和安全。首先确认是否使用LVM# 11. 检查根文件系统是否在LVM逻辑卷上 df -h / | grep -q ^/dev/mapper echo 可能是LVM || echo 可能不是LVM lsblk # 更直观地查看块设备树状结构如果lsblk输出显示sda下面有sda1、sda2并且有vg_name-lv_root这样的映射那就是LVM。假设我们有一块新磁盘/dev/sdb要将其空间加入根逻辑卷步骤大致如下# 12. LVM 扩容步骤示例 # a. 创建物理卷 sudo pvcreate /dev/sdb # b. 将物理卷扩展到现有的卷组假设卷组名为 centos sudo vgextend centos /dev/sdb # c. 扩展逻辑卷假设逻辑卷名为 root sudo lvextend -l 100%FREE /dev/mapper/centos-root # d. 调整文件系统大小对于 xfs 和 ext4 不同 # 如果是 ext4: sudo resize2fs /dev/mapper/centos-root # 如果是 xfs: sudo xfs_growfs /重要操作前务必备份重要数据并确保你理解每一步的含义。对于生产系统建议在维护窗口进行。3.2 非LVM分区扩容如果/dev/sda1是直接的分区非LVM并且它后面有未分配空间扩容就复杂得多通常需要借助growpart和resize2fs/xfs_growfs工具但前提是分区表类型如GPT和文件系统支持在线扩容。更常见的情况是添加新磁盘然后通过软链接或挂载新目录来转移部分数据如将/home或/var/lib/docker迁移到新盘。3.3 预防性监控与管理临时救火不如日常防火。建立简单的磁盘空间监控很有必要。配置日志轮转确保所有关键应用如Nginx, MySQL, Docker容器的日志都配置了合理的logrotate策略按大小或时间切割并压缩旧日志。使用监控工具像Prometheus配合node_exporter或者简单的crontab定时任务在磁盘使用率超过80%时发送告警邮件。定期清理任务将一些安全的清理命令写入crontab例如每周清理一次 Docker 悬空镜像和构建缓存每月清理一次旧的日志包。一个简单的 shell 脚本监控示例可以放到crontab中每小时运行一次#!/bin/bash THRESHOLD80 CURRENT_USE$(df / | awk NR2 {print $5} | sed s/%//) if [ $CURRENT_USE -gt $THRESHOLD ]; then echo 警告根分区磁盘使用率 ${CURRENT_USE}% 超过阈值 ${THRESHOLD}% | mail -s 磁盘空间告警 $(hostname) adminexample.com # 可以在这里触发自动清理脚本 fi4. 疑难杂症与深度排查即使上述方法都试过有时还是会遇到一些奇怪的问题。这里分享几个我踩过的坑和对应的排查技巧。4.1 文件系统预留空间df显示的使用率可能包含为 root 用户保留的块通常是5%。这是为了在磁盘完全满时root 用户仍有空间执行修复操作。但对于数据盘这个预留可能没必要。你可以检查并调整# 13. 查看文件系统预留空间比例 sudo tune2fs -l /dev/sda1 | grep -i Reserved block count # 或者更直接看百分比 sudo dumpe2fs -h /dev/sda1 2/dev/null | grep -i Reserved blocks如果确定要释放这部分空间比如对于纯数据存储的/data分区可以调整为1%甚至0%sudo tune2fs -m 1 /dev/sda1 # 将预留空间比例调整为1%警告对根分区/执行此操作需极其谨慎保留至少3%-5%是系统稳定性的安全垫。4.2 Inode 耗尽df -h显示空间充足但系统依然报“No space left on device”。这可能是因为 inode 用完了。inode 存储文件的元信息权限、所有者、时间戳、数据块位置等。如果分区内存放了海量小文件比如邮件队列、Docker容器层、缓存文件就可能耗尽 inode。# 14. 检查 inode 使用情况 df -i /如果IUse%接近100%就需要清理文件而不是关注容量。查找 inode 消耗大户# 15. 查找占用大量 inode 的目录 sudo find / -xdev -type f | awk -F/ {print /$2} | sort | uniq -c | sort -rn | head -10这个命令统计根目录下第一级子目录中的文件数量。找到目标后进去进一步分析并清理。4.3 稀疏文件与磁盘碎片稀疏文件sparse file是另一种特殊情况它“看起来”很大但实际占用的磁盘块很少。du报告实际占用ls -l或df可能报告逻辑大小。数据库文件、虚拟机磁盘镜像常用此技术。通常这不是问题除非你错误地复制了它没有用cp --sparsealways之类的选项导致它被“填实”从而占用巨大空间。Linux的ext4/xfs等现代文件系统碎片化问题不严重一般无需像Windows一样进行磁盘碎片整理。4.4 Systemd Journal 日志膨胀现代Linux发行版多用systemd其日志服务journald的日志存储在/run/log/journal或/var/log/journal。如果配置不当可能无限增长。# 16. 检查 journal 日志大小 sudo journalctl --disk-usage # 清理早于指定时间的日志 sudo journalctl --vacuum-time7d # 保留最近7天 sudo journalctl --vacuum-size500M # 保留最多500M日志 # 或者限制配置文件 /etc/systemd/journald.conf 中的 SystemMaxUse 参数4.5 容器与虚拟化的特殊考量在容器化环境中除了Docker还要注意容器运行时如containerd的存储。有时容器被删除了但对应的存储目录/var/lib/containerd/里的数据没有完全清理。Kubernetes集群中持久卷声明PVC的删除策略如果设置不当也会导致底层存储空间不释放。对于虚拟机如果使用qcow2格式的磁盘即使删除了虚拟机内的文件宿主机上的镜像文件也不会自动缩小。需要使用qemu-img工具进行压缩qemu-img convert -O qcow2 original.qcow2 compressed.qcow2操作前务必关闭虚拟机并备份原镜像。处理/dev/sda1磁盘满的问题本质上是一个系统的排查和运维过程。从快速定位、安全清理到规划扩容和建立预防机制每一步都需要结合对系统架构和业务应用的了解。养成定期检查磁盘空间和关键目录大小的习惯配置好日志轮转和监控告警就能让“磁盘已满”这个经典问题从一场深夜紧急故障变成一个可预测、可管理的日常运维项。