
1. 问题现场当“/dev/sda1”亮起红灯“磁盘空间不足”——这大概是所有Linux系统管理员和开发者最不想看到的警告之一尤其是当它出现在根分区/dev/sda1上时。这个分区通常承载着操作系统、应用程序、用户主目录以及各种系统日志一旦它被塞满轻则导致应用无法写入日志而报错重则引发系统服务崩溃、用户无法登录甚至整个系统陷入不可用状态。我遇到过不少次半夜被报警叫醒登录服务器一看df -h命令的输出里/dev/sda1那一行的Use%赫然显示着100%或者Avail只剩下可怜的几十兆甚至几KB。那种感觉就像家里的下水道彻底堵死了必须立刻、马上疏通。/dev/sda1是一个典型的Linux磁盘分区命名。sd通常指SCSI或SATA接口的磁盘在虚拟机里也常见a表示第一块磁盘1表示第一个分区。所以/dev/sda1往往就是系统安装时创建的第一个主分区在很多默认安装场景下它被挂载在根目录/。因此解决/dev/sda1满的问题本质上就是清理根分区的空间。但清理不是盲目地删除文件你需要像侦探一样先找到“元凶”——到底是哪些文件或目录占用了大量空间以及它们为什么会产生、是否可以被安全清理。在开始动手之前我们必须明确一个核心原则永远不要在生产环境盲目执行rm -rf。你删除的可能是正在被进程打开的关键日志、是应用程序的临时缓存、甚至是系统运行必需的符号链接。错误的删除操作可能导致数据丢失或服务中断。我们的排查思路应该是定位 - 分析 - 确认 - 操作或归档。接下来我将结合多年处理这类问题的经验带你走一遍完整的排查和解决流程。2. 诊断第一步使用正确的工具看清全貌当接到磁盘满的告警时第一步永远是先登录系统获取准确的现状信息。这里最基础也最重要的两个命令就是df和du。2.1 使用df -h确认问题范围和严重程度df(disk free) 命令用于报告文件系统的磁盘空间使用情况。加上-h(human-readable) 参数它会用 K, M, G 这样易读的单位显示大小。df -h执行后你会看到类似下面的输出文件系统 容量 已用 可用 已用% 挂载点 devtmpfs 3.9G 0 3.9G 0% /dev tmpfs 3.9G 0 3.9G 0% /dev/shm tmpfs 3.9G 8.6M 3.9G 1% /run tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup /dev/sda1 50G 48G 379M 100% / /dev/sdb1 200G 45G 156G 23% /data tmpfs 783M 0 783M 0% /run/user/0关键解读找到目标找到挂载点为/的那一行确认其对应的设备确实是/dev/sda1。评估严重性关注可用和已用%两列。如果可用空间只剩几MB或几十MB已用%为 100% 或 99%说明问题已经非常紧急系统可能已经无法创建新文件或写入日志。查看其他分区顺便看看其他分区如/data的使用情况。这有助于你思考是否有数据迁移的可能性例如将/var或/home目录通过符号链接或绑定挂载转移到空间充足的分区但这属于中长期优化方案应急时先聚焦清理。注意有时df显示已用100%但du统计的实际文件大小之和却小于分区容量。这通常是因为文件被删除后其占用的空间并未被释放——文件可能被某个未退出的进程持续打开着。此时需要使用lsof | grep deleted来查找这些“幽灵”文件并重启持有该文件的进程。这是后续高级排查的一部分。2.2 使用du命令进行深度空间分析df告诉了我们“地快淹了”du(disk usage) 命令则能帮我们找到“水是从哪个房间漏出来的”。它用于估算文件和目录的磁盘使用量。基础但强大的命令组合快速定位根目录下的大目录cd / sudo du -sh *-s表示汇总summarize-h表示人性化显示。这条命令会列出根目录下所有一级子目录和文件的总大小。通常/var、/usr、/home是常见的“嫌犯”。逐层深入找到罪魁祸首 假设上面发现/var目录异常巨大比如30G。cd /var sudo du -sh *继续查看/var下的子目录。可能是/var/log日志、/var/lib应用程序数据如Docker、数据库、/var/cache缓存。使用排序功能一眼找到最大的项 手动一层层cd和du效率较低。更高效的方法是结合sort命令sudo du -h --max-depth1 / | sort -hr--max-depth1只统计一级子目录。sort -hr是sort -h -r的合并写法-h表示按人类可读的数字单位K,M,G排序-r表示逆序从大到小。这条命令能立即告诉你根目录下哪个子目录最大。同理在怀疑的目录内也可以这样用sudo du -h --max-depth1 /var | sort -hr sudo du -h --max-depth1 /var/log | sort -hr2.3 可视化工具ncdu的降维打击如果你觉得命令行排序还不够直观或者服务器数量多、想提升效率我强烈推荐使用ncdu(NCurses Disk Usage) 工具。它提供了一个交互式的文本界面可以像使用文件管理器一样浏览目录并直观地看到每个目录的空间占比。安装与使用# 在CentOS/RHEL系系统上 sudo yum install ncdu -y # 在Debian/Ubuntu系系统上 sudo apt-get install ncdu -y # 扫描指定目录例如根目录 sudo ncdu /运行后你会进入一个全屏界面。使用上下箭头选择目录右箭头键进入子目录左箭头返回上级目录。界面顶部会显示当前目录的总大小和扫描进度下方列表按大小降序排列子项占比一目了然。按d键可以直接删除选中的文件或目录会提示确认这比反复执行rm命令要安全直观得多。ncdu在分析复杂、嵌套深的目录结构时优势巨大它能帮你快速跳过那些无关紧要的小目录直击占用空间最大的“元凶”。3. 常见“空间杀手”及其针对性清理策略通过上面的诊断你大概率会锁定几个常见的“疑犯”。下面我针对这些高频目录提供具体的清理策略和注意事项。3.1/var/log—— 日志文件的狂欢与灾难这是最常见的磁盘爆满原因。应用程序、系统服务如journald都会在这里持续写入日志。如果没有配置日志轮转log rotation或轮转策略不合理单个日志文件轻松涨到几十GB。排查与清理查看最大的日志文件sudo ls -lhS /var/log/ | head -20-lhS参数表示以易读格式(-h)、长列表(-l)并按文件大小排序(-S)。head -20显示最大的20个文件。检查系统日志journald 现代Linux系统普遍使用systemd-journald来管理日志。它的日志默认存储在/run/log/journal易失性和/var/log/journal持久性。如果/var/log/journal过大可以清理。查看日志占用的总空间sudo journalctl --disk-usage清理指定时间之前的日志例如保留最近7天的sudo journalctl --vacuum-time7d或者将日志总大小限制在一定范围内例如不超过500Msudo journalctl --vacuum-size500M修改配置文件永久生效编辑/etc/systemd/journald.conf设置SystemMaxUse500M和RuntimeMaxUse100M然后重启服务sudo systemctl restart systemd-journald。清理特定的应用日志对于像nginx、apache的访问日志通常配置了logrotate。你可以手动触发轮转并删除旧日志sudo logrotate -f /etc/logrotate.d/nginx # 强制轮转nginx日志对于没有轮转或轮转失败的大日志文件切勿直接rm。更安全的做法是使用truncate或echo清空文件内容如果确认该日志文件不再被需要sudo truncate -s 0 /var/log/huge_app.log # 或者 sudo echo /var/log/huge_app.log重要警告清空前请确认是否有进程正在写入该日志。如果有清空是安全的进程会继续向文件末尾写入。直接删除文件(rm)会导致进程写入失败因为其持有的文件描述符指向了一个已被删除的inode。查找并清理*.log、*.gz旧的压缩日志等文件# 查找 /var/log 下大于100M的 .log 文件 sudo find /var/log -name *.log -type f -size 100M # 确认后可以批量清空谨慎操作 sudo find /var/log -name *.log -type f -size 100M -exec truncate -s 0 {} \;3.2/var/lib/docker—— Docker的存储“黑洞”如果你在服务器上运行Docker那么/var/lib/docker绝对是重点检查对象。它包含了镜像images、容器containers、卷volumes和构建缓存build cache的所有数据。空间占用分析使用 Docker 自带的命令查看docker system df -v这个命令会详细列出镜像、容器、本地卷和构建缓存的空间使用情况并指出哪些是悬空dangling的即未被任何容器引用的镜像层或卷。常见的清理操作清理所有悬空资源最安全通常能释放不少空间docker system prune -a这个命令会交互式地询问你是否删除所有未使用的镜像、容器、网络和构建缓存。加上-f可以跳过确认。仅清理悬空镜像docker image prune清理所有停止的容器和相关的卷谨慎docker system prune -a --volumes清理构建缓存docker builder prune深入文件系统层面 有时docker system prune显示清理了但df -h显示空间并未释放。这是因为Docker使用的存储驱动如overlay2可能还存在未释放的底层数据块。此时可以尝试重启Docker服务sudo systemctl restart docker重启后存储驱动可能会清理一些内部状态。如果问题依旧可能需要考虑迁移Docker数据目录到更大的磁盘或者使用更高级的工具如docker-gc进行定期清理。实操心得对于长期运行的CI/CD服务器或开发环境一定要为Docker配置日志驱动的大小限制在/etc/docker/daemon.json中设置log-opts的max-size和max-file并建立定期执行docker system prune -f的cron任务否则磁盘被撑满是迟早的事。3.3/tmp,/var/tmp和/var/cache—— 临时文件与缓存的藏身地这些目录用于存放临时文件和应用程序缓存。正常情况下系统重启或应用程序退出时会清理。但如果应用程序异常退出或者缓存机制有问题这里就可能堆积大量垃圾文件。清理策略安全清理/tmp和/var/tmp 这两个目录下的文件如果其最后访问时间atime或修改时间mtime超过一定天数通常可以安全删除。许多系统有定时任务如tmpreaper或systemd-tmpfiles来做这件事但紧急情况下可以手动处理。# 查看 /tmp 下的大文件慎删可能有进程正在使用 sudo find /tmp -type f -size 100M # 删除 /tmp 下超过10天未访问的文件 sudo find /tmp -type f -atime 10 -delete # 删除 /var/tmp 下超过30天的所有内容更激进 sudo find /var/tmp -type f -mtime 30 -delete警告/tmp目录可能被一些进程用作socket文件或PID文件的存放地直接删除可能导致正在运行的服务出问题。最好先lsof查看文件是否被打开。清理包管理器的缓存对于 yum (RHEL/CentOS)sudo yum clean all这会清理/var/cache/yum下的所有软件包头文件和包文件缓存。对于 dnf (Fedora/RHEL8)sudo dnf clean all对于 apt (Debian/Ubuntu)sudo apt-get clean # 删除所有已下载的 .deb 包文件 sudo apt-get autoclean # 删除旧版本的 .deb 包 sudo apt-get autoremove # 删除自动安装且不再需要的依赖包这些操作通常很安全能释放出可观的空间尤其是在频繁安装更新后。3.4 用户主目录/home和/root有时问题出在用户自己的文件上比如开发人员编译生成的大型二进制文件、下载的ISO镜像、测试数据等。排查方法使用du和ncdu扫描/home目录找出占用空间最大的用户目录然后与该用户沟通进行清理。对于/root管理员需要自查是否有大型的备份文件、安装包等遗忘在此。一个常见陷阱/home下的隐藏文件.cache特别是浏览器缓存如Chrome, Firefox在桌面版Linux或长期运行的带图形界面的服务器上可能增长到几个GB。可以指导用户清理其~/.cache目录。4. 高级排查当常规清理无效时如果你用du统计出的所有文件总大小远远小于df显示的已用空间那么很可能遇到了以下情况4.1 被进程占用的已删除文件这是经典问题。一个进程打开了一个大文件比如日志然后这个文件被其他人或日志轮转脚本删除了。在Linux中只要进程不关闭文件描述符磁盘空间就不会被释放尽管文件名已经在文件系统中消失了。排查命令lsof(List Open Files)# 查找已被删除但仍被进程占用的文件 sudo lsof | grep deleted输出会显示进程PID、命令名以及被删除文件的路径标记为(deleted)和大小。解决方案最安全重启持有该文件的进程。例如如果是一个java进程占用了已删除的日志文件重启该Java应用。不中断服务有风险向进程发送信号让其重新打开日志文件。对于许多守护进程如nginx,httpd可以使用kill -USR1 pid或systemctl reload来让其重新加载配置并重新打开日志文件。但这需要你对目标进程的信号处理机制非常了解否则可能导致服务异常。最后手段如果进程不重要可以直接kill -9 pid杀掉它。空间会立即释放。4.2 磁盘索引节点inode耗尽df显示的是块block的使用情况而文件系统还有另一个限制索引节点inode数量。每个文件包括目录、设备文件等都会消耗一个inode。如果创建了大量的小文件例如邮件服务器的队列、Docker容器产生的临时文件即使磁盘空间还有剩余也可能因为inode用尽而无法创建新文件。检查inode使用情况df -i或者df -ih关注/dev/sda1对应的IUse%列。如果达到或接近100%就是inode耗尽。排查inode被谁消耗了# 查找根目录下哪个目录包含的文件数量最多消耗inode最多 sudo find / -xdev -type f | cut -d / -f 2 | sort | uniq -c | sort -rn | head -20这个命令可能较慢。更高效的方法是逐层使用find和wcsudo find /var -type f | wc -l sudo find /home -type f | wc -l ...或者使用专门统计inode的工具# 查看每个一级目录的inode使用数 sudo find / -maxdepth 1 -type d | while read dir; do echo $dir : $(find $dir | wc -l); done | sort -k2 -rn | head -20解决方案找到产生海量小文件的源头通常是某个失控的应用程序或配置错误的日志然后进行清理或修复。单纯删除大文件无法解决inode耗尽问题必须删除大量的小文件。4.3 LVM或虚拟磁盘的“瘦分配”问题如果你使用的是LVM逻辑卷管理或者像VMware这样的虚拟化平台提供的“精简配置”Thin Provisioning磁盘那么df看到的是操作系统内文件系统的大小而物理磁盘的实际占用可能受上层存储管理的影响。有时需要在宿主机或存储层进行“回收”操作。对于LVM可以尝试lvreduce和resize2fs/xfs_growfs来调整文件系统大小操作有风险务必先备份。对于VMware虚拟机可以在客户机内部进行“写零”操作然后在宿主机使用vmkfstools进行压缩。在Linux客户机内可以用dd或cat /dev/zero zero.file; rm zero.file来填充空闲空间为0但注意确保磁盘有足够剩余空间来创建这个临时文件。更安全的方法是使用fstrim命令如果文件系统和虚拟机配置支持TRIM。5. 根治与预防建立长效管理机制应急清理只是治标要治本需要建立监控和预防机制。配置磁盘空间监控告警使用像Zabbix,PrometheusGrafana, 或云平台自带的监控系统对关键分区的使用率设置告警阈值例如 80% 警告 90% 严重。这样可以在问题发生前得到预警。实施合理的日志管理策略配置 logrotate确保所有重要应用日志都配置了logrotate设置合理的轮转周期如每天、保留份数如7-30天和压缩选项。使用 centralized logging考虑使用rsyslog,syslog-ng,Fluentd或Logstash将服务器日志集中收集到专门的日志服务器或Elasticsearch集群中本地只保留短期日志。定期清理计划任务将安全的清理命令写入cron定时任务。例如每周清理一次包管理器缓存、每月清理一次/tmp旧文件、定期执行docker system prune -f。示例在/etc/cron.weekly/下创建脚本cleanup.sh。#!/bin/bash apt-get autoclean -y # 对于Debian/Ubuntu # 或 yum clean all # 对于RHEL/CentOS find /tmp -type f -atime 7 -delete journalctl --vacuum-time7d合理的分区规划在新系统部署时就将/home,/var,/tmp等容易增长的目录单独分区。这样即使其中一个分区满了也不会影响根分区和系统的正常运行。例如给/var单独分配100G给/home分配200G。应用程序配置优化指导开发人员或自行配置应用程序避免在关键分区产生不必要的超大文件。例如调整应用程序的日志级别、设置调试日志的自动清理、将大数据文件输出到专用的数据分区如/data。处理/dev/sda1磁盘满的问题是一个从紧急响应到根因分析再到长期预防的完整运维流程。每一次磁盘告警都是一次检查系统健康状况和运维规范的机会。掌握这套组合拳你就能从容应对这个经典的运维挑战确保服务的稳定运行。记住清理的关键是“胆大心细”——果断定位问题但操作前务必确认影响。