上周某台测试服务器的磁盘又爆了,df -h一看,/home分区用量100%,业务日志直接卡死。我跑到机器上一查,这台机器的/home当年是直接建在裸盘上的ext4,要扩容就得停机、重新分区、再把数据拷回去,效率极低。而同一机房另一台数据库服务器,当初建时就用LVM做了底层存储,同样的情况我只加了块新盘,敲了几条命令,空间在业务不中断的情况下就划分好了。两相对比,LVM的价值体现得淋漓尽致。
这篇内容就是围绕LVM(Logical Volume Manager,逻辑卷管理器)的基本操作展开的:它到底是什么、能解决什么问题、从零如何创建、日常如何扩容缩容、快照怎么用,以及我在多年维护中踩过的坑。适合刚接触Linux运维的同事、接手服务器管理的同学,以及所有被磁盘分区搞得头疼的开发者。看完你就能上手操作,并且知道每一步为什么会写成这样。
1. 一次磁盘扩容求助:为什么第一个想到的答案是LVM
1.1 非LVM磁盘的扩容困境
先说说没有LVM时遇到磁盘不够用是什么体验。传统的分区方式,比如/dev/sdb1直接格式化ext4挂到/data,这个分区的大小在分区表里是写死的。你不可能随随便便往分区后面“追加”空间,因为相邻的磁盘空间可能已经属于另一个分区或已经是空闲区域但无法在线合并。
真正到生产环境里,分区不够用通常就这几条路:
- 停机维护,把数据备份出来,重新划分分区,再把数据导回去——业务中断时间按小时算。
- 挂一块新盘到别的目录,把业务路径改成新盘位置——应用层面可能不认。
- 用
rsync做增量同步去另一台机器,再切换——本质也是迁移,时间成本更高。
这些方案都不是不能用,但在“在线”“无损”“快速”三个维度上总得妥协。而LVM的诞生就是为解决这个问题:它在物理磁盘和文件系统中间加了一层逻辑抽象,让空间可以像水池蓄水一样,随时往里加、往外抽,文件系统大小跟着动态调整。
1.2 LVM能替我们解决的五个问题
这几年的维护经验中,LVM对我的价值主要集中在五个场景:
- 在线扩容:分区不够了,加块盘,并入卷组,扩展逻辑卷和文件系统,业务不用停机。
- 多盘合并:一块盘不够大,可以把多块盘组成一个卷组,上层看到一个更大的“空间池”,再按需划出逻辑卷。
- 快照备份:创建LVM快照,得到一个几乎不占空间的时间点副本,用于数据库备份前的一致性确认。
- 灵活回收:文件系统空间富余时,可以缩小逻辑卷,把空间腾给其他分区(注意文件系统要支持缩容)。
- 设备抽象:上层用的逻辑卷名称和底层物理磁盘解耦,换盘、拔盘、磁盘顺序变化都不会影响挂载和使用。
你不需要一开始就理解全部机制,只要记住这句话:LVM把“一块一块的物理磁盘”变成了“一个统一调度的空间池”,文件系统不再是直接长在磁盘上,而是长在从这个池子里划出的逻辑卷上。理解了这一层,后面的所有操作就顺理成章了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三件套概念:PV、VG、LV在磁盘管理里各扮演什么角色
开始敲命令前,必须把LVM的三个核心角色搞清楚。很多新人的困惑点就在这里:明明只是加个空间,为什么要分三个层次?我用一个仓库的类比来解释。
2.1 物理卷(PV):相当于入库的原材料
PV(Physical Volume,物理卷)就是一块磁盘或磁盘分区经过pvcreate标记后的状态。你可以理解为把一间库房录入到了仓库管理系统里。系统能看到这间库房的存在、知道它有多大,但它还没有被分配到具体的业务用途上。
创建PV的动作很简单,比如pvcreate /dev/sdb1,但对刚接触的人来说重点是:这一步并不是格式化,不破坏原有数据的逻辑结构(当然如果盘上有数据,还是建议先确认备份)。它只是在磁盘头部区域写入LVM元数据,告诉系统“这块区域现在归LVM管理”。
查看PV状态的命令:
bash复制pvs
pvdisplay
pvs输出简洁,适合日常快速看;pvdisplay输出详细,能看到PV所属的VG等信息。
2.2 卷组(VG):统一仓库的调度中心
VG(Volume Group,卷组)是多个PV组成的一个空间池。还是用仓库类比:单个库房面积有限,但如果把三间库房打通,合并成一间大仓库,就能灵活调度了。VG就是这个被“打通”后的仓库。
创建卷组用vgcreate命令。例如把/dev/sdb1和/dev/sdc合并成一个叫vg_data的卷组:
bash复制vgcreate vg_data /dev/sdb1 /dev/sdc
这里发生的核心变化是:两块盘的空间在LVM层面上被合并了。比如/dev/sdb1是20GB,/dev/sdc是20GB,那vg_data的总容量就是40GB。上层不再关心空间具体来自哪块盘,只看卷组里还有多少空闲。
查看VG状态:
bash复制vgs
vgdisplay
vgdisplay可以看到VG的总大小、已分配空间、空闲空间,以及PE大小和PE数量。PE我们马上讲。
2.3 逻辑卷(LV)与物理扩展块(PE)
LV(Logical Volume)就是从VG这个大仓库里划分出的一个“货架区”,对应系统里的一个块设备。最终文件系统就建在LV上,用户看到的/data目录,本质上是挂载在某个LV上的文件系统。
创建逻辑卷的命令就是lvcreate,后面我会详细演示。这里先补充一个关键概念:PE(Physical Extent,物理扩展块)。
PE是LVM分配空间的最小单位,默认大小为4MB。你可以把它理解为仓库里的标准货箱,所有空间分配都要按货箱的整数倍来。当执行lvcreate -L 10G时,LVM实际做的是从VG中划出10G / 4M也就是2560个PE给这个LV。PE的大小可以在创建VG时用-s参数调整,没有特殊需求一般保持默认4MB即可。PE选的太小,卷组可管理的空间上限会变小、元数据开销变大;选的太大,分配粒度变粗,小空间分配也会吃掉一个完整PE。默认4MB在绝大多数场景够用。
查看LV状态:
bash复制lvs
lvdisplay
把三者连起来记:PV是原材料库房,VG是仓库,LV是仓库里划出的货架区,PE是搬运货物的标准货箱。 文件系统长在LV上,LV从VG里取空间,VG的空间来自PV,这就是LVM的完整链路。
3. 从裸盘到可用文件系统:PV/VG/LV创建全流程
下面进入动手阶段。我用一台虚拟机做演示,给虚拟机新增了两块20GB的磁盘,设备名分别对应/dev/sdb和/dev/sdc。真实生产环境操作思路完全一致,只是设备名要按实际环境确认。这里强烈建议在操作前反复确认磁盘名,一旦认错盘,后面操作的对象错了,数据损失无法挽回。
3.1 环境确认与分区规划
先看系统当前挂载情况与磁盘列表:
bash复制lsblk
fdisk -l
lsblk会列出所有块设备、大小、挂载点。确认新增盘就是/dev/sdb和/dev/sdc后,我先用fdisk给/dev/sdb创建一个分区,分区类型设置为8e(Linux LVM):
bash复制fdisk /dev/sdb
# 交互过程
n # 新建分区
p # 主分区
1 # 分区编号
回车 # 起始扇区默认
回车 # 结束扇区默认
t # 修改分区类型
8e # Linux LVM
w # 写入并退出
分区完成后,/dev/sdb1就是可用的PV载体。那/dev/sdc呢?我故意不做分区,直接整块盘交给LVM。这在实际工作中也有人这么干,但建议生产环境还是分个区更规范,一是分区表里有记录,后续排查更方便;二是如果磁盘上还有其他分区,不会误伤。这里同时演示两种方式容易让人产生疑惑,我明确说:优先选分区后建PV的方式,整盘直接做PV更适合刚测试、临时场景。
3.2 创建PV与VG:把散盘合成池子
执行pvcreate把两个设备变成物理卷:
bash复制pvcreate /dev/sdb1 /dev/sdc
然后创建卷组vg_data:
bash复制vgcreate vg_data /dev/sdb1 /dev/sdc
接下来用vgs查看卷组信息,应该能看到总容量约40GB,空闲也是40GB。用vgdisplay则能看到PE大小和PE总数:
bash复制vgdisplay vg_data
输出中PE Size显示4MB,Total PE显示10239(40G除以4M的向下取整)。这时候盘已经被揉进了一个池子,空间处于未分配状态,等待划分给逻辑卷。
3.3 创建LV并落地文件系统
在卷组vg_data上创建一个名为lv_data的逻辑卷,大小10GB:
bash复制lvcreate -L 10G -n lv_data vg_data
这里解释下参数:-L 10G按容量分配,-l 255则按PE数量分配,两者各有适用场景。日常需求多按容量来,但如果想把VG剩余空间一次全部分给某个LV,直接-l 100%FREE更省心。
创建完成后,逻辑卷对应的设备路径是/dev/vg_data/lv_data,同时也会在/dev/mapper/下生成vg_data-lv_data的链接。接下来格式化并挂载:
bash复制mkfs.ext4 /dev/vg_data/lv_data
mkdir /data
mount /dev/vg_data/lv_data /data
df -h /data
看到/data挂载上且容量为10GB,一个基本的LVM生命周期就走完了。但注意,mount只是临时挂载,重启会失效,必须写入/etc/fstab。
3.4 写入fstab实现开机挂载
写/etc/fstab有个老生常谈的注意点:推荐用UUID而不是设备名,因为设备名在系统重启、磁盘顺序变化时可能漂移。获取UUID的方式:
bash复制blkid /dev/vg_data/lv_data
然后在/etc/fstab末尾加上一行:
code复制UUID=xxxxx /data ext4 defaults 0 2
改完执行mount -a做验证,没有报错再重启测试一下,避免开机直接进emergency模式。这套流程走完,LVM的基本创建链路你已经会了。接下来看最常用的日常操作:扩容和缩容。
4. 扩容与缩容:LVM最核心的日常操作
如果说创建LVM是基本功,那扩容缩容就是它日常发挥价值的主战场。这一章我会按实际运维场景拆解。
4.1 在线扩容场景:从加盘到生效的完整命令链
假设/data当前容量10GB,使用率已经到95%。业务不想停,怎么办?
第一步,确认VG还有多少空闲空间:
bash复制vgs
如果VG空闲足够,直接扩展LV即可。比如扩5GB:
bash复制lvextend -L +5G /dev/vg_data/lv_data
注意+5G的写法表示在现有基础上增加5GB;如果不带+,-L 5G表示直接将LV调整为5GB,两者语义完全不同,生产环境写成+5G更安全。
如果VG空闲不够,就需要先加新盘。假设新盘是/dev/sdd,先分区(操作类似前面),然后:
bash复制pvcreate /dev/sdd1
vgextend vg_data /dev/sdd1
这样vg_data的容量增大了,再回到lvextend步骤。
但千万注意:LV扩了不代表文件系统扩了。文件系统层还停留在原来的大小,df -h看到的不变。必须执行文件系统扩展命令:
bash复制# ext4
resize2fs /dev/vg_data/lv_data
# 或 xfs
xfs_growfs /data
执行完再df -h确认,容量已经变成15GB。整个过程中业务没有中断,文件系统在线完成扩容,这就是LVM最核心的价值。
新版lvextend提供了-r参数,可以自动执行resize2fs/xfs_growfs,但从稳妥角度,我习惯把两步分开,因为一旦自动扩展失败,排查链路多一层;手动分开执行,每一步都有明确输出,哪一步出错一眼就能定位。
4.2 ext4与xfs在扩展时为何要用不同的工具
刚接触LVM的人很容易困惑:为什么lvextend之后,ext4用resize2fs,xfs用xfs_growfs,工具和参数都不一样?
因为文件系统扩展能力取决于工具支持。ext4的resize2fs既可以扩展也可以缩小;xfs的xfs_growfs只能扩展不能缩小,而且输入参数通常是挂载点而不是设备路径。下面是两者的对比:
| 维度 | ext4 | xfs |
|---|---|---|
| 在线扩容 | 支持 | 支持 |
| 在线缩容 | 不支持 | 不支持 |
| 扩容命令 | resize2fs 设备路径 |
xfs_growfs 挂载点 |
| 缩容命令 | resize2fs 需离线执行 |
不支持 |
| 适用场景 | 通用业务、目录服务 | 大文件存储、数据库高吞吐场景 |
这里补充一个信息:ext4的resize2fs在没有指定目标大小时,会自动扩展到文件系统所在块设备的完整容量,所以扩容后只需执行resize2fs /dev/vg_data/lv_data,不用带参数。xfs则必须指定/data挂载点或设备路径,因为它读取的是挂载点对应的信息。
4.3 缩容ext4的完整操作链与风险提示
缩容是LVM操作里风险最高的一环,务必严格按顺序执行。还是以/data为例,假设当前15GB,想缩到8GB,所有操作必须在卸载状态下进行:
bash复制umount /data
e2fsck -f /dev/vg_data/lv_data
resize2fs /dev/vg_data/lv_data 8G
lvreduce -L 8G /dev/vg_data/lv_data
mount /data
逐条解释:
umount先卸载文件系统,避免在线缩容导致文件系统损坏。e2fsck -f强制检查文件系统。缩容前必须确认文件系统状态健康,否则缩了一半遇到坏块,数据基本救不回来。resize2fs /dev/vg_data/lv_data 8G先把文件系统缩小到8GB,注意这里带了目标大小。lvreduce -L 8G /dev/vg_data/lv_data再把逻辑卷缩小到8GB。- 最后重新挂载验证。
顺序绝对不能反。如果先lvreduce缩了LV再缩文件系统,文件系统还以为自己还是15GB,但底层块设备已经只有8GB,数据必然被截断。我见过有人把顺序搞反,最后只能从备份里恢复数据。
需要明确的是:xfs不支持缩容。这要求你在创建文件系统时就想清楚:如果业务分区未来可能要回收空间,优先用ext4;如果确定了只用xfs,缩容这条路就直接堵死了,只能靠迁移数据来重新分配大小。
5. 快照、迁移与备份:LVM的进阶价值
LVM快照是我在数据库备份场景中用过的最可靠工具之一,原理不复杂,但很多人第一用就踩坑,所以单独展开讲。
5.1 COW写时复制:快照为什么占空间很小
创建快照的命令:
bash复制lvcreate -s -L 2G -n snap_data /dev/vg_data/lv_data
这里-s表示创建快照,-L 2G给快照分配2GB空间。很多人不理解,源LV已经10GB,快照才2GB,怎么够用?
这就涉及COW(Copy-On-Write,写时复制)机制。快照刚创建时,并不复制源LV的完整数据,它只是记录了一个状态时间点。之后如果源LV上有数据块被修改,系统在覆盖那块数据前,会先把原始数据复制到快照区域保存。所以快照里保存的是“源LV在快照创建后,又发生了哪些变化的数据副本”。这也意味着:
- 快照空间大小不需要等于源LV大小,只需要覆盖“快照有效期内发生的修改数据量”。
- 如果快照创建后,源LV上一口气修改了超过2GB的数据,快照空间耗尽,快照将自动失效(inactive)。这是快照最坑的地方。
- 快照期间读快照,看到的是创建时刻的数据状态;读源LV,看到的是实时数据。
5.2 用快照做数据库备份前的数据一致性保证
生产环境用快照备份数据库,思路大致是:
- 在应用层做“短暂锁写”,让数据库把脏数据刷到磁盘,保证文件系统层面的数据是完整一致的。
- 执行
lvcreate -s创建快照。 - 立刻解锁,业务恢复。
- 挂载快照到临时目录,进行备份。
演示一下挂载快照并读取内容:
bash复制mkdir /mnt/snap
mount -o ro /dev/vg_data/snap_data /mnt/snap
tar czf /backup/data.tar.gz -C /mnt/snap .
umount /mnt/snap
快照只读挂载,备份过程中源LV持续写入也不影响备份数据的一致性。这比直接在业务在线时拷文件靠谱得多。
5.3 快照回滚与跨机迁移思路
如果源LV数据损坏,想把系统恢复到快照创建时的状态,可以运行:
bash复制lvconvert --merge /dev/vg_data/snap_data
--merge会把快照里的数据合并回源LV。需要注意:合并时源LV必须是未挂载状态,如果挂载着,合并操作会排队等待,在下一次挂载时执行。合并期间绝对不要对源LV做写入,否则数据状态会很混乱。
LVM在跨机迁移场景中的价值也很大。常用思路是:源机器上先对LV做快照,把快照挂载后打包;目标机器创建相同或更大的LV,格式化后解包覆盖。业务停机时间被压缩到最低。
6. 实操中踩过的坑与排查思路
这一章写几个我实际遇到过的问题,每个坑背后都有具体的排查链路,而不是直接甩结论。
6.1 选错盘与漏分区的教训
有个老朋友在现场加盘时,把pvcreate的对象写成了/dev/sdb——但他那台机器的/dev/sdb其实是系统盘。虽然pvcreate本身不会立即破坏数据,但LVM元数据写入后,系统盘的引导信息可能被干扰,重启后进不了系统。这件事的直接教训是:执行任何pvcreate/vgcreate前,先对照lsblk和fdisk -l把设备名认准,有条件再用lvs确认已有环境。另一个原则是,系统盘上的分区不建议纳入LVM管理,保持系统分区独立更安全。
还有一个常见问题是分区类型没设成8e就直接pvcreate。技术上LVM并不强制要求分区类型,但没设置会导致后续保留分区表的人无法从分区信息中判断分区用途,排查灾难时可能多花时间。规范操作还是设一下。
6.2 扩容后文件系统大小没变的排查链路
出现“扩容后df没变”时,很多人第一反应是命令执行失败。用一条条确认:
bash复制# 第一步:确认LV大小
lvs /dev/vg_data/lv_data
# 第二步:如果LV大小正确,确认VG还有没有空闲
vgs
# 第三步:确认文件系统类型
blkid /dev/vg_data/lv_data
# 第四步:执行对应扩展命令
resize2fs /dev/vg_data/lv_data # ext4
xfs_growfs /data # xfs
# 第五步:再次验证
df -h /data
通常问题出在忽略了文件系统扩展这一步。lvextend只动了逻辑卷层,文件系统层不执行扩展命令,df自然不变。另外注意xfs必须指定挂载点,如果写错路径也会一直报错。
6.3 快照被写满失效:一场凌晨的数据库备份事故
一次自动备份作业,快照大小按源LV容量的10%创建,结果在备份当天正好赶上批量任务大量写库,快照空间被写满,状态从active变成inactive,备份脚本直接失败。还好及时发现了数据没有损坏,但那次事故让我记住了两件事:
- 快照容量预估不能按业务数据总量来算,应该按“高峰期写入速度乘以备份预计耗时”来估算。比如源LV写入速度50MB/s,备份需要3分钟,那快照空间至少要留9GB以上的余量。
- 创建快照后,立刻
lvs检查快照状态,确保是active。备份期间也要监控快照空间的使用率,例如用lvs -o +data_percent查看已使用比例。
6.4 拔盘故障后的PV清理与VG修复
磁盘故障或者人为下线一块盘后,系统里会出现PV缺失的状态,VG里对应的PV显示为不完整。处理思路是:
先查看异常状态:
bash复制pvs
vgs
如果VG因为缺失PV处于不完整状态,需要把缺失的PV从VG里移除:
bash复制vgreduce --removemissing vg_data
这一步操作前确认数据安全,因为缺失PV上的数据已经访问不到,--removemissing处理后VG会以剩余PV的容量继续运行。如果只是人为想移除某块盘上的PV,正确姿势是先把数据搬走:
bash复制pvmove /dev/sdd1 # 把sdd1上数据移到同VG其他PV
vgreduce vg_data /dev/sdd1 # 从VG移除
pvremove /dev/sdd1 # 彻底清理PV标记
pvmove期间数据在做物理搬迁,生产环境要预期耗时,并观察pvs -o pv_used的变化确认搬完。
6.5 逻辑卷跨VG扩展的误区
有个场景曾经差点踩雷:两个VG,一个满了,一个空着,想直接把满VG里的LV扩展到空VG上。LVM不支持跨VG扩展逻辑卷,LV只能从单一VG取空间。正确做法要么在同一个VG里加入新盘扩容,要么在新VG上重建LV并把数据迁过去。这个认知能帮你避免很多绕路的操作。
最后再分享一个我在地实际维护中沉淀的小技巧:日常巡检不要只盯df -h,LVM三个层级的状态也要看。我平时会写一个简单的巡检脚本,每天输出pvs、vgs、lvs摘要,并在卷组空闲空间低于20%时提示预警。这样很多扩容需求都是在业务还没受影响时就被提前处理掉了,而不是等磁盘满了才去灭火。LVM基本操作说穿了并不难,难的是把“分层管理”的意识刻进日常运维习惯里,让扩容缩容这类动作真正变成有预案、可回滚的常规操作。
