接到一个朋友的求助,说他们公司一台跑着核心业务数据库的服务器,/data分区眼看就要满了。按照传统做法,要么停机加硬盘、重新分区、再把数据拷过去,要么就得冒着风险在线上动刀。他们问我有没有什么办法能"不动声色"地把空间腾出来、甚至把磁盘越用越大。我说,这种情况我碰过太多次了,答案基本是同一个:在 Linux 下做存储管理,LVM(Logical Volume Manager)就是为这种场景而生的。
我最早接触 LVM 的时候也觉得它不过是个"逻辑卷管理工具",直到有一次生产环境磁盘告警,我在线把一块新硬盘加进卷组、扩了逻辑卷、文件系统也跟着变大,整个过程业务零中断,我才真正意识到这层抽象的价值有多大。这篇内容不是 LVM 文档的翻译稿,是我这些年在一堆 Ubuntu、CentOS、Rocky Linux 服务器上折腾 LVM 攒下来的实操经验。不管你是刚入行的运维、还在啃 Linux 基础的学生,还是被"磁盘满"折磨过的开发者,读完你应该能自己上手把 LVM 用起来,并且知道哪些坑不能踩。
1. 为什么传统分区方案越来越不够用:LVM 解决的核心矛盾
1.1 传统分区的三个死穴
在聊 LVM 之前,得先搞清楚它到底解决了什么问题。大多数人刚接触 Linux 时,磁盘管理就是fdisk分个区、格式化、挂载,完事。这种方案在磁盘规划很简单的时候没毛病,但一旦服务器跑久了,你一定会撞上这三个问题:
- 分区大小定死,扩容等于搬家。你装系统的时候给
/home分了 200GB,三年后数据涨到 250GB,然后呢?传统分区是不能在线扩的,你得找一块新磁盘,把数据原样拷过去,再改挂载点。如果你的数据有几百 GB,这个迁移过程不仅耗时,而且中间任何一个环节出错,数据就全交代了。 - 多个磁盘的空间是割裂的。服务器上插了四块 500GB 的盘,传统做法是分成
/data1、/data2、/data3、/data4四个挂载点,某个目录不够用了,别的目录再空也帮不上忙,因为不同分区之间没法"借"空间。 - 单块磁盘容量有上限,不能随便"拼接"。如果你跑的是一个视频存储服务,单块 500GB 磁盘放不下一个 1.2TB 的文件,那就只能靠 RAID 或者存储服务器,成本一下子上去。
1.2 LVM 的本质:在物理磁盘和文件系统之间加一层"蓄水池"
LVM 的思路说起来其实很朴素:不要直接把文件系统架在磁盘分区上,中间加一层逻辑层。这一层逻辑层把物理磁盘(或者分区)先收编成一个个物理卷(Physical Volume,PV),再把多个物理卷合并成一个大卷组(Volume Group,VG),最后从卷组里切出你想要大小的逻辑卷(Logical Volume,LV),文件系统就建在逻辑卷上。
打个比方,传统磁盘分区就像你去租了几间固定大小的房间,客厅 20 平,卧室 15 平,中间有堵墙,客厅想摆个大沙发但是放不下,卧室却空着。LVM 相当于先让你把一整层楼的面积合并成一个总空间,然后你想隔出多大的客厅就用隔板隔多大,想给客厅大一点,就把隔板往外推一点。关键区别在于:LVM 的隔板可以在业务跑着的时候随意挪动,而且只要整个卷组还有剩余空间,你随时能扩大逻辑卷。
这种设计带来了几个直接收益:
- 在线扩容:不需要停机,不需要卸载分区,文件系统跟着逻辑卷一起变大。
- 跨磁盘聚合:四块盘合成一个卷组,你再也不用纠结数据放
/data1还是/data4,就一个逻辑卷,空间池子统一调度。 - 灵活缩容(部分文件系统支持):空间规划错了也能往回缩。
- 快照能力:LVM 自带的 copy-on-write 快照,备份数据库的时候尤其好用,这个后面单独讲。
所以很多生产环境装系统的时候会刻意把/和关键数据目录放在 LVM 上,不是为了炫技,是为了给未来留余地。
2. LVM 的核心抽象与日常巡检:PV、VG、LV 如何协同工作
2.1 三个层级的一条数据链
LVM 整个体系可以看成一条流水线,数据从物理层到逻辑层要经过三层加工:
第一层:物理卷(PV)。它可以是整块磁盘(比如/dev/sdb),也可以是磁盘上的一个分区(比如/dev/sdc1)。把磁盘初始化为 PV,相当于在磁盘头部写入了 LVM 的元数据标记,告诉系统"这块区域归 LVM 管了"。同一个 PV 里,空间按固定大小切成很多个小块,这个块叫PE(Physical Extent),默认大小 4MiB。PE 就相当于物理存储器的最小单位。
第二层:卷组(VG)。卷组是多个 PV 组成的一个大资源池。把一个 PV 加进 VG,相当于把这个物理卷上所有 PE 都投进池子。VG 没有固定的物理位置,它只是逻辑上的聚合。你可以在一个 VG 里看到来自不同磁盘的多个 PV。
第三层:逻辑卷(LV)。卷组建好之后,你从池子里按 PE 个数切出逻辑卷。逻辑卷对上层系统来说就像一块全新的磁盘,你可以对它mkfs、mount,甚至可以再分区(一般不建议)。LV 的大小同样按 PE 算,lvcreate -l 100%FREE就是"把卷组里所有空闲 PE 都划给这个 LV"。
这几个概念对应到常用命令上就是三件套:
pvs/pvdisplay:查看物理卷状态,确认有没有 PV 处于 missing 或 degraded 状态。vgs/vgdisplay:查看卷组总容量、剩余空闲量。做扩容前先跑这个,心里就有底了。lvs/lvdisplay:查看逻辑卷大小和路径,以及对应的 VG 名。
我平时巡检存储,基本就是依次跑这三个命令,看状态字段是不是正常。很多故障在爆发之前,pvdisplay里就会先出现异常状态,早发现早处理。
2.2 为什么 PE 大小值得被关注
PE 默认 4MiB,大多数场景不用改。但在某些极端场景下,PE 大小会影响上限。PE 数量是用 32 位整数存储的,如果 PE 设得太小(比如 1MiB),而磁盘特别大(超过 2TB),可能因为 PE 数量太多触发上限。反过来,如果你把 PE 设成 64MiB,小空间切分会很粗糙——卷组的可用空间可能余出几十 MiB 用不上。
所以我的建议是:默认 4MiB 起步,遇到超大存储池(几十 TB 以上)再考虑调大 PE 大小,或者干脆重新规划存储架构。绝大多数中小企业服务器,4MiB 完全够用。PV 元数据丢失的问题(印象里遇到过)也在这一层,元数据里面有 VG 和 LV 的组成关系,丢了就相当于卷组的"户口本"没了,后面恢复会很费劲,这一点到故障章节详细聊。
2.3 命令输出怎么看:一个实际巡检例子
假设你登上一台服务器,执行vgs,看到类似输出:
VG #PV #LV #SN Attr VSize VFree vgdata 3 2 0 wz--n- 7.28t 2.40t含义是:卷组叫 vgdata,由 3 个物理卷组成,有 2 个逻辑卷,快照数量为 0,总大小 7.28TB,还有 2.4TB 空闲。如果你要扩容,先确认VFree还有多少,再决定是扩 LV,还是要给 VG 再加 PV。这一步是最容易忽略的:很多人直接对 LV 执行 lvextend,结果发现卷组空间不足,扩容失败。顺序永远应该是先看 VG 的 VFree,再看 LV 现状。
3. 从零搭建一套 LVM:物理卷、卷组、逻辑卷的完整创建链路
3.1 准备阶段:哪些发行版自带 LVM,最少需要多大空间
现在主流 Linux 发行版基本都内置了 LVM 相关工具,或者可以通过包管理器快速安装。Debian/Ubuntu 上是lvm2这个包,RHEL/CentOS/Rocky 上默认就带,就算没带,yum install -y lvm2也能装上。在开始之前,先确认系统里有没有pvcreate命令:
which pvcreate如果没有任何输出,说明 lvm2 没装。CentOS/RHEL 系:
sudo yum install -y lvm2Ubuntu/Debian 系:
sudo apt update && sudo apt install -y lvm2装完之后建议插上一块新硬盘,或者找一台测试虚拟机做实验。我建议新手测试时给虚拟机加一块 20GB 的虚拟磁盘,避免误操作影响系统盘。创建 LVM 不需要把整块盘都用了,你可以只划一个分区给 LVM,也可以用整块盘。
3.2 创建物理卷:pvcreate 这一步背后的写入动作
假设你的测试盘在系统里识别为/dev/sdb。先确认磁盘状态:
lsblk fdisk -l /dev/sdb如果是一块全新盘,没有任何分区表,可以直接对整个盘创建 PV:
sudo pvcreate /dev/sdbpvcreate执行的时候实际上会在磁盘开头写入 LVM 元数据,并扫描整块磁盘,把可用空间划分成 PE。执行完之后用pvs确认:
sudo pvs输出里/dev/sdb应该出现在列表里,PV Size 大约 20GB。
如果你不想用整块盘,而是想先在盘上建一个分区再初始化成 PV,步骤是:
sudo fdisk /dev/sdb在 fdisk 里选择n新建分区,t改分区类型为8e(Linux LVM),w写入分区表。然后:
sudo pvcreate /dev/sdb1我自己更推荐整块盘直接做 PV,一是省去分区表这层,二是未来如果要换盘,直接把整块盘从 VG 里移除,数据用pvmove迁走,新盘加进去就行,不用重新折腾分区。但有些场景,比如你想让一块盘上同时存在普通分区和 LVM 分区,那就需要分区了。
3.3 创建卷组:vgcreate 命名规范与容量规划
有了 PV 之后,接下来把它收进卷组:
sudo vgcreate vgdata /dev/sdbvgdata这个名字你可以按业务起,比如数据库服务器就叫vgmysql,日志服务器就叫vglog,这样以后看到 LV 路径也能一眼对应上业务。如果你有两块以上的盘想合并,创建 VG 的时候可以直接把多个 PV 写在后面:
sudo vgcreate vgdata /dev/sdb /dev/sdc这条命令执行完,你用vgs或者vgdisplay能看到卷组的总容量约等于两块盘之和,VFree 也是这个值。
这里有个很多人不知道的细节:卷组创建完之后,默认也会划定 PE 大小。你可以通过-s参数指定:
sudo vgcreate -s 16M vgdata /dev/sdb虽然默认 4MiB 在大多数情况下够用,但在做一个超过 5TB 的存储池时,我会把 PE 调大一点,减少元数据开销。这个属于规划层面的细节,你了解一下即可,不用死记默认值。
3.4 创建逻辑卷并格式化挂载:lvcreate 的各种常用参数
卷组就绪,现在从中切出逻辑卷。假设我想创建一个 10GB 的逻辑卷给数据库用:
sudo lvcreate -L 10G -n lvdata vgdata这条命令的意思是从vgdata卷组里切 10GB,逻辑卷名字叫lvdata。逻辑卷创建后会在系统里生成一个设备节点,路径通常是/dev/vgdata/lvdata(即/dev/卷组名/逻辑卷名),同时也会有一个镜像路径/dev/mapper/vgdata-lvdata。
我习惯用-l 100%FREE来直接把卷组的全部剩余空间划给逻辑卷,这样省心:
sudo lvcreate -l 100%FREE -n lvdata vgdata创建完逻辑卷,它还是一块"空白的逻辑磁盘",需要格式化文件系统才能用。比如用 ext4:
sudo mkfs.ext4 /dev/vgdata/lvdata或者 xfs(CentOS/RHEL 7+ 默认文件系统):
sudo mkfs.xfs /dev/vgdata/lvdata然后挂载:
sudo mkdir -p /data sudo mount /dev/vgdata/lvdata /data3.5 开机自动挂载:fstab 里最容易踩的坑
手动mount只在当前会话生效,服务器一重启就丢了,所以必须把挂载信息写进/etc/fstab。用blkid查逻辑卷的 UUID:
sudo blkid /dev/vgdata/lvdata然后编辑/etc/fstab,添加一行:
UUID=xxxx-xxxx-xxxx /data ext4 defaults 0 2这里有个我踩过很多次的坑:fstab 里千万不要直接用/dev/vgdata/lvdata这种路径,要优先用 UUID。因为 LVM 设备在系统启动时的设备名顺序可能会变化,一旦系统恰好在 LV 激活之前去读 fstab,而设备路径又对不上,很容易进入 emergency mode。用 UUID 能避免绝大多数这种情况。
写完 fstab 后,别急着重启,先执行一次验证:
sudo mount -a这个命令会重新读取 fstab 并尝试挂载所有条目,没有任何报错基本就稳了。我还习惯加一条:
sudo findmnt --verify --verbose用 findmnt 检查 fstab 的语法和挂载点是否存在,这个命令比mount -a更严格一些,能提前暴露潜在问题。
4. 在线扩容与缩容:我在不停机的情况下调整磁盘的完整过程
4.1 三种扩容场景的判断方法
LVM 最大的卖点就是在线扩容。但扩容之前你要先判断自己属于哪种场景:
场景 A:卷组还有空闲空间(VFree > 0)。这种情况最简单,直接在现有 LV 上执行扩展即可。场景 B:卷组没有空闲空间,但机器上还有未使用的磁盘。要先对磁盘建 PV,再vgextend把新 PV 加入卷组,之后才能扩 LV。场景 C:卷组没有空闲空间,机器上也没有闲置磁盘。那就得评估是否有不重要的数据可以缩容,或者直接加新盘。
我在生产环境遇到最多的是场景 B,因为最初规划存储时预留的空间往往不够,业务增长比预期快,只能不断加盘。
4.2 扩展卷组:vgextend 一个命令让新盘加入池子
假设服务器新插了一块 20GB 的磁盘,系统识别为/dev/sdd。先初始化 PV,再扩展卷组:
sudo pvcreate /dev/sdd sudo vgextend vgdata /dev/sdd执行vgs确认:
VG #PV #LV #SN Attr VSize VFree vgdata 4 2 0 wz--n- 9.77t 4.88t你会发现#PV从 3 变成 4,VSize 和 VFree 都变大了。到这一步,卷组资源池已经扩容完成,但逻辑卷的大小还没有变化,你需要继续下一节的操作。
4.3 扩展逻辑卷与文件系统:lvextend + resize2fs / xfs_growfs
当卷组有足够空间后,假设我想把lvdata从 10GB 扩展到 20GB:
sudo lvextend -L 20G /dev/vgdata/lvdata如果你想直接扩满所有剩余空间:
sudo lvextend -l 100%FREE /dev/vgdata/lvdata这里必须注意一个顺序问题:先扩逻辑卷,再扩文件系统。如果你先扩文件系统再扩 LV,文件系统根本不知道底层变大了。
扩展文件系统分两种情况:
- ext4 文件系统:
sudo resize2fs /dev/vgdata/lvdata- xfs 文件系统:
sudo xfs_growfs /data注意 xfs 的扩展命令参数是挂载点,不是设备路径。而且 xfs 是支持在线扩大的,不用担心业务中断。执行完之后用df -h验证,你会发现/data的容量已经变成 20GB 了。
有人可能会问:为什么 ext4 用 resize2fs 传设备路径,xfs 用 xfs_growfs 传挂载点?因为 xfs 在设计上强调对挂载状态的管理,它希望在已经挂载的文件系统上原地扩展,而 ext4 的 resize 工具更偏向独立操作块设备。这不是什么坑,就是两个文件系统的设计差异,记住口诀就行:ext4 用 resize2fs 跟上设备,xfs 用 xfs_growfs 跟挂载点。
4.4 缩容的正确顺序与 xfs 的"禁区"
扩容讲完了,但有些场景是要缩容的,比如你之前规划给某个 LV 的空间太多,需要切一部分给另一个更紧急的业务。缩容的规则和扩容正好相反:先缩文件系统,再缩逻辑卷。顺序搞反了,数据直接损坏。
ext4 缩容步骤:
# 先卸载(生产环境慎用,尽量安排停机窗口) sudo umount /data # 检查文件系统 sudo e2fsck -f /dev/vgdata/lvdata # 缩文件系统到 8G sudo resize2fs /dev/vgdata/lvdata 8G # 再缩逻辑卷到 8G sudo lvreduce -L 8G /dev/vgdata/lvdata # 重新挂载 sudo mount /dev/vgdata/lvdata /data这里有几个必须强调的注意点:
- 缩容必须卸载文件系统,不能在线缩容 ext4。xfs 文件系统完全不支持缩小,这是 xfs 的设计决策,它假设存储只会增长,缩了会导致文件系统损坏。你在网上看到有人 xfs 缩容成功了,那多半是把 LV 先缩小后强制重建文件系统,数据已经没了。
- e2fsck 不是可选项。缩容之前必须检查文件系统,否则
resize2fs会拒绝操作。你没检查硬缩,轻则命令失败,重则文件系统元数据错乱。 lvreduce的时候,务必保证给 LV 设定的大小不小于文件系统已经缩到的大小。比如文件系统缩到了 8G,LV 也缩到 8G,这是匹配的;如果你把 LV 缩到 6G,文件系统没缩到位,那一部分文件系统数据就留在 LV 外面的空间里,等于数据被抛弃了。
4.5 一条完整的扩容实战日志(可复制)
为了让你更有体感,我贴一条我在测试机上完整跑通的扩容流程,方便你当成操作清单:
# 1. 查看现状 lsblk df -h /data vgs # 2. 加入新硬盘 pvcreate /dev/sde vgextend vgdata /dev/sde # 3. 确认扩容后的卷组空间 vgs # 4. 扩展逻辑卷到 50G(假设原来 30G) lvextend -L 50G /dev/vgdata/lvdata # 5. 扩展文件系统(xfs 示例) xfs_growfs /data # 6. 验证 df -h /data lvs这套流程我反复执行过很多次,只要卷组空间足够、文件系统类型匹配,基本没有失败的可能。唯一需要警惕的是 fstab 里的 UUID 在扩容后会不会变——不会,UUID 由文件系统生成,扩容不会改变它。
5. LVM 快照:我数据库备份的"后悔药"是怎么工作的
5.1 快照原理:写时复制,不是你想象中的整盘拷贝
LVM 快照是很多运维会忽略但实际很好用的功能。传统备份方式是停机拷贝或者用 rsync 实时同步,都有一个痛点:数据量一大,拷贝时间长,而且数据库在拷贝过程中可能持续写入,导致备份文件不一致。LVM 快照能在秒级创建一个"逻辑卷在某一瞬间的副本",它依赖的是**写时复制(Copy-On-Write, COW)**机制。
原理是这样的:创建快照时,LVM 不会复制所有数据块,而是把自己标记成"快照源 LV 和快照 LV 共享同一份数据"。当源 LV 上有数据块要发生修改时,LVM 会先把旧数据复制到快照区,再写入新数据。也就是说,快照里保存的是那些"即将被改动"的旧版本数据。只要源 LV 的数据没被动过,快照几乎不占额外空间;修改得越多,快照区占用越大。
生活化理解:这就像你拍了一张房间全景照,之后有人往房间里添置新家具,你不会去重拍照片,只需要在照片上贴一张便签记录"这个地方原来没有柜子"。LVM 快照就是这个便签体系。
5.2 创建快照与恢复备份的实际操作
创建快照的命令:
sudo lvcreate -s -n lvdata-snap -L 5G /dev/vgdata/lvdata参数说明:-s表示 snapshot,-n lvdata-snap是快照名,-L 5G是分配多少空间给快照区。快照区空间不是复制源数据,而是用来存放"写时复制"产生的旧数据,所以不需要给到源 LV 那么大。如果源 LV 是 100GB,而备份期间改动不大,5GB 快照可能就够了;但如果改动量很大,快照区会被写满,一旦写满,快照会自动失效并变得不可访问。
快照创建后,它会在/dev/vgdata/lvdata-snap出现一个块设备。你可以直接挂载它来读取某时刻的数据:
sudo mkdir -p /mnt/snap sudo mount -o ro /dev/vgdata/lvdata-snap /mnt/snap挂载之后你看到的就是创建快照那一刻的静态数据。用它备份数据库,步骤通常是:
- 创建快照(比如在凌晨 3 点)。
- 挂载快照。
- 从快照目录把文件拷贝到备份盘,或者直接用
tar打包。 - 卸载快照并删除快照卷:
lvremove /dev/vgdata/lvdata-snap。
这个过程完全不影响业务正常写入源 LV,因为快照只关心"旧数据别丢",新数据照常写。对 InnoDB 这类带 buffer pool 的数据库,创建快照前最好用FLUSH TABLES WITH READ LOCK让数据文件处于一致状态,不过那是数据库层面的讲究,LVM 本身不管这个。
5.3 快照空间耗尽的管理原则
我用快照吃过一次亏:给一个大逻辑卷创建快照之后,因为备份脚本执行时间较长,期间源数据改动超过了快照区容量,结果 LVM 报 "Snapshot is full" 并且自动移除了这个快照。这个错误很容易被忽略,因为业务本身没报错,等你真需要恢复数据时才发现快照已经没了。
所以用快照要养成几个习惯:
- 监控快照区使用率。
lvs输出里有一列Data%就是快照区的占用百分比,超过 80% 就要警惕。 - 创建快照时不要把空间给得恰恰好。源 LV 越大、备份窗口越长、业务写入越频繁,快照区就要越大。宁可多给,不要少给。
- 快照生命周期要短。快照不是永久存储方案,用完就删,长时间挂着一个快照会持续积累 COW 数据,最后占据大量空间。
另外一个冷知识:快照也可以递归创建,就是给快照再拍快照。但绝大多数场景用不到,而且链式快照一旦源被删,恢复逻辑会变得非常复杂,不要给自己找麻烦。
6. 我在生产环境踩过的 LVM 坑:故障排查与修复实录
6.1 坑一:fstab 用设备路径,重启后掉进 emergency mode
这是我刚接触 LVM 时踩过的第一个大坑。当时给一台 CentOS 7 机器加了数据盘并做了 LVM,往/etc/fstab里写挂载行时直接用了/dev/vgdata/lvdata。结果系统重启后进入 emergency mode,屏幕上显示依赖未满足,某个挂载点无法挂载。
排查思路:
- 先看系统日志:
journalctl -xb,里面明确提示 fstab 中某个设备不存在。 - 因为 LVM 卷没被激活(VG 没跑起来),设备节点就不存在,
/dev/vgdata/lvdata这个路径自然也就找不到。 - 解决办法其实很朴素:在 emergency mode 里先把该行注释掉,系统能正常启动,再检查 LVM 服务状态。
但根本解决方法是改成 UUID 挂载,并确保 LVM 服务开机自启。RHEL/CentOS 系默认会启用 lvm2 相关的服务(lvm2-lvmetad.service、lvm2-monitor.service等),Debian/Ubuntu 也类似,所以一般不需要手动干预;但如果你用的是一套精简定制系统,记得确认 lvm2 服务没有被人为禁用。
另外一个经验是:新加 LVM 挂载后,最好有意识地"重启一次看看"再收工,不要因为手动mount成功就以为万事大吉。比起在业务高峰期被紧急呼叫,提前花五分钟验证重启,性价比高得多。
6.2 坑二:xfs 扩容后 df 看不到变化,99% 是忘了扩展文件系统
很多运维在生产环境扩容时会执行:
lvextend -L +10G /dev/vgdata/lvdata然后立刻df -h,发现容量没变,于是以为扩容失败。这个现象太常见了,我在团队里带新人的时候反复强调:lvextend 只是扩展了 LVM 层,文件系统还停留在旧的边界。你得针对具体文件系统执行对应的扩展命令,df才会刷新。
排查方法其实很简单:
lvs如果 lvs 显示 LV Size 已经变大,说明 LVM 层扩展成功;再查文件系统类型:
blkid /dev/vgdata/lvdata如果显示TYPE="xfs",那就跑xfs_growfs;如果是 ext4,就跑resize2fs。到这里问题解决。
这种情况不算故障,但确实是新手最容易卡住的地方。我自己的习惯是把扩容操作封装成一串命令,执行完直接验证,避免"人肉补步骤"。
6.3 坑三:PV 丢失导致卷组降级,如何用 pvmove 恢复
有次一台服务器的一块盘出现坏道,整块磁盘在系统里消失,对应 PV 状态变成了missing。这时候vgs输出 VG 的 Attr 里会出现p(partial)标记,pvs中那个 PV 能看到unknown device:
PV VG Fmt Attr PSize PFree /dev/sdc1 vgdata lvm2 a-- 1.00t 0 [unknown] vgdata lvm2 a-m 1.00t 0这种情况的处理逻辑是:
- 先不要急着做 vgremove 或者其他破坏性操作。只要 VG 里还有一块 PV 活着,并且数据有冗余或者你接受丢失该盘上的数据,可以尝试用
vgreduce --removemissing vgdata把坏 PV 从卷组里移除。但这样做会丢掉那个 PV 上的所有数据,如果你跑了 RAID,这一步其实是安全的;如果不是 RAID,你要评估清楚再执行。 - 如果坏盘还能识别(只是 IO 报错),可以用 pvmove 把数据迁移到好盘上。先
pvcreate一块新盘,vgextend加入卷组,然后执行:
sudo pvmove /dev/sdc1 /dev/sddpvmove会把/dev/sdc1上所有 PE 的数据搬到/dev/sdd,这个过程可以在线进行,但会很耗 IO,生产环境建议放在低峰期执行。
- 迁移完成后,
vgreduce vgdata /dev/sdc1,把空壳 PV 从卷组里移除,再pvremove /dev/sdc1清理 PV 标记。
我在实际处理这类问题时的顺序是:先跑pvs确认哪些 PV 受影响,跑lvs确认哪几个 LV 位于坏 PV 上(如果某个 LV 完全在坏 PV 上,又没有冗余,那数据基本救不回来;如果 LV 是条带化的,或者横跨多个 PV,丢失一部分 PE 也会导致 LV 无法完整访问)。在动手之前,先备份你还来得及备份的数据,这永远是第一优先。
6.4 坑四:误删 LV,数据还有救吗?
还有一种没那么常见但一旦发生就很痛的操作——lvremove删错了逻辑卷。虽然lvremove执行前会交互式确认,但如果你在自动化脚本里用了--force或者直接敲了yes,数据就没了。
LVM 删除 LV 时只是把逻辑卷的映射关系清掉,并把对应的 PE 标记为"空闲"(实际上并没有立刻把数据清零)。理论上可以借助工具扫描并重建元数据,但恢复成功率不是 100%。我自己的经验是:
- 如果误删后马上发现,并且卷组里还没有新的写操作(没有其他 LV 创建、没有大量 IO),立即停机或停业务,用
vgcfgrestore从备份元数据恢复的概率会高很多。 - LVM 元数据默认在 PV 上有备份,在
/etc/lvm/archive/和/etc/lvm/backup/下能看到历史卷组元数据文件。执行vgcfgrestore -l vgdata可以列出可恢复的历史版本。这要求你在删除之前有卷组元数据的归档文件。
关于这条,我的建议其实就一个字:防。删除逻辑卷之前,用lvs和lvdisplay确认路径,不要在脚本里对 LV 做递归删除操作。存储相关的操作,稳妥永远大于效率。
7. 我个人对 LVM 使用的几条经验总结
规划时给 VG 留余量,不要一个 LV 吃掉 100% 空间。即使你当前只需要 300GB,卷组里有 500GB,建议只创建 400GB 的逻辑卷,留下 100GB 作为跑批、日志增长、快照缓冲。真到空间不够了再加盘,总比空间满了再去急急忙忙找盘强。
文件系统选型影响你后续缩容能力。如果预测未来可能需要缩容(比如测试环境、开发环境、按需分配的项目),优先用 ext4;如果是大型生产存储,xfs 的性能和扩展性更有优势,但要接受"不能缩"的约束。两个文件系统我都用过,说实话普通场景差距感知不明显,真正的差异在极端容量和文件数量上。
每次存储变更前看一眼
/etc/lvm/archive/,确认元数据备份存在。LVM 每次更新卷组元数据都会自动归档,这个目录就是你的后悔药仓库。了解它存在,就多一层安全感。不要跳过
pvs、lvs的日常巡检。你可能觉得这些都是"不常用"的命令,但我在处理故障时发现,很多问题的早期信号就是 PV 的状态异常,定期巡检能帮你把危机消灭在萌芽。
LVM 本质上就是一个让你在存储规划上"留有余地"的工具,它不能解决所有问题(比如单盘物理损坏、文件系统本身的逻辑错误),但绝大多数"磁盘空间不够、分区太死、想要更灵活"的场景,它都值得你第一时间想到。希望这篇东西能帮你把 LVM 从"听说过"变成"上手能用、踩坑会绕",也欢迎你在实践中遇到其他蹊跷问题再回来讨论。反正存储这种事,总会有新的坑等着我们。