OpenEuler 24.03 LVM逻辑卷管理实战:扩容、快照与故障排查
2026/9/17 2:37:14 网站建设 项目流程

这个系列写到第17篇了,前面几篇把OpenEuler 24.03的安装、网络配置和服务管理都过了一遍,评论区一直有朋友追着问:安装时分区到底怎么选?根目录满了怎么办?给home扩容到底要不要重启?这些问题背后其实都指向同一个技术点——LVM逻辑卷管理。在OpenEuler 24.03里,从你点下自动分区那一刻起,LVM就已经接管了整块磁盘:根目录、home目录都住在逻辑卷里,设备名也不再是熟悉的 /dev/sda2,而变成了 /dev/mapper/openeuler-root 这种样子。如果不理解这套抽象,扩容、快照、数据盘迁移这些日常操作就无从谈起。

这篇文章我按自己平时排障的思路来写:先解释为什么OpenEuler默认要用LVM,再把PV、VG、LV这些概念用大白话讲透,然后从创建到扩容、快照、故障排查给出一套可以直接照抄的命令序列。适合刚上手OpenEuler的运维新人,也适合用过LVM但总在细节上踩坑的老手。个人经验优先,能帮大家少走弯路。

1. 为什么在OpenEuler 24.03上要用LVM

1.1 装完系统后,你的磁盘其实早就是LVM

很多朋友第一次装完OpenEuler,打开终端执行 lsblk,看到输出里不是 sda1、sda2 这种简单的分区名,而是 openeuler-root、openeuler-home 这样的设备路径,第一反应是怀疑自己安装选错了。没有选错。OpenEuler 24.03的安装器在自动分区方案下默认采用LVM:会单独切一个 /boot 普通分区,用于存放内核和引导文件;而根目录、/home 以及其他业务分区,全部放在一个或多个逻辑卷里。

为什么安装器要这么做?因为LVM给系统预留了后悔药。传统分区方案下, / 和 /home 是两块独立的物理分区,中间空余空间没法自由调配;LVM方案下, / 和 /home 只是同一个资源池里的两个租户,谁空间不够,随时可以把资源池里剩余空间划给谁,甚至不用重启。

判断当前系统是否用了LVM,命令很简单:

lsblk pvs vgs lvs

lsblk 看的是设备和挂载点的对应关系;pvs、vgs、lvs 是LVM自己的三张视图,分别显示物理卷、卷组、逻辑卷。如果在输出里看到了 vg 层面的信息,那LVM就在工作。

1.2 传统分区和LVM的关键差别

我经常跟同事打一个比方:传统分区相当于买房,房间隔断是砖墙,想改格局必须砸墙,动静很大;LVM相当于租了个大开间,用移动隔板分区,今天想要大客厅就拉大隔板,明天想要大卧室再推回去。

具体差异看这张表:

对比项传统分区LVM
扩展方式需要重新分区,通常要停机卷组有剩余空间即可在线扩展
跨磁盘单块物理盘一个卷组可以跨多块物理盘
缩容从头分区再同步数据理论上支持缩容,但受文件系统限制(XFS不可缩)
快照依赖文件系统层LVM原生支持,秒级创建
数据迁移需要dd或rsyncpvmove在线迁移,业务无感
故障排查相对简单多一层抽象,启动时依赖lvm2服务

看起来LVM几乎全胜,但代价是系统启动链路里多了一个lvm2组件。如果在救援模式里忘了激活卷组,你可能会连自己的数据盘都找不到。这个坑后面专门聊。

1.3 LVM帮我解决的真实问题

举几个我实际遇到的场景。第一类是根分区被日志写满,系统告警,如果是传统分区只能想办法删日志,删完了还是焦虑;LVM方案直接从卷组匀10G给根分区,lvresize 加一条 xfs_growfs,几十秒搞定。第二类是数据库服务器加了块新盘,当时没规划好,后续要并入已有数据目录,LVM只要 pvcreate 再 vgextend,旧数据完全不用动。第三类是日常发布前给业务卷打快照,出问题5分钟内回滚,这在传统分区时代几乎不敢想象。这些体验足够说明,在OpenEuler这种长期稳定运行的系统里,LVM是值得养成的存储习惯。

2. LVM基础概念和完整创建流程

2.1 PV、VG、LV、PE:用一杯水讲清楚

LVM术语看起来唬人,拆开看就四个东西。

PV(Physical Volume,物理卷)是把一块硬盘或者硬盘分区初始化为LVM能识别的存储单元,相当于你买回来的矿泉水瓶,是可以使用的原材料。VG(Volume Group,卷组)是把多个PV拼在一起形成的资源池,相当于把好多瓶水倒进一个大桶里,桶的容量是所有瓶子之和。LV(Logical Volume,逻辑卷)是从VG这个大桶里舀出来的水,挂载到系统后就是一个虚拟分区,用户可以像使用普通分区一样使用它。PE(Physical Extent,物理扩展块)是VG分配空间的最小单位,默认4MB,可以理解成舀水的勺子大小,每次分配都以PE的整数倍进行,所以有时候你看到LV大小和命令里写的数值不是完全一致,多半是PE对齐造成的。

弄懂这四个概念后,LVM整套命令体系就很好记了:pv开头的是操作物理卷,vg开头的是操作卷组,lv开头的是操作逻辑卷。

2.2 从一块新硬盘开始,完整创建LVM

下面我用一台虚拟机现场演示,新加一块10G的硬盘,设备名是 /dev/sdb,目标是创建一个5G的逻辑卷挂载到 /data。

第一步,初始化PV:

sudo pvcreate /dev/sdb

输出会显示 Physical volume "/dev/sdb" successfully created。这里我特意用了整块盘而不是分区,现代LVM完全支持直接基于整块裸盘创建PV;如果你希望保留分区表,可以先用 fdisk 把磁盘分区,再把分区类型改成 8e(Linux LVM),然后 pvcreate /dev/sdb1。

第二步,创建VG:

sudo vgcreate data_vg /dev/sdb

第三步,从VG里创建LV:

sudo lvcreate -n data_lv -L 5G data_vg

说明一下参数:-n 指定逻辑卷名字,-L 指定容量。创建完之后, /dev/data_vg/data_lv 这个设备就出现了,也可以使用 /dev/mapper/data_vg-data_lv 访问它。

第四步,在LV上格式化并挂载:

sudo mkfs.xfs /dev/data_vg/data_lv sudo mkdir -p /data sudo mount /dev/data_vg/data_lv /data

提醒一句,OpenEuler默认文件系统是XFS,XFS的扩容只能加不能减,这一点后面会反复强调。如果你需要一个能缩容的文件系统,格式化时就该选ext4。

2.3 挂载持久化:fstab里的两个坑

mount命令只能临时挂载,重启就失效。要让系统开机自动挂载,把下面这行加进 /etc/fstab:

/dev/mapper/data_vg-data_lv /data xfs defaults 0 0

不过这里有两个我踩过的坑,值得单独拿出来说。

第一个坑是Device Mapper路径的横杠问题。在 /dev/mapper 下,卷组名和逻辑卷名之间用横杠分隔,但如果卷组名或LV名本身带横杠,比如 vg-test 配 lv-data,那路径就会变成 /dev/mapper/vg--test-lv--data,横杠会翻倍。这个规则很容易把新人绕晕,所以我的习惯是用UUID代替设备路径。执行 blkid /dev/data_vg/data_lv 拿到UUID,然后:

UUID=xxxx-xxxx /data xfs defaults 0 0

第二个坑是校验。改完fstab后,一定执行 mount -a 或者直接 reboot,别等到登录不了了才想起来。之前有同事在文本编辑器里写错一个单词,重启后系统直接进入emergency mode,排查半天才发现是fstab格式问题。改fstab这事,万无一失的做法永远是改完立刻验证。

3. 给home目录扩容的完整实操步骤

3.1 扩容前,先把三层结构看清楚

扩容是Linux运维里最高频的操作,但很多人上来就是执行 lvextend,然后发现 df -h 里的容量根本没变化,于是开始怀疑人生。其实扩容是一个涉及三个层面的操作:先看VG这个资源池里还有多少水,再看LV这条水管要不要换粗,最后文件系统这个水龙头也要打开。大多数失败案例都是忽略了最后一步。动手之前,我建议按顺序执行四条命令:

df -hT vgs lvs pvdisplay

df 看文件系统当前容量和格式,vgs 看卷组剩余空间(VFree列),lvs 看逻辑卷的当前大小,pvdisplay 确认物理盘状况。这四条命令执行完,你对全局就心里有数了。

3.2 同卷组内扩容:两步走,别少一步

假设当前 /home 对应逻辑卷 /dev/openeuler/home,容量20G,vgs显示卷组剩余30G。想把 /home 扩到50G,执行:

sudo lvextend -L 50G /dev/openeuler/home

注意 -L 后有没有 + 号的区别:-L 50G 是扩容到50G,-L +20G 是在原来基础上增加20G。我的习惯是扩容用加号,因为意图更明确,不会因为记错当前容量把卷给缩小了。

然后调整文件系统。如果 /home 是XFS,执行:

sudo xfs_growfs /home

如果 /home 是ext4,执行:

sudo resize2fs /dev/openeuler/home

XFS和ext4的扩容命令参数完全相反:xfs_growfs 后面跟挂载点,resize2fs 后面跟设备文件。这一点太容易混淆了,我在生产环境里见过不止一个人对着XFS文件系统运行 resize2fs,结果直接把文件系统搞损坏。

嫌两步麻烦的话,新版lvm2支持 -r 参数一键完成:

sudo lvextend -r -L +20G /dev/openeuler/home

-r 表示调整LV的同时自动调用文件系统扩容工具。实测下来这个参数很稳,但我建议第一次用的时候还是先手动走一遍流程,真正理解发生了什么,再用自动化参数。

3.3 卷组空间不够:先扩VG,再扩LV

如果说 vgs 显示 VFree 为0,这时候就得从物理层想办法了。常见做法是给虚拟机或者物理机加一块新盘。假设新盘是 /dev/sdc,执行:

sudo pvcreate /dev/sdc sudo vgextend openeuler /dev/sdc

第一条命令把新盘变成PV,第二条命令把它并入现有的卷组。执行完再 vgs,VFree应该已经从0变成新盘的容量了,然后就可以继续执行 lvextend。

这里有一个虚拟化环境特别常见的现象:磁盘已经在虚拟机设置里加好了,但 lsblk 看不到。别急,这不是你操作的问题,是SCSI子系统没有及时扫描到新设备。执行:

echo "- - -" > /sys/class/scsi_host/host0/scan

如果还是看不到,把 host0 换成 host1、host2 再试,或者用 lsscsi 查看当前有哪些SCSI主机。扫描这个动作不会破坏数据,可以反复执行,直到 lsblk 看到新盘为止。

4. LVM快照和精简池:给数据上双保险

4.1 快照:升级之前打一发,秒级回滚

LVM快照是我在所有Linux服务器上都会用到的功能。它的原理不是复制数据,而是写时复制(Copy-On-Write):创建快照那一刻,LVM只记录源LV的元数据状态,几乎瞬间完成;之后源LV上每发生一次新的写入,旧数据才会被复制到快照空间里保存。所以快照刚创建时几乎不占空间,随着源LV数据不断变化,快照占用才会逐渐增长。

创建快照的命令:

sudo lvcreate -s -n home_snap -L 5G /dev/openeuler/home

-s 表示快照,-n 指定快照名,-L 是快照空间大小。快照空间给多大有讲究:如果源LV平时写入量很小,5G就够;如果是频繁写入的数据库目录,建议给源LV的20%以上。快照空间一旦写满,快照就会失效,甚至可能导致源LV暂停工作,所以宁可给大一点。

查看快照和使用情况:

lvs

输出里能看到快照的 Data% 或 Snap% 列,越接近100%越危险。

需要回滚时,先卸载源LV:

sudo umount /home sudo lvconvert --merge /dev/openeuler/home_snap sudo mount -a

merge完成后快照卷会自动消失,源LV恢复到快照创建那一刻的状态。我自己的习惯是:每次升级内核、升级数据库、跑批量脚本之前,都先打一个快照,出问题三分钟回到之前的状态,安全感和幸福感都很高。

4.2 精简池:把100G当400G规划

如果只是单块盘、单卷组,上面的用法完全够用。但如果你在跑虚拟化平台或者开发测试环境,要批量创建几十个业务卷,每个卷实际用量都不大,这时候传统的预先分配模式就很浪费。LVM的精简池(thin pool)就是为这种场景准备的。

精简池的精髓在于超卖:你创建一个物理上只有50G的精简池,却可以在里面创建多个虚拟容量为100G的精简卷,实际占用按写入量动态增长,就像容器镜像的分层存储,看起来很大,实际只占一小块。

创建精简池:

sudo lvcreate -T -L 50G -n thinpool openeuler

在池里创建精简卷:

sudo lvcreate -T openeuler/thinpool -n dev1 -V 100G

注意 -V 后面的是虚拟容量,可以远大于池的物理容量。创建完的精简卷格式化和挂载方式跟普通LV一样。

用精简池必须配置自动扩展,否则池撑满会发生连锁反应,所有精简卷一起出问题。编辑 /etc/lvm/lvm.conf,确认下面两行的值:

thin_pool_autoextend_threshold = 80 thin_pool_autoextend_percent = 20

意思是池的使用率达到80%时,自动给池追加当前池大小20%的容量。这个机制不配置好,建议不要直接上生产环境。另外精简卷不支持缩容,创建时虚拟容量想清楚再填,这也是精简池最常见的埋点。

5. 常见问题与故障排查实录

5.1 忘了密码要进rd.break,LVM卷组怎么激活

这个场景网上问得特别多,很多老鸟第一次遇到也容易卡住。当一台OpenEuler机器忘了本机密码,常规做法是重启后在GRUB菜单里按 e 编辑启动项,找到 linux 开头的行,在行尾加一个参数 rd.break,然后按 Ctrl+X 启动,系统会进入一个紧急shell。此时根文件系统被只读挂载在 /sysroot,可别以为LVM已经万事大吉。在紧急shell里,系统只完成了最小启动流程,其他数据卷组大概率没有主动激活;哪怕根卷组因为挂载 /sysroot 已经被initramfs碰过,为了接下来能对整套系统做操作,我仍然建议先手动确认LVM状态。

执行:

mount -o remount,rw /sysroot lvm vgscan lvm vgchange -a y

vgscan 先在磁盘上扫描出所有卷组,vgchange -a y 把所有卷组标记为激活。激活之后, /dev/mapper 下才会出现 openeuler-root 这些设备,后续 chroot /sysroot 进去才能正常操作系统。

完整流程大概是:

mount -o remount,rw /sysroot lvm vgscan lvm vgchange -a y chroot /sysroot passwd

改完密码后,如果系统开启了SELinux,建议在chroot环境里执行 touch /.autorelabel,重新标记一下安全上下文,避免因为上下文异常导致重启后无法登录。最后执行 exit 退出紧急shell,系统会继续完成启动。整个过程不要瞎敲命令,尤其是 lvm vgchange -a y 的时候,如果有多块盘,一定要先确认操作的是哪一块VG,别在数据盘上做出不可逆的操作。

5.2 扩容后容量没变化、克隆机器起不来:三个高频坑

第一个坑是扩容后文件系统容量没变。前面已经反复提过,lvextend 只是把LV变大了,文件系统本身还维持旧状态,必须执行 xfs_growfs 或 resize2fs。如果忘了这一步,df -h 显示的结果肯定是没变的。

第二个坑是XFS想缩容。XFS的设计决定了它只能扩不能缩。如果业务上确实需要缩容,唯一靠谱的办法是:备份数据、删除LV重新创建、恢复数据。千万别想着在线缩容XFS,那是拿数据开玩笑。ext4虽然能缩,但也必须先在卸载状态下用 resize2fs 把文件系统缩到小于目标LV大小,再 lvreduce 缩减LV容量,顺序反了一样会出问题。

第三个坑是克隆虚拟机后VG UUID冲突。把一台装了OpenEuler的虚拟机复制出来,开机后经常卡在LVM相关阶段,报 Volume group "openeuler" not found 或者 duplicate VG name。原因是克隆机的物理盘里还保留了原始VG的UUID,新机器上启动时LVM发现同一个VG有重复标识,就不激活了。解决思路是给新机器的VG重新生成UUID:

vgimportclone -n openeuler /dev/sdb

或者更直接一些,对未激活的VG执行:

vgchange -u VG名称

执行后VG的UUID会重新生成,就能正常激活了。这个操作只影响LVM元数据,不碰你的业务数据,但操作前还是提醒一句:先备份元数据,vgexport / vgimport 这套流程比较复杂,别在生产环境第一次实验。

5.3 问题排查速查表

我把LVM运维里最典型的几个问题和排查方向整理成一张表,遇到问题对照着找思路:

现象可能原因处理办法
df -h 容量没变LV扩展了但文件系统没调整xfs_growfs 挂载点或 resize2fs 设备路径
vgs 看不到新盘磁盘还没有初始化成PV执行 pvcreate /dev/sdX
新加磁盘 lsblk 不显示SCSI子系统没扫描到echo "- - -" > /sys/class/scsi_host/host0/scan
报 Volume group not foundVG名写错或卷组未激活vgscan 后 vgchange -a y
快照空间写满导致源LV异常快照分配太小、写入量过大检查 Data%,删除无用快照释放空间
克隆虚拟机后无法启动VG UUID冲突vgimportclone 或 vgchange -u 重新生成UUID
删除文件后空间不释放有进程仍占用已删除文件lsof | grep deleted,重启对应进程

这张表我贴在工位上很久了,几乎每周都派上用场。

6. 日常维护与监控技巧

6.1 用一行脚本盯住卷组剩余空间

LVM最大的风险往往不是操作失败,而是无人注意的持续增长。日志、临时文件、数据库归档,哪一天突然把卷组空间耗尽,所有写入全部失败,那才是灾难。所以监控卷组剩余空间,应该像监控CPU和内存一样日常。

我习惯写一个简单的脚本 /opt/lvm_check.sh:

#!/bin/bash threshold=10 free=$(vgs --noheadings --nosuffix --units g -o vg_free openeuler 2>/dev/null | awk '{print int($1)}') if [ "$free" -lt "$threshold" ]; then echo "$(date) VG openeuler free space is ${free}G, below ${threshold}G" >> /var/log/lvm_check.log fi

脚本里 vgs 的 --units g 会强制按G输出,--nosuffix 去掉单位,awk 取整比较即可。写完后记得 chmod +x /opt/lvm_check.sh,然后加到crontab里:

crontab -e

加一行:

0 9 * * * /opt/lvm_check.sh

每天早上9点跑一次。空间告急时除了日志,你还可以把它改成发送告警邮件或者调用接口通知。核心是把空间剩余多少从一个手工查看的事情,变成一个系统自动关心的事情。

6.2 让精简池和快照自动扩展,别把预警拖成故障

精简池的自动扩展配置在 /etc/lvm/lvm.conf 里,原理前面已经说了。这里再补充一个日常观察命令,定期看池和快照的占用比例,比等告警更可靠:

lvs -o lv_name,data_percent,snap_percent

data_percent 表示精简池或卷的数据占用比例,snap_percent 表示快照空间占用比例。我通常会在 cron 脚本里把这两个值也带入判断,任何一个超过85%就先手工扩容或清理,而不是干等自动扩展。自动扩展是兜底,主动观测才是第一道防线。

还有一个细节值得留意:创建LV时考虑PE大小。默认PE是4MB,存储量比较大的服务器,VG容量达到几十TB时,PE数量会非常巨大,可能导致部分操作变慢。对这种场景,可以在 vgcreate 时用 -s 参数指定更大的PE,比如:

sudo vgcreate -s 16M data_vg /dev/sdb

PE越大,管理开销越小,但空间分配粒度也会变粗,LV大小会按16M的整数倍向上取整。小容量环境没必要改,大容量环境值得规划一下。

最后再分享一个我自己的习惯。动手折腾LVM这几年,我最大的体会是:LVM不复杂,但它多了一层抽象,要求你有更强的全局感。操作之前先看vgs确认卷组还有多少余量,操作之后一定要确认文件系统真的感知到了新空间,这两步抓住了,九成故障都能避免。记得有次给 /home 扩容,命令里卷组名写对了,LV路径却不小心写成了 /dev/openeuler/root,结果 lvextend -r 直接把 root 给撑大了,重启后 /home 还是满的。从那以后我做任何LVM变更,都先 lvs 把目标LV的路径原样复制出来,再粘贴到命令里,绝不再手工输入。这套流程我用到现在,一次扩容事故都没再出过,你也试试?

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

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

立即咨询