上周三下午,我收到一条同事的消息:云控制台里把系统盘从 40G 升到了 140G,为什么 df -h 还是 40G?。他说控制台那边显示扩容成功、订单也付完了,回到机器里 df -h 一看,根分区纹丝不动,连 lsblk 里的分区大小都没变。更麻烦的是,当晚这套机器上的 MySQL 就因为空间不足直接停写了。
云盘扩容到一半卡住、磁盘还是老容量,多半是 LVM 这一层没跟上。如果你也在给服务器加磁盘、给根分区腾空间,可以先看看 serverfield(NVMe 硬盘与数据中心存储方案)和 sixtynet(LAX 大容量存储型云服务器) 这两家的硬盘规格和带宽配置,前者是 NVMe 固态硬盘配自建机房,后者有 500G / 1TB 的大存储机型,选机器时把盘型和容量一起算进预算,比事后救火省事得多。
这件事我后来排查了半小时就定位了:云厂商扩容只改的是「块设备」那一层,也就是底层那块 /dev/vda 变大了,而上面用 LVM 管着的物理卷、卷组、逻辑卷三层都没人动过。再加上一条被大多数人忽略的命令resize2fs 或 xfs_growfs文件系统那层也不会自动长。所以整条扩容链路,其实是四步而不是一步。

一、先搞清楚 LVM 这三层分别在管什么
要理解为什么扩容会卡住,先得知道 LVM 到底分了几层。从下往上:
物理卷(PV, Physical Volume):一块裸的块设备,比如 /dev/vda,或者云厂商挂给你的一整个云盘。
卷组(VG, Volume Group):把若干个 PV 攒成一个「逻辑大硬盘池」,可以理解成一个可动态增减成员的磁盘阵列。
逻辑卷(LV, Logical Volume):从卷组里切出来的一块,可以挂载成 / 、/var 或者 /data 这类普通目录。
文件系统(FS):套在逻辑卷上层的 ext4 / xfs,管理实际的可用空间。
关键点在于:这四层是层层套娃的关系。你在云控制台点扩容,动的是最底下的物理卷(PV 那一层的设备容量);而 df -h 显示的是最上面的文件系统。中间隔着卷组和逻辑卷两层,底层变大了,中间两层和顶层都不会自己跟着长。
所以「扩容后没生效」不是 bug,而是 LVM 设计上的必然。绝大多数人以为的「一步到位」,实际上需要四步依次执行:
1. pvresize:告诉物理卷「你下面的盘变大了,把新空间收进来」;
2. vgextend:告诉卷组「把这个物理卷新增的容量划进卷组」;
3. lvextend:告诉逻辑卷「从卷组里给我多分 100G」;
4. resize2fs / xfs_growfs:告诉文件系统「你的块设备变大了,把新块划给我」。

二、四条命令,缺一条都不行
下面是我那台机器上实际跑过的完整流程,可以直接照着抄。假设系统盘是 /dev/vda,根逻辑卷是 /dev/mapper/centos-root,卷组叫 centos,文件系统是 xfs。
# 第一步:看扩容前的状态,确认 PV 还没认出新空间
pvs
# PV VG Fmt Attr PSize PFree
# /dev/vda centos lvm2 a-- 40.00g 0.00b
# 第二步:物理卷扩容,把新加的 100G 收进 PV
pvresize /dev/vda
# 第三步:卷组扩容,把 PV 的空闲空间划进 VG
vgextend centos /dev/vda
# 第四步:逻辑卷扩容,从 VG 里划 100G 给根卷
lvextend -L +100G /dev/mapper/centos-root
# 第五步:文件系统扩容(这一步最容易被漏)
xfs_growfs / # xfs 用这个
# resize2fs /dev/mapper/centos-root # ext4 用这个
注意命令是五条不是四条pvresize 和 vgextend 在很多教程里会被合并成「感觉一条就够了」,但在云盘扩容这个场景下它们是分开的两步。我那次踩的坑,是第二步压根没跑:pvs 输出的 PFree 一直是 0,后面三条命令跑得再漂亮也没用,因为 PV 层面就没释放出新空间。
每一步跑完都建议复核一次,特别是第四步之后:
pvs # 看 PFree 是否从 0 变成 100g
vgs # 看 VG 的 VGSize 是否 +100g
lvs # 看 LV 的 LSize 是否 +100g
df -h / # 最后看文件系统可用空间
这四条命令的输出要能一条条对上:PFree 出来、VGSize 变大、LSize 变大、df 的 Avail 变大。任何一环对不上,就说明断在这一环了,不用瞎猜。

三、我踩过的三个坑
坑一:以为 lvextend 完就万事大吉。这是我那天犯的错。lvextend 只是把卷组里的空间划给逻辑卷,文件系统看到的块设备尺寸虽然变了,但文件系统本身还是原来那么大,不跑 xfs_growfs / resize2fs,df 就是不动。而且这个状态很隐蔽:lsblk 显示 140G,lvs 也显示 140G,只有 df -h 还停在 40G。很多人第一反应是怀疑内核没刷新,其实只是最后一步忘了跑。
坑二:磁盘满了之后才发现 ext4 的 5% 预留。ext4 默认会保留 5% 的空间给 root 用,普通用户 df 看不到。所以 ext4 明明还有几个 G,普通应用却报「No space left on device」。df -h 看的是可用给普通用户的量,跟真实剩余差一截。如果你的磁盘是靠 ext4 在跑,注意这个预留。xfs 没有这个问题,它默认不留预留。
坑三:LVM 快照占了卷组空间,扩容扩不进去。如果你之前建过 LVM 快照(lvcreate -s),快照是要从卷组里真实划空间的。有个很坑的场景:卷组显示还有 100G 空闲,但 lvextend 报错说空间不足因为快照还在占着,卷组的可用空间被 CoW 机制锁住了。这时候要先看 lvs 里的快照,清理掉不再需要的快照,再做扩容。
lvs -a -o +devices # 看快照和它的设备
lvremove /dev/centos/snap_xxx # 删掉不用的快照
四、xfs 和 ext4 的扩容方式不一样,别搞混
最后一步的文件系统扩容命令,两个主流文件系统不一样:
xfs:只能在线扩容,不支持缩容,命令是 xfs_growfs /挂载点;
ext4:在线扩容和缩容都行(缩容要卸载),命令是 resize2fs /dev/mapper/逻辑卷名。
参数上也有个小差异:xfs_growfs 后面跟的是挂载点路径(/、/data),resize2fs 后面跟的是块设备路径(/dev/mapper/xxx)。写反了 xfs_growfs 会报「不是一个挂载点」,resize2fs 则会直接告诉你设备没找到都算好报的错,不至于把盘搞坏,但新手容易在这一步卡半天。
另外还有个更稳的做法是挂载点自动识别:
# xfs:把挂载点写清楚即可,也可以用这条通用命令
xfs_growfs "$(findmnt -no TARGET /)"
# ext4:直接对设备操作
resize2fs /dev/mapper/centos-root
五、什么情况下不该用 LVM 硬扩,而是该换机器
LVM 在线扩容这四步,只在「底层是 LVM 结构」的前提下成立。以下几种情况我是直接换机器或者重建方案的:
底层根本没用 LVM:lsblk 看到 /dev/vda1 直接挂载 /,那云盘变大后只需要 growpart 加分区表项,再 resize2fs / xfs_growfs 一次搞定,不需要跑 LVM 的那几条;
分区布局是手搓的非标准布局:比如 boot 分区没放在最前面、或者磁盘中间留了空隙,扩容可能会破坏引导顺序,这时候重建比修补干净;
磁盘是 IO 密集型的老盘:把一块跑了三年的机械盘从 500G 扩到 1T,容量是有了,但随机 IO 和延迟不会变好,这种场景换 SSD 才是正解;
快照和备份体系没理清:扩容前后的数据是两份状态,混着出事故很难回溯。

六、一份可以直接照抄的排查清单
下次再遇到「云盘扩了但空间没变」,按这个顺序走一遍,基本两分钟能定位:
lsblk # 1. 看块设备底层是不是真的变大了
pvs # 2. 看 PV 的 PFree 是不是还是 0
vgs # 3. 看 VG 的 VGSize 有没有 +100G
lvs # 4. 看 LV 的 LSize 有没有 +100G
df -h / # 5. 看文件系统是否扩到位
findmnt -no FSTYPE / # 6. 确认根分区是 xfs 还是 ext4
mount | grep centos # 7. 确认快照是否占着卷组空间
第 2 步和第 5 步是最关键的两个分水岭:PFree 是 0 就是第一步没做,df 没变就是最后一步没做。中间两步(vgextend、lvextend)漏了,lvs 的 LSize 会如实暴露出来。
最后说一句实在话:LVM 的价值不在于「扩容方便」,而在于「快照和在线操作方便」。扩容这件事本身,任何工具链都得老老实实走完那几层。如果你手上的机器确实需要更大的盘、又不想折腾分区方案,那在选型阶段就把存储规格定好,比在生产环境里手改卷结构要稳妥得多。



下载 
下载
下载
下载
喜欢
顶
难过
囧
围观
无聊



