做Linux运维和服务器管理,磁盘管理是永远绕不开的基本功。而只要涉及“动态扩容”“灵活调整”这类需求,LVM(逻辑卷管理)几乎就是默认答案。网上讲LVM的教程不少,但大多数只停留在“敲命令能跑通”的层面,真正到生产环境遇到卷组满了、磁盘掉了、系统重启后卷不认了,才发现自己对LVM的理解还是皮毛。
这篇文章围绕最核心的三个命令——pvcreate、vgcreate、lvcreate,把LVM从裸盘到业务挂载的完整链路捋一遍。我会把每一步背后的设计逻辑、参数取舍、实际运维中容易踩的坑都讲清楚。适合刚接触LVM的初学者,也适合那些用过LVM但遇到问题只能靠百度解决的运维朋友。
1. LVM整体设计与核心思路
很多人第一次接触LVM时,最大的困惑是:明明fdisk分区、mkfs格式化、mount挂载就能用,为什么还要多出PV、VG、LV这一堆概念?这个问题的答案,恰恰是LVM存在的根本意义。
1.1 传统分区的痛点在哪里
用传统分区方式管理磁盘,最大的问题在于“分区的边界是固定的”。比如你给/home分了500G,结果数据涨得飞快,500G不够用了,而/data分区还剩200G空闲。这时候你想把200G挪给/home?做不到。传统分区不支持在线调整大小,就算用resize2fs配合fdisk调整,也得先卸载分区、重新划分边界,极其痛苦,而且有数据丢失风险。
我见过不少业务事故,就是磁盘扩容时操作失误导致数据损坏。用LVM之后,这种“拆东墙补西墙”的问题基本不存在了,因为LVM把物理磁盘和最终呈现给业务的逻辑空间彻底解耦了。
1.2 三层架构与核心概念
LVM把磁盘管理抽象成三层:
- PV(Physical Volume,物理卷):最底层,本质是把整块磁盘或磁盘分区初始化为LVM可识别的格式,相当于把磁盘“格式化”成LVM的原料。
- VG(Volume Group,卷组):由多个PV聚合成一个“空间池子”,VG就是磁盘空间的中转仓库。你可以随时往VG里加PV,也可以把PV从VG里移走。
- LV(Logical Volume,逻辑卷):从VG池子里切割出来的“虚拟分区”,这才是最终格式化和挂载给业务使用的对象。
打个比方:PV是你买回来的面粉原材料,VG是你的厨房储物柜,LV是你从柜子里取出来、和好面准备蒸的那屉馒头。面粉多了就塞进柜子,柜子里的空间可以随时调整蒸多少馒头,不需要把已经蒸好的馒头回炉重做。
1.3 核心抽象:PE与LE
LVM底层还有两个容易被忽略的概念——PE和LE。
- PE(Physical Extent,物理扩展块):PV空间被划分成等大的小块,这个块的大小在创建VG时指定。
- LE(Logical Extent,逻辑扩展块):LV空间同样被划分成等大的小块,一个LE对应一个PE。
实际上,LVM管理空间的最小单位不是MB或GB,而是PE。VG里的空间就是由一个一个PE组成的,LV分配空间时,本质是“从VG中领取若干个PE”。理解这点对后面理解lvcreate的-l参数特别重要,因为-l参数指定的就是“领多少个PE”或者“占VG总PE数的百分之多少”。
1.4 有了LVM能做什么
总结下来,LVM带来的核心能力就三个:
- 在线扩容:VG容量不够时,加新硬盘或新分区,vgextend把空间加入池子,再lvextend给LV扩容,整个过程不用卸载分区、不用重启系统。
- 在线缩容:虽然生产环境我强烈不建议对在线文件系统做缩容,但LVM至少在技术层面支持对ext4等文件系统进行缩容操作。
- 灵活组合:多块大小不一的磁盘,通过LVM可以拼成一个大的VG,然后按需切分给不同的业务目录,空间利用率远高于传统固定分区。
接下来,我们就从最基础的pvcreate开始,一路到lvcreate,把这条命令链路完整走一遍。
2. 核心命令实操:pvcreate、vgcreate、lvcreate详解
这一章是全文的重头戏。我会把三个命令的适用对象、参数含义、典型使用场景逐一拆解,同时把实际操作中容易踩的坑全部标出来。
2.1 实操前提与环境准备
在敲任何命令之前,先确认两件事:目标磁盘确实没有被使用,以及分区表状态是否满足LVM需求。
先看一下当前磁盘情况:
[root@localhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 100G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 99G 0 part / sdb 8:16 0 100G 0 disk sdc 8:32 0 100G 0 disk这里sdb和sdc是两块全新的空盘,没分区也没挂载,非常适合用来演示。如果你是给已有分区的磁盘做PV,建议先用fdisk把分区类型改成LVM(Hex code 8e),这个操作很多人容易忽略。
以sdb为例,使用fdisk修改分区类型:
fdisk /dev/sdb进入交互界面后依次输入:
n创建新分区- 一直回车使用默认值
t修改分区类型- 输入
8e表示Linux LVM类型 w保存退出
修改完执行partprobe让内核重新读取分区表:
partprobe2.2 pvcreate:把物理磁盘变成LVM原料
pvcreate的作用,就是把一整块磁盘或一个磁盘分区初始化为LVM的物理卷。
[root@localhost ~]# pvcreate /dev/sdb /dev/sdc Physical volume "/dev/sdb" successfully created. Physical volume "/dev/sdc" successfully created.这一步实际上是往磁盘头部写入LVM元数据(metadata),标记这块磁盘“归LVM管理了”。执行后用pvs或pvdisplay查看:
[root@localhost ~]# pvs PV VG Fmt Attr PSize PFree /dev/sdb lvm2 --- 100.00g 100.00g /dev/sdc lvm2 --- 100.00g 100.00g这里有几个细节值得注意:
- pvcreate可以直接针对整块磁盘,也可以针对分区(比如/dev/sdb1)。直接对整块盘做PV,省去了分区步骤,但后期如果要做LVM之外的操作会麻烦一点。
- PV的元数据默认存放在磁盘开头的特定区域。如果做完PV后,用
pvremove /dev/sdb可以清除元数据、把磁盘恢复成普通状态。 - 执行pvcreate前,务必确认这块磁盘上没有任何业务数据。因为一旦做了PV,原有的分区信息和文件系统结构会被LVM元数据覆盖。
2.3 vgcreate:把物理卷聚合为卷组
有了PV之后,下一步就是把一个或多个PV组合成一个VG。
[root@localhost ~]# vgcreate vg_data /dev/sdb /dev/sdc Volume group "vg_data" successfully created这里vg_data是我给卷组起的名字,命名规则和普通变量类似,建议起得有意义——比如按用途分,vg_data、vg_log、vg_backup,后期看到卷组名就能知道它服务于哪个业务。
创建后用vgs或vgdisplay查看:
[root@localhost ~]# vgs VG #PV #LV #SN Attr VSize VFree vg_data 2 0 0 wz--n- 199.99g 199.99gVG原始容量是200G,因为LVM自身会占用少量元数据空间,所以显示199.99G,正常现象。
关于vgcreate,最重要的一个参数是-s,即PE大小:
[root@localhost ~]# vgcreate -s 16M vg_data /dev/sdb /dev/sdcPE大小直接决定了VG里空间分配的最小粒度。如果不指定,默认是4MB。什么场景需要调整呢?比如你的VG特别大,单个LV动辄几十TB,用默认4M的PE会导致LV内部的“块数量”巨大,可能带来一定性能损耗,此时可以把PE调大,比如16M或32M。相反,如果空间规划很细碎、经常要做小容量分配,就保持4M甚至更小。
注意:PE大小一旦确定,后期无法直接修改。想改只能重建VG,所以创建VG前务必想清楚。
2.4 lvcreate:从卷组切割逻辑卷
VG创建完成后,就可以用lvcreate从VG中切出LV了。
2.4.1 按容量创建
最直观的用法是按指定容量创建:
[root@localhost ~]# lvcreate -L 20G -n lv_data1 vg_data Logical volume "lv_data1" created.-L 20G表示创建20G大小的逻辑卷,-n lv_data1指定逻辑卷名字。创建后设备路径是/dev/vg_data/lv_data1,也可以通过/dev/mapper/vg_data-lv_data1访问。
2.4.2 按PE数量创建
如果需要更精细地控制空间,可以改用-l参数,指定从VG中分配多少个PE:
[root@localhost ~]# vgdisplay vg_data | grep "Total PE" Total PE 12799 [root@localhost ~]# lvcreate -l 1280 -n lv_data2 vg_data如果PE大小是16M,1280个PE就恰好是20G。还有一种更省心的写法:直接按百分比分配:
[root@localhost ~]# lvcreate -l 30%VG -n lv_data3 vg_data这条命令表示从VG总空间里取30%给新LV,非常适合不确定VG具体容量、只想按比例分配的场景。
2.4.3 跨PV分配的行为
当VG里有多块PV时,lvcreate默认会在多块PV上“摊开”分配空间。比如上面创建的lv_data1,它的空间可能一部分落在sdb上、一部分落在sdc上,这种特性天然实现了类似RAID0的条带化写入,提升了I/O性能,但物理上任何一块磁盘故障都会导致LV不可用。
如果想尽量把某个LV的空间留在同一块PV上,可以用-C y参数开启连续分配策略,但代价是可能浪费其他PV上的空间。实际生产中,除非你这个VG本身就是由多块数据盘组成、且业务能容忍单盘故障风险,否则不必过度纠结这个细节。
2.5 格式化与挂载
LV创建成功并不代表可以直接使用,还需要格式化文件系统并挂载:
[root@localhost ~]# mkfs.xfs /dev/vg_data/lv_data1 [root@localhost ~]# mkdir /data1 [root@localhost ~]# mount /dev/vg_data/lv_data1 /data1想让重启后自动挂载,把下面这行写入/etc/fstab:
/dev/vg_data/lv_data1 /data1 xfs defaults 0 0如果你用的是ext4文件系统,创建命令对应
mkfs.ext4。xfs和ext4在后续扩容操作上有区别,这个下文会有详细说明。
3. 实战演练:从两块裸盘到业务挂载的完整链路
这一章我以一台测试服务器为例,模拟真实业务场景:新加两块300G磁盘,需要做成LVM,最终挂载给一个文件服务目录使用,并且预留扩展能力。
3.1 环境规划与磁盘准备
业务需求:给一个图片上传服务准备存储目录,当前预计需要200G,但后续可能迅速增长,要求能在线扩容。
操作思路:两块300G磁盘都加入LVM,创建一个VG,先给业务分配200G的LV,剩余空间留作后续扩容池。
检查磁盘状态:
[root@localhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 300G 0 disk sdb 8:16 0 300G 0 disk两块盘都是裸设备,直接创建PV:
[root@localhost ~]# pvcreate /dev/sda /dev/sdb [root@localhost ~]# pvs PV VG Fmt Attr PSize PFree /dev/sda lvm2 --- 300.00g 300.00g /dev/sdb lvm2 --- 300.00g 300.00g3.2 创建VG并制定PE大小
考虑到后续要频繁创建LV且业务容量跨度较大,我把PE设置为16M:
[root@localhost ~]# vgcreate -s 16M vg_images /dev/sda /dev/sdb [root@localhost ~]# vgdisplay vg_images --- Volume group --- VG Name vg_images System ID Format lvm2 Metadata Areas 2 Metadata Sequence No 1 VG Access read/write VG Status resizable MAX LV 0 Cur LV 0 Open LV 0 Max PV 0 Cur PV 2 Act PV 2 VG Size 599.98 GiB PE Size 16.00 MiB Total PE 38399 Alloc PE / Size 0 / 0 Free PE / Size 38399 / 599.98 GiB注意到PE Size已经是16MiB,Total PE是38399个,这意味着后续所有LV空间分配都是以16M为最小单位展开的。
3.3 创建LV并初始化文件系统
为业务创建200G的逻辑卷:
[root@localhost ~]# lvcreate -L 200G -n lv_upload vg_images Logical volume "lv_upload" created.查看LV状态:
[root@localhost ~]# lvs LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert lv_upload vg_images -wi-a----- 200.00g格式化并挂载:
[root@localhost ~]# mkfs.xfs /dev/vg_images/lv_upload [root@localhost ~]# mkdir /srv/upload [root@localhost ~]# mount /dev/vg_images/lv_upload /srv/upload [root@localhost ~]# df -h /srv/upload Filesystem Size Used Avail Use% Mounted on /dev/mapper/vg_images-lv_upload 200G 33M 200G 1% /srv/upload到这里,一条从裸盘到业务可用存储的完整链路就跑通了。
3.4 在线扩容:文件系统增长的关键操作
图片服务跑了一周,200G快用完了。现在需要把lv_upload扩容到300G,全程不卸载文件系统。
第一步,扩展LV本身:
[root@localhost ~]# lvextend -L +100G /dev/vg_images/lv_upload Size of logical volume vg_images/lv_upload changed from 200.00 GiB (12800 extents) to 300.00 GiB (19200 extents). Logical volume vg_images/lv_upload successfully resized.第二步,扩容文件系统。这一步必须根据文件系统类型区别对待:
- xfs文件系统使用
xfs_growfs:
[root@localhost ~]# xfs_growfs /srv/upload- ext4文件系统使用
resize2fs:
[root@localhost ~]# resize2fs /dev/vg_images/lv_upload执行后再看df -h,会发现文件系统已扩容到300G,业务无感知。这就是LVM在生产环境最核心的价值。
注意:xfs文件系统只支持扩容不支持缩容,ext4虽然支持缩容,但强烈不建议在生产环境对在线缩容,风险极高。
3.5 卷组扩容:VG空间不够时怎么办
如果整个VG的空间都不够了,比如上面的ve_images已经用了450G,剩余150G不够业务下一个阶段的扩容需求,就需要往VG里加新磁盘。
假设新加了一块500G磁盘sdc:
[root@localhost ~]# pvcreate /dev/sdc [root@localhost ~]# vgextend vg_images /dev/sdc [root@localhost ~]# vgs VG #PV #LV #SN Attr VSize VFree vg_images 3 1 0 wz--n- 1.07t 620.00g之后继续lvextend按需扩容即可,整个过程链条非常顺。
4. 常见问题与排查技巧实录
这一章的内容是我多年运维生涯里积累的经验合集。看起来都是小问题,但在生产环境出问题时,每一个都可能让人抓狂。
4.1 删除顺序与残留清理
LVM设备删除顺序必须严格遵循“先LV、再VG、最后PV”,不能乱来。
正确删除流程:
# 1. 卸载LV挂载点 umount /srv/upload # 2. 删除LV lvremove /dev/vg_images/lv_upload # 3. 删除VG vgremove vg_images # 4. 删除PV pvremove /dev/sda /dev/sdb如果直接执行pvremove而VG还引用着该PV,系统会报PV仍被VG使用,阻止删除。这是LVM的保护机制,不要把报错当成故障。
4.2 千万别在挂载状态下删LV
我见过一个真实案例:某同事直接对挂载中的LV执行lvremove,以为空出空间就好,结果删完发现文件系统彻底损坏,数据没法恢复。LVM虽然会尝试阻止删除已挂载的LV,但在某些版本、某些文件系统状态下,仍然可能造成不可逆转的数据丢失。
一定要先确认umount成功、lsof确认无进程占用,再做删除操作。
4.3 重启后卷不认了
系统重启后,发现VG不在了、LV挂载不了,连/dev/vg_images/lv_upload路径都不存在。这种情况大概率是LVM元数据没有被正确扫描到。
先用pvscan扫描所有磁盘的PV:
[root@localhost ~]# pvscan PV /dev/sda VG vg_images lvm2 [300.00 GiB / 300.00 GiB free] PV /dev/sdb VG vg_images lvm2 [299.98 GiB / 299.98 GiB free]如果发现某块盘没有被PV列表识别,但磁盘上明确做过LVM,可以手动指定设备扫描:
[root@localhost ~]# pvscan --cache /dev/sdc如果因为系统启动顺序问题导致PV设备节点还没创建,LVM通常会在boot阶段自动扫描所有磁盘设备。实在不行,检查一下/etc/lvm/lvm.conf中的filter配置,看是不是把这块磁盘设备过滤掉了。
4.4 卷组满了?先看VG再找LV
遇到“无法创建新LV”或者“lvextend失败”的情况,不要直接怀疑磁盘坏了,先按下面的排查顺序走一遍:
# 1. 看VG总容量和空闲容量 vgs # 2. 看具体PV的空间使用 pvdisplay # 3. 看具体LV的容量 lvs # 4. 看文件系统是否真的满了 df -h很多情况下,VG里还有充足空闲空间,而是某个LV的文件系统容量没跟上。比如LV已经扩容了,但ext4没执行resize2fs,业务就仍然看到旧容量。
4.5 LVM快照功能简述
lvcreate除了创建正常LV之外,还可以为已有LV创建快照:
[root@localhost ~]# lvcreate -L 20G -s -n snap1 /dev/vg_images/lv_upload快照不是备份,它依赖原LV的数据,一旦原数据块发生修改,LVM会先把原数据复制到快照区域。如果快照空间满了,快照就会失效,无法继续提供一致性视图。生产环境做数据库一致性备份前,可以用快照来保证备份文件一致性,但千万别把快照当成长期备份方案。
4.6 磁盘移机后如何恢复VG
当某块PV被换到另一台机器上,只要这块PV之前存在于某个VG中,并且元数据信息完整,可尝试以下流程:
[root@new-host ~]# pvscan [root@new-host ~]# vgscan [root@new-host ~]# vgchange -ay vg_imagesvgchange -ay会激活VG,重新生成LV设备节点,前提是VG内所有PV都能被识别,并且元数据没有损坏。
5. 最后再分享几点实操经验
做LVM管理这么多年,有几个心得体会,写在这里给各位参考:
第一,VG和LV的命名一定要有业务语义。vg_images、lv_upload一眼能懂,但vg01、lv001这样的名字,后期维护时根本想不起它对应哪个业务。生产环境上,一个好的命名习惯能在故障排查时节省大量时间。
第二,不要把PE大小设得过大。我曾经图省事把所有VG的PE都设成64M,结果后面有个业务只需要500M空间,一个PE就占了64M,空间浪费得很心疼。小颗粒度的PE虽然会增加元数据开销,但灵活性更好。生产环境默认的4M其实已经很合理,除非你明确知道为什么要改大。
第三,时刻关注VG剩余空间。LVM的优势在“弹性”,但这个弹性是建立在VG有足够空闲PV空间的前提上。最好的做法是在业务磁盘使用率到达70%时就开始规划扩容,而不是等到磁盘满了才手忙脚乱去加盘。结合计划任务,定期把vgs、df -h的结果汇总一下,给自己的服务器做一个空间趋势基线,你会发现运维压力小很多。
LVM这套工具链并不复杂,核心命令就是pvcreate、vgcreate、lvcreate这三个“三板斧”。真正决定运维水平高低的,往往是对底层原理的理解和那些文档里不会写的实操细节。希望这篇记录能让你少踩几个坑,至少在下次磁盘告警时,能从容不迫地敲出那几行命令。