根分区空间告急?从排查到扩容的完整实战指南
2026/9/24 22:06:09 网站建设 项目流程

1. 为什么你的根分区说满就满:先搞清楚空间到底被谁吃了

做运维这些年,隔三差五就能收到“根分区使用率 98%”的告警,一开始还会紧张一下,后来发现这几乎是每台服务器走向稳定的必经之路。很多人第一反应是加磁盘、扩分区,但说实话,如果不先搞清楚空间是被谁占掉的,扩完还是会满。根目录不是一瞬间爆掉的,它的使用率通常是在日志堆积、软件缓存、临时文件这些地方一点点被蚕食的。

先看几个最常见的高危目录,你ssh上去之后可以先按这个顺序检查:

  • /var/log:服务日志、系统日志、nginx/access.log、mysql 慢查询,这些文件正常情况下会按天切割,但一旦某个服务疯狂写错误日志,几天就能把磁盘塞满。我见过最夸张的一次,一个 Java 应用因为死循环打异常堆栈,两天写了 120GB 日志。
  • /tmp:很多程序会把临时文件往这里丢,比如解压中的 tar 包、上传中的临时分片、sort 命令的中间文件。程序异常退出后,这些临时文件不会被自动清理。
  • /var/cache:apt/yum 的软件包缓存,升级过几次系统后,这个目录能到几个 GB 甚至十几个 GB。还有 pip、npm 的缓存目录,虽然默认路径在用户家目录下,但 root 用户的也在 /root 下面。
  • /var/lib/docker:如果你跑 Docker,这个目录是重灾区。overlay2 层、悬空镜像、构建缓存,都是按 GB 计算的空间占用。
  • /usr/opt:有些部署脚本把 JDK、中间件、数据库数据直接放根分区,而不是单独挂数据盘,这是非常常见的“规划欠债”。
  • /root:用户家目录里不要小看,.cache.local.npm.conda这些隐藏目录,日积月累也不小。

那排查命令怎么用?我的习惯是三层递进:

先看整体格局,执行df -hT看每个挂载点的使用率和文件系统类型,重点盯“/”那一行的 Use% 和 Mounted on。

再看块设备分布,执行lsblklsblk -f,确认磁盘是怎么分区的、有没有 LVM、物理卷大小是多少。这一步决定你后面能走哪条扩容路线。

最后定位大文件,执行du -sh /*先把根目录下一级目录的占用列出来,找到大目录再一层层往下钻。这一步有个效率技巧:直接cd /然后再敲du -sh *还是慢?用ncdu这个工具会更直观,它可以交互式浏览目录树,按大小排序,还能直接删除垃圾文件,几秒钟就能定位到“罪魁祸首”。

如果是应急止血,先别急着扩容,把下面这几类东西清一清:

  • journald 日志:执行journalctl --vacuum-size=200M,把 systemd 日志限制在 200MB 内。这个命令比直接删文件安全,它会自动处理正在写入的日志文件。
  • apt/yum 缓存:Ubuntu 执行apt-get clean,CentOS 执行yum clean all,能释放不少空间。
  • Docker 悬空镜像:docker system prune,会清理不再使用的镜像层、容器、网络和构建缓存。注意它默认不会删正在使用的镜像,相对安全。
  • core dump 文件:find / -type f -name "core.*" -size +100M 2>/dev/null找出来直接删掉。
  • 旧的系统内核:uname -r看当前内核版本,再用dpkg --list | grep linux-image(Debian/Ubuntu)或rpm -qa | grep kernel(CentOS)列出所有内核,把旧的删掉。Ubuntu 可以使用apt-get autoremove --purge自动清理旧内核。

这些清理动作频繁做几次,你大概就能总结出自己服务器上“谁在稳定吃空间”。到了这一步,你才有资格去谈扩容——因为扩容只是在给系统“续命”,如果垃圾的源头不堵住,扩容后的空间一样会被吞掉。

2. 扩容前的“体检”:分清你是哪种磁盘布局,选错方案会出大事

不同机器根目录扩容的思路完全不一样,不是一句“执行 resize2fs”就能搞定的。动手之前,至少要确认三件事:磁盘类型是传统 MBR 还是 GPT、根分区所在磁盘上有没有空闲空间、以及核心的——文件系统是 ext4 还是 xfs。

2.1 先认清楚三种常见布局

第一种是传统分区直挂,也就是/dev/sda1直接挂载到/。这种布局下如果想要在线扩容,前提是分区后面还有未分配的空间,或者你能腾出空间来。如果是虚拟机,可以直接调大虚拟磁盘;如果空间已经全部分配完了,那就比较麻烦,需要借助空闲分区或者重建分区表。

第二种是 LVM 逻辑卷管理,/dev/mapper/centos-root挂载到/。这是大多数 CentOS/RHEL 服务器默认的安装方式。LVM 的好处是可以在不影响数据的情况下,把新加入的物理卷空间划给逻辑卷,这就是大多数人说的“扩容”的真正操作对象。国产主流 Linux 发行版和 Ubuntu Server 的默认安装,也大多会把系统根分区放到 LVM 里,区别只是卷组名和逻辑卷名不同。

第三种是云盘直挂,云服务器厂商(比如阿里云、腾讯云、华为云)的控制台操作了“在线扩容”之后,磁盘块设备本身已经有了更大容量,但在系统里还没生效,需要你执行 growpart 或 fdisk 去调整分区表,再扩展文件系统。这种情况不涉及新磁盘,也不需要 LVM,属于“物理盘变大,系统分区还没跟上”。

判断自己属于哪一种,一条命令就能解决:

lsblk

输出里如果看到vda1sda1这类直接挂根目录的,就是传统分区;如果看到类似vg-rootvg-lv_rootubuntu--vg-ubuntu--lv这种带逻辑卷名称的,就是 LVM;如果只有vda1但你在云控制台已经执行过扩容,那就是云盘场景。

2.2 确认文件系统类型:ext4 和 xfs 的扩容命令完全不同

文件系统类型决定扩容的最后一步用什么命令,这一步出错会导致数据丢失,所以绝对不能跳过。

df -hT /

输出结果的第二列会显示文件系统类型:

  • 如果是ext4,最后一步执行resize2fs /dev/xxx,可以无损扩展,而且支持在线扩容。
  • 如果是xfs,最后一步执行xfs_growfs /,注意这个命令的参数是一个挂载点,而不是设备路径,而且 xfs 只能扩大不能缩小。也就是说,如果某个 xfs 分区空间规划过头了,你想把它缩小,那基本只能备份重来。
  • 如果你看到是 btrfs,情况又不一样,它自带子卷功能,一般很少通过传统分区方式去扩容,这里不展开讲。

分类讨论完之后,还有一条铁律:无论哪种情况,扩容前先确认有没有空闲空间。用fdisk -l /dev/sdaparted /dev/sda print free查看分区表,看分区后面还有没有未分配的空间。如果没有,那你就别急着动 resize,而是先想办法扩大磁盘本身(虚拟机加盘、云盘扩容),或者考虑挂载新磁盘。

注意:不要在根分区正在满负荷读写、数据库正在高峰期的时候做扩容操作。虽然 LVM 和 resize2fs 都支持在线操作,但文件系统层面的元数据变更,任何一次意外断电都可能导致数据不一致。生产环境强烈建议先做快照,或者至少选择业务低峰期操作。

2.3 我说过很多次的“扩容三不”

第一,不要直接删掉一个分区再重建,哪怕你觉得那个分区没用。分区表操作一旦失误,数据直接找不回来。第二,不要在根分区上执行mkfs,那等于格式化,我见过太多新手把/dev/sda1/dev/vda1敲反,结果整个系统起不来。第三,不要迷信网上的“一键扩容脚本”,跟自己当前系统内核、文件系统版本、分区表格式都对不上,容易翻车。

3. 虚拟机场景扩容:从虚拟磁盘到文件系统的完整链路

虚拟机和云服务器的扩容操作有相似之处,也有明显的差异。这里我以 KVM/libvirt 虚拟机和 VirtualBox 为例,把从“虚拟磁盘变大”到“系统内生效”的全链路走一遍。

3.1 给虚拟磁盘增加容量:两种常用方式

KVM 的磁盘文件常见格式是 qcow2,可以离线扩容。先关机(必须关机),然后在宿主机上执行:

qemu-img resize /var/lib/libvirt/images/your-disk.qcow2 +50G

这个命令就是把虚拟磁盘镜像的容量增加 50G。操作结束后,你用qemu-img info /var/lib/libvirt/images/your-disk.qcow2可以看到虚拟磁盘容量已经变大了。qcow2 是稀疏存储的,扩容后宿主机的物理磁盘不会立刻被占满 50G,只有虚拟机里真正写入数据才会逐步占用,这点不用担心。

VirtualBox 的命令则是:

VBoxManage modifymedium disk "/path/to/your-disk.vdi" --resize 120000

注意这个参数单位是 MB,--resize 120000表示把磁盘调整到 120GB。如果虚拟机里已经用了 80GB,想扩到 100GB,那就填 100000 而不是 20000。填错了只会让你多出很多未分配空间,不会损坏数据,但最好还是算清楚。

还有一种更“物理”的方式:直接给虚拟机增加一块新虚拟磁盘。这种方式不需要改原盘的镜像文件,启动之后按新磁盘来挂载、初始化。如果你的目的是给/扩容,那要按“新磁盘加入 LVM 卷组”的路线操作,后面会说。

3.2 开机后识别新空间

磁盘镜像扩容完成后,启动虚拟机,在系统里执行lsblk,你会发现磁盘设备(如/dev/vda)显示的总容量已经变大,但分区(如/dev/vda1)还保持原来的大小。这时操作系统已经看到了“大磁盘”,但分区表和文件系统还没有跟上。

这一步非常关键:分区表操作前,建议先备份分区表信息:

sfdisk -d /dev/vda > /root/partition-table-backup.txt

保存这份备份主要是为了出问题时能快速恢复分区布局。然后检查分区表类型:

fdisk -l /dev/vda

如果输出里看到 “Disk label type: gpt”,说明是 GPT 分区表,扩容时优先用growpart自动处理,比手工用 fdisk 删了重建要安全得多。如果是 “dos”,那就是经典的 MBR 分区表,也可以用 growpart 处理。

3.3 分区扩展:growpart 的最佳实践

growpart 是一个专门用来扩展分区大小的工具,它比手动画分区表更安全,因为它会保留原有分区的起始位置不变,只扩展结束位置,数据不移动、不出错。

yum install -y cloud-utils-growpart # 或 apt-get install -y cloud-guest-utils

安装完成后,确认根分区所在磁盘和分区号。比如根分区是/dev/vda1,那命令就是:

growpart /dev/vda 1

注意这里不是写/dev/vda1,而是写成磁盘设备加空格加分区号。执行成功后,再看lsblkvda1的大小已经延伸到磁盘末尾了。

有些老版本内核或者云镜像系统里没有 growpart,此时可以手动用 parted 处理:

parted /dev/vda print free resizepart 1 100% quit

这个操作同样只调整分区终点,不触碰分区起点。执行之后立刻同步分区表:

partprobe /dev/vda

注意:有些虚拟机磁盘驱动(比如 virtio-blk)支持直接在线重新读取分区表,但如果是老型号的 IDE 或 SATA 控制器,partprobe可能不生效,会提示 “Re-reading the partition table failed”。这种只能重启虚拟机,没有别的安全办法。重启前确保把扩容命令准备好,开机后在第一时间把文件系统扩展命令执行掉。

3.4 最后一步:扩展文件系统,区分 ext4 和 xfs

分区变大之后,文件系统还停留在原来的大小,不扩展的话,df -h看到的使用率不会有任何变化。继续执行文件系统扩展命令:

ext4 文件系统:

resize2fs /dev/vda1

xfs 文件系统:

xfs_growfs /

两个命令的区别要记住:resize2fs 针对的是设备路径,你在/etc/fstab里怎么写就填哪个设备;xfs_growfs 针对的是挂载点,直接写/就行,它会自动找到对应的设备。执行完,用df -hT /验证,根分区容量已经变大。

如果你是用 LVM 装系统的虚拟机,那上面的操作前半段是一样的——先扩大虚拟磁盘,再 growpart 扩展分区。但后半段要对准逻辑卷来操作:

pvresize /dev/vda1 lvextend -l +100%FREE /dev/mapper/centos-root resize2fs /dev/mapper/centos-root # 如果是 xfs: # xfs_growfs /

这套命令顺序不能乱:先让物理卷识别新空间,再把空闲空间全部划给逻辑卷,最后扩展文件系统。我见过有人先 lvextend 再 pvresize,结果 lvextend 提示没有足够空闲空间,然后又回头折腾 pvresize,虽然最终能补回来,但白白绕了一圈。

4. 云服务器在线扩容:控制台点完按钮,系统内还要做这几步

云服务器的扩容走的是另一条路线,因为云盘的控制权在厂商控制台里,不在你的系统里。阿里云、腾讯云、华为云虽然界面不同,但逻辑都一样:先在控制台执行“磁盘扩容”,然后在系统内让分区和文件系统感知到新容量。

4.1 控制台扩容后的第一件事

在控制台完成扩容后,回到系统里先执行:

lsblk

你会看到磁盘整体容量已经变大了,比如原来 40G 的/dev/vda现在是 100G,但/dev/vda1还是 40G。如果lsblk看到的磁盘容量还是原来的值,说明云盘在系统层还没被重新识别,可以尝试:

echo 1 > /sys/class/block/vda/device/rescan

或者对大多数虚拟化平台:

partprobe /dev/vda

如果都不生效,那就只能重启实例。好在云服务器重启很快,代价不大。

4.2 分区扩容:两种云盘类型,两种处理方式

云服务器的系统盘绝大多数是 GPT 分区表,而且云厂商通常会预装 growpart 工具。确认根分区是哪个:

df -hT /

假设输出显示根是/dev/vda1,执行:

growpart /dev/vda 1

执行后立刻验证:

lsblk /dev/vda

如果看到分区大小已经变为 100G,说明分区表更新成功。极少数情况下,你看到分区的 SIZE 列已经变大,但cat /sys/class/block/vda1/size还是原来的块数,那可能是分区表信息没有刷新,重启一般能解决。

4.3 文件系统扩展,缺一不可

这一步和虚拟机场景一样,按文件系统类型选择命令。唯一需要注意的是,有些云厂商的系统盘默认是 xfs(比如新版 CentOS、阿里云 Alibaba Cloud Linux),有些是 ext4(比如 Ubuntu、Debian)。执行完文件系统扩展后,df -hT /看到的容量就更新了。

为了降低风险,云服务器扩容前建议打一个“磁盘快照”。别觉得麻烦,快照几分钟就能创建好,却能让你在操作失误时一键回滚,成本极低,收益极高。

4.4 扩容后如果新空间没生效,查这几个地方

  • df -hT没有变化:检查文件系统扩展命令是否执行成功,可能是命令报错了但你没仔细看输出。
  • 确认lvextend是否已经把空间划给根逻辑卷,可能卷组里有空闲空间,但逻辑卷没扩展。
  • 确认是否格式化过(千万别):如果你不小心对新分区执行了mkfs,数据全部清空,只能靠快照恢复。
  • 确认是多路径盘还是直通盘:有些云盘在多路径环境下,块设备名不是/dev/vda,而是/dev/mapper/mpatha,扩容方式完全不同,建议咨询云厂商文档。

5. 非 LVM 且无剩余空间的另一种解法:目录迁移与软链接

有时候根目录所在的磁盘在物理上和分区表层面都已经是“满”了,没有未分配空间可以扩,也没有云控制台可以点。这种情况下,最稳的方案不是强行改分区表,而是把大目录迁移到新磁盘或新分区上,用软链接指回去。这个方案安全、可逆、不需要动根分区,非常适合那些“根分区规划太小但没法在线扩”的老机器。

举个例子,根目录下/home或者/var/lib/mysql占满了根分区,而系统里刚好加了一块新盘/dev/sdb。操作流程:

  1. 格式化新盘(确认盘符不会写错):
mkfs.ext4 /dev/sdb1
  1. 挂载新盘到临时目录:
mkdir /mnt/newhome mount /dev/sdb1 /mnt/newhome
  1. 同步数据:
rsync -avH /home/ /mnt/newhome/

用 rsync 而不是 cp,是因为 rsync 能保留文件属性、硬链接、时空戳,而且可以断点续传。数据同步完成后,校验一下数据完整性:

diff -r /home/ /mnt/newhome/
  1. 把原目录改名做备份,然后挂载新盘到原路径:
mv /home /home.bak mkdir /home mount /dev/sdb1 /home
  1. 验证一切正常后,写入开机自动挂载:
echo "/dev/sdb1 /home ext4 defaults 0 0" >> /etc/fstab
  1. 确认无误后删除旧的/home.bak,或者先保留几天再清理。

这种方式对很多人来说比扩容根分区更实用:不需要动分区表,不会中途停电翻车,风险集中在数据拷贝阶段,而数据拷贝本身是可以反复校验的。

6. 我踩过的一些坑:扩容时最容易翻车的几个细节

6.1 xfs 只能扩大不能缩小

这是文件系统层面的硬限制,不是 Linux 的 bug。所以在规划分区时就要想清楚:xfs 的根分区给太大,空间浪费;给太小,后面想缩回来几乎不可能。我的建议是,如果用 xfs 做根分区,初始容量最少给 50G,云服务器用户可以直接给 80G 甚至 100G。很多人问“我 xfs 根分区能不能缩小”,答案是不能,除非你备份重做分区。这是踩过坑之后最痛的教训。

6.2 扩容顺序千万别搞反

LVM 扩容的正确顺序永远是:物理卷(pvresize)→ 卷组(自动识别)→ 逻辑卷(lvextend)→ 文件系统(resize2fs/xfs_growfs)。倒过来执行几乎都会提示找不到空间或没有多余空间。网上有些教程把顺序写得模棱两可,跟着实操很容易失败,建议以这个顺序为准则。

6.3 分区表操作前先备份

虽然 growpart 很安全,但你永远不知道手滑会敲出什么命令。在改动分区表前,花十秒钟跑一下sfdisk -d或者parted ... print free留底,必要的时候甚至可以给云盘打个快照。我见过不少同行在分区表操作时翻车,最终只能靠备份恢复,所以这个习惯真的值得养成。

6.4 resizepart 之后一定刷新分区表

不管是 growpart 还是 parted resizepart,操作完都要刷新分区表。部分环境中这个刷新会自动完成,但有些环境不会。如果lsblk显示分区大小已经变了,直接执行文件系统扩展命令即可;如果没变,一定要partprobe或重启,千万不要直接去执行resize2fs,那会得到 “Couldn't find valid filesystem superblock” 之类的报错。

6.5 docker 目录疯狂膨胀

如果是 Docker 服务导致的根分区爆满,最简单的方式是给 docker 的默认存储目录单独挂一个数据盘。你可以通过配置/etc/docker/daemon.json中的>df -hT / lsblk

确认根分区容量已更新、文件系统挂载正常。然后,把mount -a执行一遍,确认/etc/fstab里的挂载项没有语法错误。如果是 LVM 扩容,确认vgslvs输出正常,卷组里不要遗留奇怪的“unknown device”。

到这里,扩容操作本身已经完成了。但这段经历真正值得沉淀的是:下次你装机或重装系统时,记得给根分区留足余量,数据目录单独挂数据盘,日志目录单独规划大小,不要把所有鸡蛋放在一个筐里。扩容的“术”很简单,难的是对空间规划的“道”。把这次遇到的情况记录下来,下次告警再来时,你就能从容应对了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询