资讯动态

Linux磁盘清理与分区调整:从排查到自动化实践全指南

发布时间:2026/10/14 14:18:26 来源:尧图企业网站定制
磁盘满了这四个字大概是Linux运维生涯里出现频率最高的告警没有之一。不管你是个人桌面用户、自建NAS的爱好者还是正经管几台服务器的运维几乎都经历过那种“明明没装几个东西df -h一看某个分区已经100%”的窒息时刻。这篇文章围绕“linux清理分区”这个话题把我实际排查、清理、调整分区、做自动化的一套完整思路和踩过的坑写下来。适合正在为磁盘空间发愁的人也想给刚接触 Linux 的朋友一套可以直接照做的排查方法。文中会涉及诊断命令、常见垃圾文件藏身处、分区调整的正确姿势、自动化清理脚本以及几个非常容易翻车的细节。1. 动手前的体检先搞清楚空间究竟被谁吃了1.1 别凭感觉删东西先用 df 看文件系统全局很多人一遇到磁盘满就急着卸载软件包但真正吃空间的大头往往是数据、日志、快照而不是你装的那几个应用。所以第一步永远是看全局文件系统级别的用量而不是应用程序级别的用量。我习惯先用这条命令df -hT-T会顺带显示文件系统类型-h是人性化单位。输出里你会看到类似/dev/mapper/centos-root、/dev/sda1这种设备路径以及它们的挂载点、容量、已用、可用、使用率。如果使用率到了90%以上就是一个危险信号需要立刻进入排查环节。另外务必看一眼 inode 情况df -iinode 是文件系统管理文件的索引节点它和空间是两个维度。有时候你df -h看还有好几个 G但写入文件却提示No space left on device问题就出在 inode 耗尽了——也就是小文件数量太多把索引占满了。我在后面“常见问题”章节会专门讲这个但体检阶段先扫一眼心里有个底。提示df -hT看到的是文件系统的“分配量”而不是物理磁盘的“容量”。如果是 LVM 逻辑卷实际物理磁盘可能还有剩余空间没分配出去这一点后面调整分区时要用到。1.2 用 du 和 ncdu 快速锁定重量级目录知道了哪个分区满了下一步就是揪出里面的“大块头”。我的标准命令是这个sudo du -xh --max-depth1 -sh /var /usr /home /opt /tmp /root 2/dev/null这里有几个容易被忽略的参数细节-x不跨文件系统。意思是只统计当前分区内的内容避免把挂载在某个目录下的其他分区数据也算进来导致误判。--max-depth1只看一层子目录避免输出刷屏。-s每个目录只给汇总值。2/dev/null把权限报错丢掉不然一堆Permission denied噪音很烦人。如果还想更直观我强烈推荐ncdu一个终端里的图形化磁盘分析工具sudo ncdu -x /它会先扫描一遍然后进入交互界面按目录大小从大到小排列你可以用方向键上下浏览、回车进入子目录、d键删除选中项。相比du的纯文本输出ncdu在人工判断“哪些目录值得深挖”时效率高很多。大部分发行版的软件源里都有这个包apt install ncdu或yum install ncdu就能装。我之前处理过一台某公司的应用服务器根分区 100% 报警ssh 都有点卡。用df -hT确定是根分区满了然后du -xh --max-depth1扫了一遍/var占了 18G/usr占 6G/home才 1G。再进/var下一层发现/var/log一个目录就 15G全是被某个 Java 应用刷出来的业务日志。整个定位过程不到两分钟比凭感觉翻目录省太多时间。1.3 分清楚三件事物理磁盘、逻辑分区、文件系统排查之前最好建立三个概念不然后面调整分区时会懵物理磁盘就是机器里的那块硬盘系统里叫/dev/sda、/dev/nvme0n1之类的块设备。分区或逻辑卷物理盘上划分出来的逻辑空间比如/dev/sda1或者 LVM 里的逻辑卷/dev/mapper/vg-root。文件系统在分区之上建立的存储结构ext4、xfs、btrfs 都属于这一类必须挂载到某个目录才能用。清理文件是腾出已分区空间里的空闲容量调整分区是把空间从一个分区挪到另一个分区。这是两种完全不同的“手术”难度和风险差异很大。在动手之前先明确你到底需要做哪一种如果某个目录堆满了日志、缓存该做的是“清理文件”不需要动分区结构。如果整个分区布局不合理比如根分区只有 20G 而/home有 200G想给根分区腾点地方这才需要考虑“调整分区”。千万不要在没搞清楚现状之前就拿着fdisk对着磁盘乱敲那是玩家暴毙最快的方式。2. 空间大户逐个数这些地方最容易藏腐烂粮食2.1 系统日志和 journald 是最常见的第一嫌疑人日志文件是第一大嫌疑对象尤其是长期运行的服务器。以前老派 Linux 的日志都写在/var/log/下syslog、messages、secure这些文件配合logrotate做轮转。但现在的 systemd 系统里大多数日志都通过journald统一管理了存放在/var/log/journal/目录下用journalctl命令查看。先看日志占了多大journalctl --disk-usage我见过跑了一个月没动过的机器光 journal 日志就有 8G。清理方式不是直接去rm /var/log/journal/这会导致 journal 丢失无法追溯排障记录而是让 journald 自己控制上限journalctl --vacuum-size200M journalctl --vacuum-time7d前者把日志压缩保留到 200M 以内后者只保留最近 7 天。但这两条命令是一次性的下次日志增长还是会占满。更一劳永逸的做法是修改/etc/systemd/journald.confSystemMaxUse500M MaxRetentionSec14d改完执行systemctl restart systemd-journald生效。这里有个经验别把SystemMaxUse设得太小比如 50M否则排障时历史上的关键日志早就没了问题出现时根本找不到线索。500M 到 1G 是服务端比较合理的区间纯桌面机可以再小一点。2.2 包管理器缓存和旧内核删起来很爽但要注意留后路Debian/Ubuntu 系的apt会把下载的 deb 包缓存在/var/cache/apt/archives/CentOS/RHEL 系的yum缓存则在/var/cache/yum/。清理方式# apt apt clean # yum yum clean all这条命令很安全只是删掉已下载的软件包缓存不影响已安装的程序。真正容易忽略的是旧内核。内核包每次升级都会在/boot写入新内核镜像在/lib/modules留下对应的模块文件。时间一长三四个旧内核留在磁盘上每个几百 M累积起来非常可观。我碰到过一个真实的例子某台机器/boot分区只有 500M升级了三次内核之后直接满了导致新的内核包根本装不上。清理旧内核的正确姿势是先看当前在用的内核版本uname -r dpkg --list | grep linux-image # Debian/Ubuntu rpm -qa | grep kernel # CentOS/RHEL原则是保留当前内核和上一个版本再往前的可以删。Debian 系用apt purge linux-image-xxx手动删除旧内核或者用apt autoremove --purge自动清理RHEL 系默认yum会保留最近几个。注意不要手滑把正在运行的内核删了虽然理论上可以继续运行但重启就起不来了删除前务必对照uname -r。2.3 Docker 和容器存储镜像叠加层的空间黑洞只要机器上跑过 Docker/var/lib/docker/就是一个不可忽视的存储大户。Docker 镜像采用分层存储每次构建、拉取都会产生新的层容器如果一直没删除它的可写层也会占用空间悬空镜像dangling images更是只增不减的垃圾。排查步骤docker system df这个命令会分别显示镜像、容器、卷、构建缓存各自占用的空间以及有多少悬空对象。清理方式docker system pruneprune会删除所有已停止的容器、所有未被使用没有被容器引用的网络、所有悬空镜像、构建缓存。如果想让空间回收得更彻底用docker system prune -a --volumes-a会连未被任何容器引用的镜像一起删除--volumes会删除没有被容器使用的匿名卷。我用-a --volumes之前会特别谨慎因为如果有卷里的数据没有挂载到宿主机删了就真没了。生产环境建议先逐项确认或者用docker system df -v详细列出哪些镜像和卷还在被引用再决定清到什么程度。容器时代还有个隐藏大户是容器日志。默认情况下Docker 容器写在/var/lib/docker/containers/下的 JSON 日志文件是无限增长的不设上限的话一个跑了两周的应用容器能吃掉几十 G。现在我经手的机器都会在/etc/docker/daemon.json里加这么一段{ log-driver: json-file, log-opts: { max-size: 50m, max-file: 5 } }效果是单个容器日志文件最大 50M最多保留 5 个写满就自动轮转。改完配置重启 Docker 后新容器默认生效已经创建的容器需要重建才生效但至少不会继续无限涨了。2.4 数据库、备份和临时文件把“安全等级”分清楚除了系统本身业务数据目录也经常爆雷。MySQL 的 binlog二进制日志、/tmp下残留的临时文件、手工备份的 tar 包、甚至 Home 目录下的缓存~/.cache、~/.npm、~/.local/share/Trash都可能填满分区。“哪些能删、哪些不能删”我给自己列了一张安全等级表分享出来位置典型内容清理命令风险等级/var/cache/apt/archivesapt 下载的 deb 包apt clean低安全/var/log/journalsystemd 日志journalctl --vacuum-size200M低可追溯性略降/var/lib/docker镜像层、容器层docker system prune中确认无引用再删/var/lib/mysqlbinlog、慢日志PURGE BINARY LOGS/ 手动删旧 binlog高操作前必须确认/tmp、/var/tmp程序临时文件手工清理可确认的残留项中正在运行的程序可能还在用~/Trash、~/.cache回收站、用户缓存rm -rf ~/.local/share/Trash/*低/var/backups备份文件保留最新删历史旧包中看备份策略关于 MySQL binlog 有一句一定要说直接rmbinlog 文件是错误操作MySQL 会在自己的记录里找不到文件而出问题。正确做法是登录 MySQL 后用PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;这类 SQL 清理。处理任何“业务应用”产生的文件前最优策略永远是先搜索一下对应应用的官方文档确认它的清理机制再动手。我早期删 MySQL binlog 时直接rm结果数据库起不来那次教训印象极深。3. 分区层操作当清理完垃圾还不够时的正确姿势3.1 先确认你的分区布局LVM 还是传统分区如果清理完垃圾发现根本问题在于分区初始分配不合理就要考虑调整分区大小。但这一步之前必须分清你的磁盘是 LVM 逻辑卷管理还是传统分区表直接挂载。怎么看两条命令lsblk pvdisplay / vgdisplay / lvdisplaylsblk会显示块设备树如果看到/dev/mapper/vg名称-lv名称说明是 LVM。pvdisplay看物理卷、vgdisplay看卷组、lvdisplay看逻辑卷这三个命令是 LVM 调整的必看信息。如果看到的是/dev/sda1、/dev/nvme0n1p2直接挂着文件系统就属于传统分区。这个区别决定了你能用哪些工具LVM 可以在线扩容、在线缩容部分文件系统支持灵活度极高。传统分区扩容相对容易前提是后面有连续空闲空间缩容就非常麻烦而且风险更大。3.2 LVM 在线扩容三步走顺序不能乱LVM 最爽的地方就是可以在不影响服务的情况下扩容。假设根分区/dev/mapper/vg-root不够用了卷组里还有空闲的物理空间vgdisplay里Free PE / Size那一项不为零那么流程是扩容逻辑卷lvextend -L 20G /dev/mapper/vg-root扩容文件系统resize2fs /dev/mapper/vg-root如果文件系统是 xfs第二步要用xfs_growfs /注意 xfs 只需要指定挂载点不需要指定设备路径。先扩逻辑卷再扩文件系统这个顺序不能反。因为文件系统是搭建在逻辑卷之上的逻辑卷是它的容器容器变大了才能让里面的文件系统也跟着变大。如果卷组本身没有空闲空间但物理磁盘还有未分配区域就得先扩展物理卷# 假设新磁盘块设备是 /dev/sdb先把整块盘变成物理卷 pvcreate /dev/sdb # 把物理卷加入卷组 vgextend vg名称 /dev/sdb然后再走lvextend和resize2fs。这套操作全程在线不需要停机是生产环境最常用到的扩容方案。3.3 LVM 缩减分区高危操作顺序反了就是数据灾难缩容比扩容危险得多。打个比方扩容是往房子里加面积缩容是拆墙。拆错了墙整个房子塌了。LVM 缩容的正确顺序和扩容正好相反先把文件系统缩小再把逻辑卷缩小。中间顺序一颠倒文件系统的元数据就可能被覆盖数据直接损坏。以 ext4 文件系统为例把/dev/mapper/vg-home从 100G 缩到 60G首先务必备份重要数据。缩容是有风险的操作任何情况都有可能发生数据无价。检查文件系统完整性e2fsck -f /dev/mapper/vg-home-f是强制检查即使文件系统看起来干净也要强制走一遍否则resize2fs可能拒绝缩容。缩小文件系统到目标大小如果最终逻辑卷计划是 60G文件系统要比它稍小一点比如缩到 59G留余量resize2fs /dev/mapper/vg-home 59G缩小逻辑卷lvreduce -L 60G /dev/mapper/vg-home注意三个细节缩容前目标分区不能再被使用最好umount卸载。如果必须在线缩ext4 支持在线缩容但我个人强烈不建议在生产环境这么做一次失误的代价太大了。顺序是“文件系统先小逻辑卷后小”。反了的话逻辑卷变小了文件系统的元数据还留在被砍掉的那段空间里直接损坏。xfs 文件系统不支持缩容这一点必须刻在脑子里。xfs 只能扩不能缩。如果机器当初用 xfs 做了/home想给它缩容基本只能备份数据、重新格式化、再恢复数据没有在线缩容这个选项。3.4 传统分区非 LVM的尴尬扩容容易缩容难传统分区表的机器比如/dev/sda2挂载/想调整大小取决于分区的物理位置。如果目标分区的磁盘介质上后面正好跟着一块“未分配”的空闲区域那么可以扩展# 使用 parted 非交互式扩展最后一个分区 parted /dev/sda resizepart 2 100% resize2fs /dev/sda2如果空闲空间不在目标分区后面而是在它前面或者中间夹着别的分区那就麻烦了。传统 MBR/GPT 分区表不支持“把分区 A 中间的空间挪给分区 B”这种操作。你能做的通常是把后面的分区删掉、重建更小的分区、多出来的空间扩展给前面的分区整个过程会涉及数据备份和恢复。我处理过一个很典型的场景某台机器根分区只有 20G后面跟着 500G 的/data分区但业务中/上的程序日志涨得太快。由于是传统分区无法在线缩/data最终方案是备份/data数据删掉它对应的分区用释放的空间扩展根分区再从剩余空间重建/data最后恢复数据。整个过程很痛苦而且需要从外部启动盘引导因为根分区在线的状态下不能删除 / 后面的分区。这种情形下图形化的 GParted Live 启动盘是救命的。它能在系统未运行的状态下提供一个带 GUI 的分区调整环境能识别 ext4、xfs、甚至 LVM 的结构用鼠标拖拽分区大小自动处理依赖关系。但即便有图形界面传统分区的缩容仍然遵循一条铁律目标分区的数据量必须小于缩容后的目标大小否则神仙也救不了。3.5 别忘了 swap 分区它也占着一块地方Swap 分区虽然平时不显眼但如果磁盘空间紧张可以看看free -h的输出swap 占用的大小也是真实磁盘空间。有些服务器初始分配了 8G 甚至 16G 的 swap但实际根本用不了那么多这时可以考虑缩减 swap 给其他分区腾空间。操作步骤以 LVM 下 swap 逻辑卷为例确认 swap 没有在使用free -h关闭 swapswapoff /dev/mapper/vg-swap删除或缩小 swap 逻辑卷# 如果是删除 lvremove /dev/mapper/vg-swap # 如果是缩到 4G lvreduce -L 4G /dev/mapper/vg-swap mkswap /dev/mapper/vg-swap重新启用swapon /dev/mapper/vg-swap注意一点swapoff之前要确认系统内存余量足够内存已经吃紧的机器强行关闭 swap 可能导致 OOM。操作前用free -h看一眼剩余内存比如剩余内存明显大于 swap 使用量再执行。4. 从手动到自动把这些清理变成长期习惯4.1 先固化一张清理清单流程化是防呆的关键手动清理做一次不难难的是每次磁盘告警都要临时想“该删哪里”。我的做法是先把常用清理项固化成一张操作清单贴在运维手册里或者直接变成脚本。清单长这样检查项检查/清理命令建议频率根分区整体用量df -hT /每日journal 日志journalctl --disk-usage每周Docker 悬空资源docker system df每周apt/yum 缓存apt clean/yum clean all每月旧内核dpkg --list | grep linux-image每次内核升级后大文件遗留find /var -type f -size 500M每月备份陈旧包查看/backup、/var/backups按备份策略有了清单自动化就顺理成章了。4.2 自动化第一步journald 和 logrotate 的默认配置很多空间问题其实是“配置问题”不是“人工清理问题”。journald 和 logrotate 就是两个最典型的自动清理机制。journald 上面已经提过/etc/systemd/journald.conf里的SystemMaxUse直接限制日志总大小。改完后它会自动过期清理根本不需要你操心。logrotate 则是传统日志轮转工具很多应用nginx、mysql、systemd 自身的某些日志都用它来管理日志文件。默认配置通常在/etc/logrotate.conf和/etc/logrotate.d/下。一个规范配置示例/var/log/myapp/*.log { daily rotate 7 compress delaycompress missingok notifempty create 0640 root root }含义是每天轮转一次保留最近 7 份旧文件压缩压缩延迟一周执行。这套配置写好后系统 cron 会定期自动执行logrotate不需要额外安排任务。4.3 自动化第二步写一个磁盘空间巡检脚本我自己的习惯是会写一个脚本挂在 systemd timer 或 cron 上每天跑一次做一个简单的“磁盘空间健康检查”。脚本逻辑不复杂核心是两点检测df的使用率、超阈值时发提醒。一个简化但实用的版本#!/usr/bin/env bash # 磁盘空间巡检根分区使用率超过 85% 时输出告警 THRESHOLD85 DF_OUTPUT$(df -h / | awk NR2 {print $5} | tr -d %) if [ $DF_OUTPUT -gt $THRESHOLD ]; then echo [$(date %Y-%m-%d %H:%M:%S)] WARN: root partition usage: ${DF_OUTPUT}% ${THRESHOLD}% /var/log/disk_check.log # 这里可以扩展为邮件告警或 webhook 通知 fi配合 cron 每天 8 点执行0 8 * * * /usr/local/bin/disk_check.sh有些朋友会直接把清理动作也写进自动化脚本里我的建议是“提醒自动化清理半自动化”。因为清理动作涉及内部业务数据不同机器的容忍度不同与其让脚本盲删不如在脚本里输出详细的清理建议哪个目录爆了、哪类文件占用最高让人来决策。只有那些绝对安全的缓存类清理比如journalctl --vacuum-size500M我才会放进 cron 里每天自动执行。4.4 别让自动清理变成自动误删给脚本加三道护栏自动清理脚本最容易翻车的地方就是“误删”。我见过有同事写了个定时清理脚本正则表达式没写好直接把业务日志目录整个删了恢复数据花了两个通宵。为了避免这种事故脚本设计上务必加三道护栏只处理明确标识的缓存目录绝不遍历扫描整个分区然后无差别删除。比如只处理/var/cache/apt、/tmp下超过 30 天且文件名模式明确的文件find /tmp -type f -mtime 30 -name *.tmp -delete。删除前先记录日志至少能追溯。脚本里每删一个文件前先echo到操作日志里。重要目录绝不自动删。业务日志、数据库文件、备份文件都不在自动清理范围内这些只做告警不碰数据。这三条守住自动化才不是定时炸弹。5. 实战问题速查那些“删了空间却没释放”的坑5.1 文件删了但 df 空间没变八成有进程还握着它这是 Linux 下最经典的磁盘问题你rm了一个 10G 的日志文件df -h一看可用空间一分没少。原因是你删掉的文件被某个进程打开了文件系统里看不到这个文件了但进程的文件描述符还在引用它磁盘空间就这么被“活死人”占着。排查方式lsof L1L1表示只列出 link count 为 0 且仍然被打开的文件。输出里能看到是哪个进程、删掉的是哪个文件。解决办法就是重启对应进程systemctl restart 相关服务名重启之后文件描述符释放空间自然就回来了。遇到这种情况别反复rm没用的先把占用进程找到并处理掉。5.2 df 显示 100% 但 du 统计下来却很少先别急着扩容du统计的是文件系统里可枚举的文件大小总和df统计的是整个文件系统的块使用量。两者对不上是正常的差额来自几个地方文件系统元数据、系统保留块、已经被删除但被进程占用的空间以及挂载点遮蔽某个目录本身有文件但下面又挂了个分区du统计时可能漏掉上层内容。经验判断顺序先跑一次lsof L1看有没有大量被删但未释放的文件。如果是 ext 文件系统df -h的使用率和物理实际是有差别的默认会有 5% 的系统保留空间给 root 使用df里看不到这部分。再检查是不是有子目录挂载了另一个分区之前提到的du -x参数就是为了避开这种统计陷阱。综合排查后如果确认文件系统层没有异常再考虑是否需要扩容分区。5.3 根分区满了但根分区不能卸载怎么调整分区根分区是系统的命根子在线状态下不能卸载但又需要调整它的大小——这是运维里最棘手的情景之一。解决方案基本上只有一个方向脱离系统本身用外部环境操作硬盘。常见的做法制作一个 GParted Live 启动 U 盘从 U 盘引导系统进入图形化分区工具此时系统的根分区处于未挂载状态可以安全调整。如果机器在虚拟化平台也可以挂载一个救援系统某些发行版安装镜像本身就带救援模式来操作。但要注意不管是 GParted 还是救援模式调整根分区大小时如果磁盘是传统分区表而根分区又在其他分区之后能否扩容取决于后面是否有空闲空间以及引导加载器的位置。很多时候这种调整会让 GRUB 找不到引导文件需要进 shell 手动重建引导配置这不是新手能轻易驾驭的操作。建议没有十足把握时优先考虑备份 重装 恢复的方式。5.4 “No space left on device”但 df 显示还有空间inode 耗尽了这个报错有一个很经典的误导场景写入文件时报错但你df -h一看磁盘还有好几个 G 可用。真相多半是 inode 用完了。处理方式df -i看看哪个分区IUse%接近 100%。inode 耗尽的常见原因是某个目录里堆积了大量小文件比如邮件队列、缓存碎片、临时文件。解决思路是清掉这些海量小文件或者如果业务确实需要海量小文件就只能重建文件系统时调大-i的比率参数如mkfs.ext4 -i 16384每 16KB 分配一个 inode。清理大量小文件时有个坑rm -rf 目录不如find 目录 -type f -delete高效。前者要先遍历目录树后者直接按文件逐个删省掉大量目录项操作实测下来速度能差好几倍。5.5 分区调整途中断电或报错别慌先 fsck分区调整最怕中途断电可能导致文件系统元数据不一致。遇到这种情况第一反应先别继续做任何操作进入救援模式然后对受影响的文件系统执行完整性检查e2fsck -f /dev/对应分区如果检查过程中出现交互式询问不要盲目一路y下去。e2fsck的每个修复选项都对应不同的元数据错误一路确认可能把一些不确定的节点也修掉了反而造成更多损失。稳妥起见检查之前先尽量备份留底或者至少在检查工具的 “read-only” 模式下先做一次检测看清问题规模和类型。5.6 一张速查表常见现象、判断命令、解决办法最后把常见问题汇总成一张速查表运维时可以直接翻现象判断命令解决思路分区使用率 100%df -hT按第 2 章清单逐项清理删了文件空间没变lsof L1找到进程并重启df 高但 du 低df -i、lsof L1检查 inode、进程占用、保留块写入报错但有空间df -i清理小文件或重建文件系统xfs 想缩容xfs_growfs只能扩备份、重建、恢复报错后起不来fsck救援模式修复先只读检测日志无限增长journalctl --disk-usage配置SystemMaxUse、logrotate这些坑我基本都踩过一轮。尤其是“删了文件空间没释放”那次当时还是新手反复df -h看了好几遍还怀疑自己是不是删错地方了最后才想到是被进程占用。后来养成了习惯空间告警来了先跑lsof L1再跑du定位大目录这已经成为条件反射。最后再分享一个小技巧。临时抢空间时/var/log里的*.gz压缩轮转日志是最安全的一批删除对象但我的做法不是删掉它们而是用gzip再压一遍或者只删一个月的旧档。这么做的原因很简单日志这东西惹祸的时候才想起来要它翻旧账如果发现日志早被手动删光了那时候才是最尴尬的。清理空间永远是个“留一手比清干净更安全”的活。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑