ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux磁盘扩容实战:从分区到LVM及文件系统完整指南

Linux磁盘扩容实战:从分区到LVM及文件系统完整指南

“磁盘满了,应用告警,日志刷屏,数据库写入失败……”这大概是运维人最不想半夜看到的画面。我处理过不少“Linux磁盘扩容”的工单,从裸金属到虚拟机、从传统分区到LVM,前前后后踩过很多坑。这篇文章不绕弯子,先把扩容背后的三层结构讲清楚,再把最常见的两种扩容路径一步步写明白,最后附上我自己的排查经验和操作习惯。无论你是刚接触服务器没多久,还是已经扛过几次故障,照着这套思路走,至少不会把能在线完成的扩容做成需要停机的大工程。

1. 扩容之前,先把场景和原理盘清楚

1.1 你遇到的到底是哪一种“磁盘不够用”

很多人一上来就问“磁盘满了怎么扩容”,但“磁盘不够用”至少分三种情况:

第一种是整块磁盘已经用满,比如系统盘本身只有40G,根分区满了,连日志都写不进去。第二种是磁盘还有剩余空间,但当初分区时只分了一小块,剩下的空间一直闲着没分配。第三种是空间已经分配给某个分区,但那个分区挂载的目录不对,或者文件系统没跟着扩,导致df看起来没变化。

这三种情况的操作路径完全不同。第一种需要看你用的是LVM还是传统分区;第二种好办,直接在原有分区上扩展,前提是这块磁盘是虚拟磁盘或云盘,且分区在磁盘靠后的位置;第三种最坑,因为命令都执行成功了,但df始终显示旧容量,往往就是文件系统扩容那一步漏了。

所以我拿到一台机器,第一件事不是敲fdisk,而是先看整体布局。

1.2 扩容的关键:分区、卷、文件系统三层结构

Linux磁盘管理可以简单分成三层:物理磁盘、分区或逻辑卷、文件系统。物理磁盘对应/dev/sda这种设备;分区是/dev/sda1、/dev/sda2;LVM场景下还有物理卷PV、卷组VG、逻辑卷LV;文件系统则是ext4、xfs这类格式,挂在某个目录上供业务读写。

可以把这三层理解成书柜:物理磁盘是整个书柜,分区是书柜里的隔板,文件系统是隔板上放档案盒的区域。你想让某个档案盒区域变大,不能只把隔板往外挪,还得告诉档案盒系统“现在你可以多占用一点空间”。放在Linux里就是:磁盘扩容 -> 分区/逻辑卷扩容 -> 文件系统扩容,三步缺一不可。

这也是很多人“扩容失败”的根源:云控制台把磁盘从100G扩到了200G,lsblk也看到sda变大了,但分区没动;分区动完了PV没动;PV动完了LV没动;LV动完了忘记跑xfs_growfs。每一层都有对应的命令,少一步,df永远不变。

1.3 不同环境的扩容差异(物理机、虚拟机、云主机)

物理机扩容通常要加物理硬盘,或者通过RAID卡在线扩容RAID组,系统层面可能还需要重新扫描SCSI设备。虚拟机则方便很多,在虚拟机管理平台里可以直接给虚拟磁盘扩容,甚至支持在线热扩容。云主机就更简单了,在云控制台里对云盘做“扩容”,但我必须强调一句:控制台扩容完成后,操作系统里看到的往往只是磁盘设备变大了,分区和文件系统还停留在旧状态,必须手动继续处理。

另外,物理机扩容时如果涉及RAID,操作顺序和普通虚拟机还不一样,必须先让RAID层面识别到新容量,再进系统处理。虚拟机和云主机的流程基本一致,只是“让系统识别新磁盘容量”这一步不同:虚拟机可能要扫描总线,云主机可能直接lsblk就能看到新容量,少数场景需要重启。

2. 动手前的必备检查和数据备份

2.1 用这几条命令摸清现状

在敲任何可能影响分区表的命令之前,先把现状摸清楚。我常用的组合是:

df -hT lsblk blkid pvs && vgs && lvs fdisk -l

df -hT能告诉你哪些文件系统满了、文件系统类型是什么、挂载点在哪。lsblk能看到磁盘、分区、LVM各层的关系,是判断“磁盘变大了但分区没变”的最直观工具。blkid用来记录分区UUID和文件系统类型,后面检查挂载关系会用到。pvs/vgs/lvs只对LVM环境有意义,能直接看出物理卷、卷组、逻辑卷目前的大小和剩余空间。

fdisk -l我习惯放在最后,因为它在某些环境下输出比较长,但能看到磁盘总容量、分区起始扇区和结束扇区。如果磁盘总容量已经变大了,但最后一个分区的结束扇区还停在旧位置,那基本可以断定分区还没扩展。

2.2 数据备份怎么做到不踩坑

扩容虽然不像格式化那样破坏性大,但任何涉及分区表和文件系统元数据的操作都有风险。我自己见过有人在生产环境执行resize2fs时中途断电,虽然概率低,可真遇到了就是事故。

对于云主机和虚拟机,最省事的是打快照。快照不是备份,但它能让你在操作失败后快速回滚到扩容前的状态,这比任何命令都重要。某些云平台支持在线快照,不影响业务;如果不能在线打快照,那就安排一个维护窗口,停机后快照。

对于物理机,没有快照的话,至少要把/etc/fstab、/etc/grub2.cfg这类关键配置文件备份出来,同时用tar或rsync把重要数据复制到其他磁盘。数据库场景还要额外注意:不能直接对数据目录做文件拷贝,必须用数据库自己的导出工具,否则拷出来的数据可能是坏的。

2.3 扩容前的风险清单

我给自己总结过一份扩容前风险清单,每次操作前都会过一遍:

  • 确认业务可接受的停机时间。能在线扩容的尽量在线做,但分区表调整仍存在风险。
  • 确认磁盘上是否还有未分配空间。如果没有,先解决物理容量问题。
  • 确认根分区和/boot分区的关系。如果/boot是独立分区且满了,扩容根分区并不能解决启动问题。
  • 确认文件系统类型。ext4用resize2fs,xfs用xfs_growfs,命令用反了会直接报错。
  • 确认有没有正在使用该分区的进程。尤其是数据库和容器,扩容前最好停止写入。
  • 确认快照或备份已经完成,并验证过可恢复。

3. LVM场景下的磁盘扩容完整实操

3.1 虚拟机或云主机:从云控制台扩磁盘到系统识别

LVM环境下的扩容路径是:控制台/虚拟化平台扩容磁盘 -> 系统识别新容量 -> 扩展物理分区 -> pvresize扩展PV -> lvextend扩展LV -> 文件系统扩容。

先看“系统识别新容量”。假设原来是一块100G的云盘/dev/sda,控制台扩容到了200G。大多数情况下,用lsblk就能直接看到sda变成了200G:

lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 200G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 99G 0 part └─centos-root 253:0 0 99G 0 lvm /

这时候sda是200G,但分区sda2还是99G,PV、LV也停留在原来的大小。如果lsblk没变化,对于虚拟机可以尝试重新扫描SCSI设备,常见做法是:

echo 1 > /sys/class/scsi_device/设备编号/device/rescan

具体编号可以从/sys/class/scsi_device/下面找,但不同虚拟化平台差异很大。更稳妥的方法是先在管理平台确认磁盘已经是新容量,然后重启系统,几乎所有场景下都能识别。能在线就别乱折腾,重启一次的成本通常比在错误命令上反复试错低得多。

3.2 扩展物理卷、卷组、逻辑卷

确认系统看到了更大的磁盘后,先扩展分区。比如上面例子里的sda2,可以使用growpart:

growpart /dev/sda 2

这个命令的作用是让最后一个分区占满磁盘剩余空间。执行后可以用lsblk验证:sda2应该从99G变成199G。这里有个前提:sda2必须是磁盘上的最后一个分区,或者至少它后面没有其他分区。这也是为什么我们总是建议装系统时把LVM分区放到磁盘最后的原因。

分区扩完后,物理卷PV的大小还没有变,需要用pvresize让它识别分区的新容量:

pvresize /dev/sda2

然后看pvs,Free这一列应该出现了新空间:

pvs

接下来把剩余空间全部加到根逻辑卷。先看逻辑卷和卷组名字,再执行lvextend:

lvs vgs lvextend -l +100%FREE /dev/centos/root

这里-l +100%FREE表示把卷组里所有空闲空间全部分配给这个逻辑卷。如果你只是想加一定容量,也可以用-L +50G这种写法。LVM的好处就在这,逻辑卷的调整比物理分区灵活得多,而且在线做基本没问题。

3.3 文件系统扩容:ext4与xfs的区别和命令

逻辑卷扩容完成后,df很可能还是旧值。原因很简单:文件系统并不知道自己可以变大,必须主动扩展。

如果是ext4,用resize2fs:

resize2fs /dev/centos/root

如果是xfs,用xfs_growfs,而且参数是挂载点:

xfs_growfs /

这两个命令都能在线执行。xfs_growfs还有一个特性:它的执行结果默认不打印“扩展后大小”,而是提示data blocks changed,所以看到“changed”就不用慌。

有一个关键区别一定要记住:ext4既支持扩大也支持缩小,但xfs只支持扩大,不支持缩小。如果你一开始用xfs做了根分区,后来想压缩空间重新规划,只能备份、删除、重建、恢复,整个过程复杂得多。

3.4 实操记录:从100G扩到200G的完整命令流

给一段完整示例,假设是某台生产虚拟机,原磁盘100G,根文件系统是xfs,挂载在/,逻辑卷路径是/dev/centos/root。

在虚拟化平台把磁盘从100G调整到200G后,进入系统执行:

# 1. 确认系统识别到磁盘新容量 lsblk /dev/sda # 2. 扩展sda2分区到磁盘尾部 growpart /dev/sda 2 # 3. 扩展物理卷 pvresize /dev/sda2 # 4. 扩展逻辑卷 lvextend -l +100%FREE /dev/centos/root # 5. 扩展xfs文件系统 xfs_growfs / # 6. 验证 df -hT /

我实际操作时,会在第2步和第3步之间再用lsblk确认一次分区大小,避免分区没扩成功就继续跑pvresize。第5步执行时,如果当前目录正好在/下面,某些环境会提示target is busy,但通常不影响执行,换个目录或者直接指定挂载点即可。

整套流程跑完,df -hT里根分区应该已经变成200G。如果还停在100G,不要怀疑人生,大概率是第2、3、4、5步里漏了某一步,按顺序重新检查。

4. 非LVM场景怎么扩容:直接扩展分区

4.1 用parted/growpart调整分区表

不是所有系统都用LVM。很多老系统、云镜像或者直接用ext4根分区的机器,根本没有PV/VG/LV这套逻辑。这时候扩容路径更简单,但也更危险:物理磁盘扩容 -> 扩展分区 -> 扩展文件系统。

最理想的情况是根分区是磁盘的最后一个分区,并且磁盘上还有未分配空间。此时可以使用growpart直接扩展分区:

growpart /dev/sda 1

growpart比fdisk手动改分区表安全得多,因为它只扩展分区结束扇区,不会改动起始扇区和分区类型。如果你的Linux发行版没有growpart,可以用parted:

parted /dev/sda resizepart 1 100%

这会交互式地让你确认,部分版本还会提醒是否更新分区表。实际操作时我要确认一下:parted resizepart只对GPT分区表和部分场景好用,MBR分区表有时会提示不能在线调整,需要重启才能生效。

如果你发现根分区不是最后一个分区,比如sda1是/boot,sda2是根分区,而磁盘后面没有空闲空间,那就比较麻烦了。这种情况最好提前规划,在安装系统时就留出足够的根分区,或者直接改用LVM。

4.2 让内核重新读取分区表

扩展分区后,Linux内核不一定立刻使用新分区表,需要重新读取。最常用的是:

partprobe /dev/sda

partprobe在大多数场景下能无痛刷新分区表。但有一种情况会失败:某个分区正被挂载使用,内核认为分区表忙,拒绝重读。此时会报“Device or resource busy”。如果实在不行,只能安排重启,或者在维护窗口里卸载文件系统再重读。

注意:fdisk里的w选项在写入分区表后也会触发内核重读,但同样可能遇到占用问题。不要因为看到“Syncing disks.”就认为万事大吉,务必用lsblk或cat /proc/partitions确认内核已经看到新分区大小。

4.3 调整文件系统大小

分区扩展完毕后,文件系统还停留在旧大小。和LVM场景一样,ext4用resize2fs,xfs用xfs_growfs:

# ext4,参数是设备路径 resize2fs /dev/sda1 # xfs,参数是挂载点 xfs_growfs /

对于非LVM的ext4分区,resize2fs执行前最好先跑一遍e2fsck检查文件系统。虽然在线检查一般只是只读,但能提前发现隐患。xfs则没有对应的在线安全强制检查,更多依赖内核日志。

如果分区不在末尾,或者磁盘空间已经被其他分区占用,直接调整文件系统也没有意义,因为文件系统大小不能超过所在分区大小。遇到这种情况,我的建议是放弃“原地扩容”,改成“加一块新盘,把数据迁移过去”,而不是强行去动中间的分区。

5. 常见问题与排查技巧实录

5.1 为什么df -h看到的没变化

这是扩容后被问得最多的问题,几乎每次都有。排查顺序应该是:

先确认磁盘设备本身有没有变大:

lsblk /dev/sda

如果sda还是旧大小,说明物理层没扩或者系统没识别,该查云控制台或虚拟机设置,必要时重启。如果sda变大了但分区没变,是该扩分区,用growpart或fdisk。如果分区变大了但PV没变,是没跑pvresize。如果PV变了但LV没变,是没跑lvextend。如果LV变了但df没变,是没跑文件系统扩容命令。

我见过有人在“LV已经扩完”之后,没跑xfs_growfs就跑来问为什么df没变化,其实只要执行xfs_growfs /就结束了。

还有一个容易忽略的点:某些文件系统扩容后,df显示的是旧inode数量或者块大小,但实际已经可用。可以用df -i看看inode有没有变化,用stat -f /看文件系统状态,别只盯着df的Size列。

5.2 “磁盘空间已用尽”但实际还有inode可用

这里有个常见误区:磁盘满了不只是容量满了,也可能是inode耗尽了。扩容后容量变大,但inode可能还是原来的数量,对于大量小文件场景,比如邮件队列、消息队列、容器日志目录,很容易出现“df容量没用完,但应用报磁盘满”。

命令是:

df -i /

如果IUse%是100%,说明inode耗尽了。ext4和xfs在扩容时通常会按比例增加inode,但如果你用的文件系统创建参数比较特殊,或者目录里小文件多到异常,容量扩完还是要关注inode。

遇到inode耗尽,优先清理无效小文件,比如旧的session、临时文件、过期的日志。实在清理不动,再考虑备份重建文件系统,因为增加inode数量通常需要重建文件系统,不能在在线扩容时直接指定。

5.3 分区表无法重新读取

执行partprobe或者fdisk w后报“Busy”,常见原因是有进程在使用该分区,或者某个逻辑卷正在使用对应的物理卷。处理思路是:先卸载文件系统,停止相关服务,再刷新分区表。

如果根分区无法卸载,那基本上只能重启。这也是为什么我强烈建议扩容动作放在维护窗口,留好重启时间。不要尝试用一些看起来很巧的命令强制在线重读,代价可能远超重启。

在云环境里,有些平台对在线扩容支持得比较好,分区表刷新通常不会失败。但物理机加磁盘后,SCSI扫描和内核重读反而容易出问题,这时候重启反而最干净。

5.4 xfs文件系统能否缩减

不能。xfs_growfs只有扩大功能,没有缩小功能。很多人在磁盘规划初期用了xfs,后来想压缩根分区给其他卷腾空间,会发现根本没有现成命令。

如果你必须为xfs缩容,唯一稳妥的办法是:备份数据、卸载文件系统、删除原逻辑卷或分区、创建较小的新逻辑卷/分区、格式化xfs、恢复数据。整个过程要停机,而且备份和恢复的时间成本很高。所以在创建文件系统时就要想清楚,不确定分区大小的场景优先用ext4或LVM,后期调整更灵活。

5.5 扩容到一半卡住或报错怎么办

resize2fs在扩容过程中如果报错,通常和文件系统不一致有关。先停止所有写入,然后执行e2fsck检查修复,再重新resize2fs。如果是xfs,xfs_growfs报错多半是逻辑卷还有剩余空间没分配,或者命令参数写错了,检查一下LV大小和文件系统当前大小。

让我提醒一句:不要一边扩容一边往这个分区里写大量数据。虽然在线扩容本身允许业务继续运行,但在数据剧烈写入的场景下做文件系统变更,风险会成倍增加。数据库这类场景,建议先停止写入,或者至少切到只读模式,扩完再恢复。

5.6 开机自动挂载与UUID注意事项

扩容后,一些系统会自动更新/etc/fstab,但更多情况是需要手动确认。分区表变化后,分区UUID在大多数情况下不会变,但少数分区管理工具调整后可能改变文件系统UUID。如果/etc/fstab里写的是UUID,开机后发现挂载不上,就要用blkid重新读取设备UUID,然后更新fstab。

我的习惯是扩容前先记录一份blkid输出,扩容后逐项对比。真的出问题,也能快速恢复。对于LVM场景,逻辑卷路径如/dev/centos/root一般是稳定的,但使用UUID挂载/xfs文件系统的机器,扩容后最好验证一次mount -a能不能正常挂载所有文件系统。

6. 一些我踩过坑之后总结出来的习惯

6.1 扩容前先拍快照

这句我几乎对每个来问的人都重复一遍:无论多么熟练,无论看起来多简单,扩容前先拍快照。我遇到过growpart一切正常、pvresize也成功,但在执行xfs_growfs时虚拟机突然死机的情况。没有快照,那就得靠备份恢复,时间完全不可控。有快照,回滚就是几分钟的事。

快照不是永久保留的东西,扩容验证通过后,确认数据完整、服务正常,就可以删除快照了。一直留着快照会占用存储空间,而且会影响性能。

6.2 命令顺序不要乱

扩容的命令顺序非常像多米诺骨牌:磁盘设备变大 -> 分区变大 -> PV变大 -> LV变大 -> 文件系统变大。任何一步提前或跳步,都会导致后续命令报错。比如LV还没扩,直接跑xfs_growfs,它会告诉你“没有空间可以扩展”;分区没扩,直接pvresize,它会认为PV大小不变。

所以我习惯把每个步骤用lsblk或df验证一遍再往下走。多敲几次lsblk不丢人,漏敲一个命令才是真的麻烦。

6.3 运维变更记录

最后分享一个习惯:每次扩容操作,我会把操作前状态、操作命令、操作后状态都记录下来,包括df快照、lsblk输出、pvs和lvs的输出。原因很简单:半年后这个磁盘可能又满了,你或者接手的人需要知道上一次扩容到底扩到了哪一步,有没有留下没做完的事情。

变更记录不一定要写得多正式,哪怕是一个文本文件,只要包含了关键命令和前后对比,就能省下大量排查时间。我个人见过太多“磁盘还是满的,但大家都说已经扩过了”的诡异场景,最后查下来要么是文件系统没扩,要么是扩到了别的逻辑卷。有记录,一眼就能定位问题。

Linux磁盘扩容这件事,说难不难,说简单也简单,但真正让操作变得可靠的不是某一条命令,而是对三层结构的理解和对风险的敬畏。希望你下次处理扩容时,能在动手前先笑一笑,然后冷静地走完每一步。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进