Home

LVM事故演练_PV掉线_partial激活与恢复

一、实验背景

在日常运维里,LVM 最有价值的地方不是扩容,而是面对磁盘故障时的可恢复性。

如果一个卷组里有多块 PV,而某个 LV 又跨在这些 PV 上,那么一旦其中一块盘掉线,就会进入一种很典型的事故状态:

  • 卷组还能被识别
  • 但卷组会提示 missing PV
  • 逻辑卷会进入 partial 状态
  • 这时系统通常不能再把它当成“完全正常”的卷来使用

这次演练的目标就是模拟这个过程,并验证:

  1. 如何确认故障范围
  2. 如何执行 partial activation
  3. 如何在磁盘恢复后把卷组拉回正常状态

二、实验环境

实验机信息:

  • 系统:Rocky Linux 9.7
  • 卷组:vg_demo
  • 逻辑卷:lv_app
  • 挂载点:/data/demo

实验前,vg_demo 已经有两块 PV:

  • /dev/sdb1
  • /dev/sdc1

并且 lv_app 已经跨在两块 PV 上。

文件系统类型是 xfs,挂载在 /data/demo

基线检查命令

vgcfgbackup vg_demo                              # 先备份卷组元数据,避免误操作后无法回滚
pvs -o+pv_uuid,pv_attr,vg_name,pv_size,pv_free   # 记录 PV 状态和 UUID
vgs -o+vg_attr,vg_size,vg_free                   # 记录 VG 状态
lvs -a -o+devices,lv_attr,lv_size               # 记录 LV 和设备映射关系
findmnt /data/demo                               # 确认挂载关系
df -hT /data/demo                                # 记录容量和文件系统类型
dmesg | tail -n 20                               # 记录当前内核日志

原始输出摘录

1. 先看一下当前会话环境

[root@localhost ~]# ll
总用量 4
-rw-------. 1 root root 1304  4月 22 15:56 anaconda-ks.cfg

[root@localhost ~]# ll -a
总用量 28
dr-xr-x---.  3 root root  147  4月 22 15:59 .
dr-xr-xr-x. 19 root root  247  4月 22 16:47 ..
-rw-------.  1 root root 1304  4月 22 15:56 anaconda-ks.cfg
-rw-------.  1 root root  943  4月 22 16:57 .bash_history
-rw-r--r--.  1 root root   18 11月  3 01:06 .bash_logout
-rw-r--r--.  1 root root  141 11月  3 01:06 .bash_profile
-rw-r--r--.  1 root root  429 11月  3 01:06 .bashrc
-rw-r--r--.  1 root root  100 11月  3 01:06 .cshrc
drwx------.  2 root root    6  4月 22 15:54 .ssh
-rw-r--r--.  1 root root  129 11月  3 01:06 .tcshrc

这段和 LVM 本身没有直接关系,但它能说明:当时我是在同一个 root 会话里连续完成整套实验的。

2. 备份卷组元数据

[root@localhost ~]# vgcfgbackup vg_demo
  Volume group "vg_demo" successfully backed up.

3. 基线 LVM 状态

[root@localhost ~]# pvs -o+pv_uuid,pv_attr,vg_name,pv_size,pv_free
  PV         VG      Fmt  Attr PSize  PFree PV UUID                                Attr VG      PSize  PFree
  /dev/sda3  rlm     lvm2 a--  62.41g    0  SFgzi0-Uw5r-B9X4-gbcj-YPqg-Awvc-YN7cFf a--  rlm     62.41g    0
  /dev/sdb1  vg_demo lvm2 a--  <5.00g    0  6fyO3k-efYe-36q3-cMqI-ysjn-ldv0-Abp1Sz a--  vg_demo <5.00g    0
  /dev/sdc1  vg_demo lvm2 a--  <5.00g    0  mL8XcA-Q0gB-f4zj-DR3W-UiHv-ZPje-dLgxQi a--  vg_demo <5.00g    0

[root@localhost ~]# vgs -o+vg_attr,vg_size,vg_free
  VG      #PV #LV #SN Attr   VSize  VFree Attr   VSize  VFree
  rlm       1   3   0 wz--n- 62.41g    0  wz--n- 62.41g    0
  vg_demo   2   1   0 wz--n-  9.99g    0  wz--n-  9.99g    0

[root@localhost ~]# lvs -a -o+devices,lv_attr,lv_size
  LV     VG      Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert Devices          Attr       LSize
  home   rlm     -wi-ao---- 19.80g                                                     /dev/sda3(10386) -wi-ao---- 19.80g
  root   rlm     -wi-ao---- 40.57g                                                     /dev/sda3(0)     -wi-ao---- 40.57g
  swap   rlm     -wi-ao---- <2.04g                                                     /dev/sda3(15456) -wi-ao---- <2.04g
  lv_app vg_demo -wi-ao----  9.99g                                                     /dev/sdb1(0)     -wi-ao----  9.99g
  lv_app vg_demo -wi-ao----  9.99g                                                     /dev/sdc1(0)     -wi-ao----  9.99g

4. 挂载和容量

[root@localhost ~]# findmnt /data/demo
TARGET     SOURCE                     FSTYPE OPTIONS
/data/demo /dev/mapper/vg_demo-lv_app xfs    rw,relatime,seclabel,attr2,inode64,

[root@localhost ~]# df -hT /data/demo
文件系统                   类型  容量  已用  可用 已用% 挂载点
/dev/mapper/vg_demo-lv_app xfs    10G  106M  9.9G    2% /data/demo

5. 先看一眼相关内核日志

[root@localhost ~]# dmesg | tail -n 20
[   15.891925] XFS (dm-2): Mounting V5 Filesystem 8d0ced08-930f-4f19-9f02-45959cefb158
[   15.892228] XFS (dm-3): Mounting V5 Filesystem 7119dfab-c5fd-4f70-b8dd-93ad858f838a
[   15.914886] XFS (dm-3): Ending clean mount
[   15.925608] XFS (dm-2): Ending clean mount

基线结果摘要

故障前,系统状态如下:

  • vg_demo 正常
  • lv_app 同时落在 /dev/sdb1/dev/sdc1
  • /data/demo 正常挂载
  • 文件系统显示为 xfs
  • 容量约 10G

这一点非常重要,因为如果 LV 只在单块 PV 上,后面的 partial activation 演练价值就会大幅下降。

三、故障注入:模拟第二块盘掉线

真实生产里,磁盘掉线可能来自:

  • 虚拟化平台热拔盘
  • 存储链路异常
  • 底层设备故障
  • 主机重启后设备枚举变化

本次实验采用最直接的方式模拟掉盘:

echo 1 > /sys/block/sdc/device/delete   # 让内核忘掉 /dev/sdc,模拟磁盘消失

这个命令的作用是让当前内核认为这块磁盘已经不在了。

注意:这是实验命令,不要在生产环境随便执行。

原始故障输出摘录

1. 删除磁盘后先看设备变化

[root@localhost ~]# lsblk -d -o NAME,SIZE,TYPE,MODEL,TRAN
NAME  SIZE TYPE MODEL               TRAN
sda    64G disk Rocky Linux-0 SSD   sata
sdb     5G disk Rocky Linux-1 SSD   sata
sr0  1024M rom  Virtual DVD-ROM [1] sata

这时 sdc 已经不见了。

2. LVM 开始报 missing PV

[root@localhost ~]# pvs -o+pv_uuid,pv_attr,vg_name,pv_size,pv_free
  WARNING: Couldn't find device with uuid mL8XcA-Q0gB-f4zj-DR3W-UiHv-ZPje-dLgxQi.
  WARNING: VG vg_demo is missing PV mL8XcA-Q0gB-f4zj-DR3W-UiHv-ZPje-dLgxQi (last written to /dev/sdc1).
  PV         VG      Fmt  Attr PSize  PFree PV UUID                                Attr VG      PSize  PFree
  /dev/sda3  rlm     lvm2 a--  62.41g    0  SFgzi0-Uw5r-B9X4-gbcj-YPqg-Awvc-YN7cFf a--  rlm     62.41g    0
  /dev/sdb1  vg_demo lvm2 a--  <5.00g    0  6fyO3k-efYe-36q3-cMqI-ysjn-ldv0-Abp1Sz a--  vg_demo <5.00g    0
  [unknown]  vg_demo lvm2 a-m  <5.00g    0  mL8XcA-Q0gB-f4zj-DR3W-UiHv-ZPje-dLgxQi a-m  vg_demo <5.00g    0

[root@localhost ~]# vgs -o+vg_attr,vg_size,vg_free
  WARNING: Couldn't find device with uuid mL8XcA-Q0gB-f4zj-DR3W-UiHv-ZPje-dLgxQi.
  WARNING: VG vg_demo is missing PV mL8XcA-Q0gB-f4zj-DR3W-UiHv-ZPje-dLgxQi (last written to /dev/sdc1).
  VG      #PV #LV #SN Attr   VSize  VFree Attr   VSize  VFree
  rlm       1   3   0 wz--n- 62.41g    0  wz--n- 62.41g    0
  vg_demo   2   1   0 wz-pn-  9.99g    0  wz-pn-  9.99g    0

[root@localhost ~]# lvs -a -o+devices,lv_attr,lv_size
  WARNING: Couldn't find device with uuid mL8XcA-Q0gB-f4zj-DR3W-UiHv-ZPje-dLgxQi.
  WARNING: VG vg_demo is missing PV mL8XcA-Q0gB-f4zj-DR3W-UiHv-ZPje-dLgxQi (last written to /dev/sdc1).
  LV     VG      Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert Devices          Attr       LSize
  home   rlm     -wi-ao---- 19.80g                                                     /dev/sda3(10386) -wi-ao---- 19.80g
  root   rlm     -wi-ao---- 40.57g                                                     /dev/sda3(0)     -wi-ao---- 40.57g
  swap   rlm     -wi-ao---- <2.04g                                                     /dev/sda3(15456) -wi-ao---- <2.04g
  lv_app vg_demo -wi-ao--p-  9.99g                                                     /dev/sdb1(0)     -wi-ao--p-  9.99g
  lv_app vg_demo -wi-ao--p-  9.99g                                                     [unknown](0)     -wi-ao--p-  9.99g

这里的 a-mwz-pn--wi-ao--p- 都是信号,说明卷组已经不再完整。

四、故障现场现象

掉盘后,第一步是观察设备变化和 LVM 状态。

1. 设备消失

lsblk -d -o NAME,SIZE,TYPE,MODEL,TRAN   # 看 /dev/sdc 是否消失

结果里,sdc 不见了,只剩下:

  • sda
  • sdb
  • sr0

这说明故障注入已经生效。

2. LVM 报 missing PV

pvs -o+pv_uuid,pv_attr,vg_name,pv_size,pv_free
vgs -o+vg_attr,vg_size,vg_free
lvs -a -o+devices,lv_attr,lv_size

现场表现非常典型:

  • pvs 提示找不到 sdc1 对应的 PV UUID
  • vgs 提示 vg_demo 缺失 PV
  • lvs 里的 lv_app 属性出现了 p

这里的 p 就是关键:

它表示这个 LV 进入了 partial 状态,也就是“不完整状态”。

3. 挂载点表面上还在

mount | grep /data/demo
df -hT /data/demo

实验里,/data/demo 仍然显示挂载中,容量也还是 10G

这一步很容易误导人。

挂载还在,不等于卷健康。

真正要看的是 pvs / vgs / lvs 的状态,而不是只看 df

五、部分激活:先把还能活的卷拉起来

当卷组缺少一块 PV 时,LVM 不会“自动帮你修复”。

你能做的是先尝试把可用部分激活起来,给后续排障争取时间。

1. 重新扫描卷组

vgscan   # 重新扫描卷组

系统仍然会提示:

  • 找不到缺失 PV 的 UUID
  • vg_demo 缺失 sdc1

但卷组本身还能被识别出来。

2. 执行 partial activation

vgchange -ay --partial vg_demo   # 只激活还能识别的部分

这一步的输出里会看到:

  • PARTIAL MODE
  • Incomplete logical volumes will be processed
  • 1 logical volume(s) in volume group "vg_demo" now active

这说明 LVM 已经尽量把幸存部分拉起来了。

但它不是“修复完成”,只是“先救活现场”。

3. 再次检查 LV 状态

lvs -a -o+devices,lv_attr,lv_size   # 再看 LV 是否还是 partial

这时 lv_app 仍然显示 p,说明它仍然处于缺盘状态。

这正是我们要演示的事故态。

六、恢复磁盘:重新扫描并让 LVM 认回 PV

磁盘掉线后,如果底层硬件或虚拟化平台恢复了,你要做的是重新扫描总线,让系统重新发现设备。

1. 重新扫描 SCSI 总线

for host in /sys/class/scsi_host/host*; do echo "- - -" > "$host/scan"; done   # 扫描所有 host
udevadm settle                                                                # 等待设备节点稳定

这一步的意义是:

  • 让内核重新发现磁盘
  • /dev 下的设备节点重新创建
  • 避免设备还没稳定就继续执行 LVM 命令

原始恢复输出摘录

1. 重新扫描总线后,LVM 重新识别到新设备

[root@localhost ~]# for host in /sys/class/scsi_host/host*; do echo "- - -" > "$host/scan"; done
[root@localhost ~]# udevadm settle
[root@localhost ~]# pvscan --cache
  pvscan[5667] PV /dev/sdb1 online.
  pvscan[5667] PV /dev/sda3 online.
  pvscan[5667] PV /dev/sdd1 online.

这一次恢复后,设备名已经从 sdc 变成了 sdd

这正好印证了前面那句话:设备名会变,PV UUID 才是关键。

2. 恢复卷组

[root@localhost ~]# vgchange -ay vg_demo
  1 logical volume(s) in volume group "vg_demo" now active

[root@localhost ~]# lvs -a -o+devices,lv_attr,lv_size
  LV     VG      Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert Devices          Attr       LSize
  home   rlm     -wi-ao---- 19.80g                                                     /dev/sda3(10386) -wi-ao---- 19.80g
  root   rlm     -wi-ao---- 40.57g                                                     /dev/sda3(0)     -wi-ao---- 40.57g
  swap   rlm     -wi-ao---- <2.04g                                                     /dev/sda3(15456) -wi-ao---- <2.04g
  lv_app vg_demo -wi-ao----  9.99g                                                     /dev/sdb1(0)     -wi-ao----  9.99g
  lv_app vg_demo -wi-ao----  9.99g                                                     /dev/sdd1(0)     -wi-ao----  9.99g

[root@localhost ~]# df -hT /data/demo
文件系统                   类型  容量  已用  可用 已用% 挂载点
/dev/mapper/vg_demo-lv_app xfs    10G  106M  9.9G    2% /data/demo

2. 刷新 LVM 缓存

pvscan --cache   # 刷新 LVM 缓存,重新识别在线 PV

这次实验里,系统重新识别到的磁盘名已经不是原来的 sdc,而是变成了 sdd

这点很关键:

  • 设备名会变
  • PV UUID 才是 LVM 识别的核心
  • 所以排障时不要死盯 /dev/sdc1

3. 正常激活卷组

vgchange -ay vg_demo   # 正常激活卷组

激活后,vg_demo 又回到了正常状态,lv_app 也恢复为完整卷。

七、恢复后验证

恢复完成后,检查三类信息:

1. LVM 状态

lvs -a -o+devices,lv_attr,lv_size   # 确认 LV 已经恢复正常

恢复后结果显示:

  • lv_app 属性不再是 partial
  • 设备映射重新完整
  • 两块 PV 都能被识别

2. 挂载状态

findmnt /data/demo   # 确认挂载还在
df -hT /data/demo    # 确认容量和文件系统状态

实验结果显示:

  • /data/demo 仍然正常挂载
  • 文件系统是 xfs
  • 容量仍然是 10G

3. 内核日志

dmesg | tail -n 50   # 检查是否还有残留 I/O 错误

在这次演练中,掉盘和恢复过程都被内核记录了下来。

恢复后没有继续出现新的 I/O 报错,说明实验闭环完成。

八、这次实验的核心结论

1. 先备份元数据

vgcfgbackup 很重要。

在事故演练或者真实故障里,先留元数据备份再操作,是很好的习惯。

2. 设备名不可靠,UUID 更可靠

掉盘恢复后,磁盘名可能从 sdc 变成 sdd

如果你的排障思路还停留在固定设备名上,很容易误判。

3. partial activation 是救援手段,不是修复手段

vgchange -ay --partial 的作用是:

  • 尽量把还能活的卷拉起来
  • 给你保数据、保现场、保诊断时间

它不会自动修复缺失的 PV。

4. 挂载还在,不代表卷健康

这次实验里,即便 /data/demo 还在挂载,LVM 也已经进入了缺盘状态。

所以生产上不能只看 df,还要看:

  • pvs
  • vgs
  • lvs

5. 故障恢复后要重新验证

不是 vgchange -ay 成功就结束了。

你还要继续确认:

  • LV 是否恢复完整
  • 挂载是否正常
  • 内核是否还报错

九、适合直接复制的排障流程

如果你以后在生产里遇到类似情况,可以先按这个顺序查:

pvs -o+pv_uuid,pv_attr,vg_name,pv_size,pv_free   # 看哪个 PV 掉了
vgs -o+vg_attr,vg_size,vg_free                   # 看 VG 是否 partial
lvs -a -o+devices,lv_attr,lv_size               # 看 LV 是否跨缺失 PV
vgscan                                           # 扫描卷组
vgchange -ay --partial <vg_name>                 # 尝试部分激活
dmesg | tail -n 50                               # 看底层 I/O 错误

如果设备恢复:

for host in /sys/class/scsi_host/host*; do echo "- - -" > "$host/scan"; done
udevadm settle
pvscan --cache
vgchange -ay <vg_name>

十、总结

这次演练比单纯扩容更接近真实事故场景。

它告诉我们三件事:

  1. LVM 的故障判断要看元数据状态,不是只看挂载点
  2. 设备恢复后,设备名可能变化,排障不能依赖固定路径
  3. partial activation 的意义是“先救现场”,不是“自动修复”

如果你在生产上做 LVM 运维,这类演练非常值得做一遍。

因为真正出事时,最值钱的不是扩容命令,而是你能不能在缺盘状态下快速判断、快速止损、快速恢复。

Linux LVM 存储 虚拟化