Linux LVM 逻辑卷管理实战:扩容、快照、迁移全流程
深入讲解 LVM(逻辑卷管理器)的核心概念与生产操作:PV/VG/LV 的创建与管理、在线扩容不停机、LVM 快照备份、瘦配置(Thin Provisioning)、以及跨磁盘数据迁移的完整操作流程。
生产服务器的磁盘迟早要扩容,如果用的是传统分区,扩容意味着停机、数据迁移、重新格式化。LVM(Logical Volume Manager)把物理磁盘抽象为逻辑卷,支持在线扩容、快照备份、跨磁盘迁移——不停机操作是它最大的价值。本文从零开始讲解 LVM 的完整生产运维。
LVM 三层结构
物理磁盘/分区 PV(Physical Volume)
↓ ↓
/dev/sdb pvcreate /dev/sdb
/dev/sdc pvcreate /dev/sdc
↓
VG(Volume Group)← vgcreate
把多个 PV 合并为一个大"池"
↓
LV(Logical Volume)← lvcreate
从 VG 中划出逻辑分区(类似传统分区)
↓
格式化 + 挂载(与普通分区相同)
初始配置:从零建立 LVM
# 假设新加了两块磁盘 /dev/sdb 和 /dev/sdc,各 100GB
# Step 1:创建 PV(初始化物理卷)
pvcreate /dev/sdb /dev/sdc
# Physical volume "/dev/sdb" successfully created.
# Physical volume "/dev/sdc" successfully created.
# 查看 PV
pvs
# PV VG Fmt Attr PSize PFree
# /dev/sdb lvm2 --- 100.00g 100.00g
# /dev/sdc lvm2 --- 100.00g 100.00g
pvdisplay /dev/sdb # 详细信息
# Step 2:创建 VG(卷组)
vgcreate data_vg /dev/sdb /dev/sdc
# Volume group "data_vg" successfully created
# 查看 VG
vgs
# VG #PV #LV #SN Attr VSize VFree
# data_vg 2 0 0 wz--n- 199.99g 199.99g
vgdisplay data_vg # 详细信息(PE大小默认4MB)
# Step 3:创建 LV(逻辑卷)
lvcreate -n app_lv -L 80G data_vg # 固定大小 80GB
lvcreate -n log_lv -l 100%FREE data_vg # 使用全部剩余空间
# 查看 LV
lvs
# LV VG Attr LSize Pool Origin Data%
# app_lv data_vg -wi-a----- 80.00g
# log_lv data_vg -wi-a----- 119.99g
# Step 4:格式化并挂载
mkfs.xfs /dev/data_vg/app_lv
mkfs.xfs /dev/data_vg/log_lv
mkdir -p /data/app /data/log
mount /dev/data_vg/app_lv /data/app
mount /dev/data_vg/log_lv /data/log
# 写入 fstab 永久挂载(用 UUID 更稳健)
blkid /dev/data_vg/app_lv
# /dev/data_vg/app_lv: UUID="abc-123" TYPE="xfs"
echo "UUID=abc-123 /data/app xfs defaults 0 2" >> /etc/fstab
在线扩容(不停机)
这是 LVM 最核心的价值:文件系统挂载状态下扩容。
扩容逻辑卷 + 文件系统
# 场景:/data/app 已用 75GB(app_lv 80GB),需要扩到 150GB
# 先确认 VG 有剩余空间
vgs data_vg
# VG VFree
# data_vg 0
# 如果 VG 剩余空间不足,先加新磁盘扩展 VG
pvcreate /dev/sdd # 新磁盘 100GB
vgextend data_vg /dev/sdd # 把新 PV 加入 VG
vgs data_vg
# VFree: 100.00g ← 有空间了
# 扩容 LV
lvextend -L 150G /dev/data_vg/app_lv # 扩到 150GB
# 或
lvextend -L +70G /dev/data_vg/app_lv # 增加 70GB
# 或
lvextend -l +100%FREE /dev/data_vg/app_lv # 用尽所有剩余空间
# 扩容文件系统(LV 扩了,文件系统还没感知到)
# XFS:只能扩大,不能缩小
xfs_growfs /data/app # 传挂载点,不是设备
# ext4:可扩可缩
resize2fs /dev/data_vg/app_lv # 无需卸载,在线扩容
# 一步完成(-r 参数自动扩容文件系统)
lvextend -r -L +70G /dev/data_vg/app_lv
# 验证
df -h /data/app
# /dev/mapper/data_vg-app_lv 150G 75G 75G 50% /data/app
缩容逻辑卷(有风险,需停服)
# ⚠️ 警告:XFS 不支持缩容,只有 ext4 支持
# 缩容必须先卸载,无法在线操作
# Step 1:卸载
umount /data/app
# Step 2:文件系统检查
e2fsck -f /dev/data_vg/app_lv
# Step 3:先缩文件系统(目标 50GB,留 10% 余量)
resize2fs /dev/data_vg/app_lv 50G
# Step 4:再缩 LV(必须先缩文件系统再缩 LV)
lvreduce -L 50G /dev/data_vg/app_lv
# Step 5:重新挂载
mount /dev/data_vg/app_lv /data/app
# 一步完成(自动缩文件系统+LV)
lvreduce -r -L 50G /dev/data_vg/app_lv
LVM 快照
LVM 快照是 COW(Copy-on-Write)机制:快照创建瞬间完成,修改原数据时才把旧数据复制到快照空间。
# 创建快照(快照空间建议为原 LV 的 20-30%)
lvcreate -s -n app_lv_snap -L 20G /dev/data_vg/app_lv
# 查看快照
lvs -a
# LV VG Attr LSize Origin Data%
# app_lv data_vg owi-aos--- 80.00g 0.00
# app_lv_snap data_vg swi-a-s--- 20.00g app_lv 0.01
# 挂载快照(只读)
mount -o ro /dev/data_vg/app_lv_snap /mnt/snapshot
# 备份快照内容
tar -czf /backup/app-$(date +%Y%m%d).tar.gz -C /mnt/snapshot .
# 或者直接 dd 整个 LV
dd if=/dev/data_vg/app_lv_snap | gzip > /backup/app_lv.img.gz
# 卸载并删除快照(快照只是临时的,用完删掉)
umount /mnt/snapshot
lvremove /dev/data_vg/app_lv_snap
# ⚠️ 快照空间满了会自动失效!监控快照使用率
lvs -o lv_name,lv_size,data_percent
用快照恢复数据
# 场景:误删了文件,快照还在,从快照恢复
# 方法1:挂载快照,复制文件
mount -o ro /dev/data_vg/app_lv_snap /mnt/snapshot
cp /mnt/snapshot/important.conf /data/app/
umount /mnt/snapshot
# 方法2:将快照合并回原 LV(恢复到快照时刻的完整状态)
# ⚠️ 这会丢弃快照后的所有变更!
umount /data/app
lvconvert --merge /dev/data_vg/app_lv_snap
# 如果 LV 正在使用,--merge 会在下次激活时执行
lvchange -an /dev/data_vg/app_lv # 停用
lvchange -ay /dev/data_vg/app_lv # 重新激活(触发合并)
mount /dev/data_vg/app_lv /data/app
瘦配置(Thin Provisioning)
普通 LV 创建时立即占用 VG 空间;Thin LV 是“超配”——声明大,实际按需用。适合虚拟机、容器场景。
# 创建 Thin Pool(存储池,实际占用空间的地方)
lvcreate -T -L 200G data_vg/thin_pool
# 从 Thin Pool 创建 Thin LV(声明 500GB,实际不占)
lvcreate -V 500G --thin -n vm1_disk data_vg/thin_pool
lvcreate -V 500G --thin -n vm2_disk data_vg/thin_pool
lvcreate -V 500G --thin -n vm3_disk data_vg/thin_pool
# 三个 LV 声明了 1500GB,但 Pool 只有 200GB
# 只要实际用量不超 200GB 就没问题
# 查看实际使用率
lvs -a data_vg
# thin_pool data_vg twi-a-tz-- 200.00g 0.00 # Pool 使用率 0%
# vm1_disk data_vg Vwi-a-tz-- 500.00g 0.00 # 声明 500GB,实际 0
# 监控 Thin Pool 使用率(超过 80% 就要扩容)
lvdisplay /dev/data_vg/thin_pool | grep "Data percent"
跨磁盘迁移数据(pvmove)
# 场景:/dev/sdb 硬盘要换掉,上面有数据,不停机迁移
# 查看 /dev/sdb 上有哪些 PE(物理区块)
pvdisplay -m /dev/sdb
# 将 /dev/sdb 上的数据迁移到其他 PV(需要其他 PV 有足够空间)
pvmove /dev/sdb # 迁移到 VG 中任意可用 PV
pvmove /dev/sdb /dev/sdd # 指定迁移到 /dev/sdd
# pvmove 支持在线运行,可以用 -b 后台执行
pvmove -b /dev/sdb
# 查看进度
pvs -o pv_name,pv_pe_count,pv_pe_alloc_count
# 迁移完成后,从 VG 中移除旧磁盘
vgreduce data_vg /dev/sdb
pvremove /dev/sdb # 清除 PV 标记
# 现在可以安全拔出 /dev/sdb 或复用
RAID + LVM 组合
# LVM 自带 RAID 功能(不依赖 mdadm)
# 创建 RAID1 镜像逻辑卷(双副本)
lvcreate --type raid1 -m 1 -L 50G -n safe_lv data_vg
# -m 1 表示 1 个镜像(共 2 份数据)
# 查看 RAID 状态
lvs -a -o lv_name,lv_size,copy_percent,devices
# 创建 RAID5(至少 3 块 PV)
lvcreate --type raid5 -L 100G -n raid5_lv data_vg
常用运维命令速查
# 查看整体 LVM 结构
pvs && vgs && lvs
# 详细报告(所有层级)
pvdisplay
vgdisplay
lvdisplay
# 查看 LV 设备路径
ls -la /dev/mapper/
# data_vg-app_lv → /dev/data_vg/app_lv
# 扫描 LVM(新磁盘接入后)
vgscan && pvscan
# 激活 VG(重启后有时需要手动激活)
vgchange -ay data_vg
# LVM 元数据备份(自动,位于 /etc/lvm/backup/)
vgcfgbackup data_vg
# 从备份恢复 LVM 元数据(磁盘元数据损坏时)
vgcfgrestore -f /etc/lvm/backup/data_vg data_vg
小结
LVM 的核心价值是把存储从“物理约束”解放出来:加磁盘不用停机、扩容文件系统不影响业务、快照让备份从分钟级缩短到秒级。生产中最常用的操作是 lvextend -r(在线扩容)和 lvcreate -s(快照备份)。值得注意的是:XFS 不支持缩容、快照空间需监控不能让它满、pvmove 是磁盘退役的标准姿势而不是 dd。
