1. 为什么你的根分区说满就满先搞清楚空间到底被谁吃了做运维这些年隔三差五就能收到“根分区使用率 98%”的告警一开始还会紧张一下后来发现这几乎是每台服务器走向稳定的必经之路。很多人第一反应是加磁盘、扩分区但说实话如果不先搞清楚空间是被谁占掉的扩完还是会满。根目录不是一瞬间爆掉的它的使用率通常是在日志堆积、软件缓存、临时文件这些地方一点点被蚕食的。先看几个最常见的高危目录你ssh上去之后可以先按这个顺序检查/var/log服务日志、系统日志、nginx/access.log、mysql 慢查询这些文件正常情况下会按天切割但一旦某个服务疯狂写错误日志几天就能把磁盘塞满。我见过最夸张的一次一个 Java 应用因为死循环打异常堆栈两天写了 120GB 日志。/tmp很多程序会把临时文件往这里丢比如解压中的 tar 包、上传中的临时分片、sort 命令的中间文件。程序异常退出后这些临时文件不会被自动清理。/var/cacheapt/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。再看块设备分布执行lsblk或lsblk -f确认磁盘是怎么分区的、有没有 LVM、物理卷大小是多少。这一步决定你后面能走哪条扩容路线。最后定位大文件执行du -sh /*先把根目录下一级目录的占用列出来找到大目录再一层层往下钻。这一步有个效率技巧直接cd /然后再敲du -sh *还是慢用ncdu这个工具会更直观它可以交互式浏览目录树按大小排序还能直接删除垃圾文件几秒钟就能定位到“罪魁祸首”。如果是应急止血先别急着扩容把下面这几类东西清一清journald 日志执行journalctl --vacuum-size200M把 systemd 日志限制在 200MB 内。这个命令比直接删文件安全它会自动处理正在写入的日志文件。apt/yum 缓存Ubuntu 执行apt-get cleanCentOS 执行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-imageDebian/Ubuntu或rpm -qa | grep kernelCentOS列出所有内核把旧的删掉。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输出里如果看到vda1或sda1这类直接挂根目录的就是传统分区如果看到类似vg-root、vg-lv_root、ubuntu--vg-ubuntu--lv这种带逻辑卷名称的就是 LVM如果只有vda1但你在云控制台已经执行过扩容那就是云盘场景。2.2 确认文件系统类型ext4 和 xfs 的扩容命令完全不同文件系统类型决定扩容的最后一步用什么命令这一步出错会导致数据丢失所以绝对不能跳过。df -hT /输出结果的第二列会显示文件系统类型如果是ext4最后一步执行resize2fs /dev/xxx可以无损扩展而且支持在线扩容。如果是xfs最后一步执行xfs_growfs /注意这个命令的参数是一个挂载点而不是设备路径而且 xfs 只能扩大不能缩小。也就是说如果某个 xfs 分区空间规划过头了你想把它缩小那基本只能备份重来。如果你看到是 btrfs情况又不一样它自带子卷功能一般很少通过传统分区方式去扩容这里不展开讲。分类讨论完之后还有一条铁律无论哪种情况扩容前先确认有没有空闲空间。用fdisk -l /dev/sda或parted /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/vda1xfs 文件系统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。操作流程格式化新盘确认盘符不会写错mkfs.ext4 /dev/sdb1挂载新盘到临时目录mkdir /mnt/newhome mount /dev/sdb1 /mnt/newhome同步数据rsync -avH /home/ /mnt/newhome/用 rsync 而不是 cp是因为 rsync 能保留文件属性、硬链接、时空戳而且可以断点续传。数据同步完成后校验一下数据完整性diff -r /home/ /mnt/newhome/把原目录改名做备份然后挂载新盘到原路径mv /home /home.bak mkdir /home mount /dev/sdb1 /home验证一切正常后写入开机自动挂载echo /dev/sdb1 /home ext4 defaults 0 0 /etc/fstab确认无误后删除旧的/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那会得到 “Couldnt find valid filesystem superblock” 之类的报错。6.5 docker 目录疯狂膨胀如果是 Docker 服务导致的根分区爆满最简单的方式是给 docker 的默认存储目录单独挂一个数据盘。你可以通过配置/etc/docker/daemon.json中的>df -hT / lsblk确认根分区容量已更新、文件系统挂载正常。然后把mount -a执行一遍确认/etc/fstab里的挂载项没有语法错误。如果是 LVM 扩容确认vgs、lvs输出正常卷组里不要遗留奇怪的“unknown device”。到这里扩容操作本身已经完成了。但这段经历真正值得沉淀的是下次你装机或重装系统时记得给根分区留足余量数据目录单独挂数据盘日志目录单独规划大小不要把所有鸡蛋放在一个筐里。扩容的“术”很简单难的是对空间规划的“道”。把这次遇到的情况记录下来下次告警再来时你就能从容应对了。
