☰
LVM实战:从pvcreate到lvcreate的磁盘扩容与运维指南
2026/10/14 5:21:23 网站建设 项目流程

接手过一台某公司的报表服务器,挂在/data下的盘满了。好在那台机器一开始就用 LVM 管理磁盘,我拉了块新硬盘,pvcreate初始化物理卷,vgextend把卷组扩大,再lvextend拉长逻辑卷,最后resize2fs同步文件系统,前后十几分钟搞定,业务没停。相比之下,另一台用传统分区部署的机器就没这么幸运了——加盘只能停机、备份、重新分区、迁移数据,折腾了一个通宵。从那次之后,凡是我经手的 Linux 服务器,只要空间规划不是一次性定死的,我都会用 LVM 管理磁盘。这篇就把pvcreate、vgcreate、lvcreate这条完整链路拆开讲清楚,包括我踩过的坑和对应排查方法,适合刚接触 LVM 的运维、开发,也适合给自己服务器做存储规划的人。

1. 为什么我从分区裸盘转向LVM:一次扩容事故的真实复盘

刚开始用 Linux 的时候,我和大多数人一样,安装系统时直接手动分区,/data单独划一个分区,觉得简单直接。后来问题就来了:分区是死的,你规划了 500G,它就永远只有 500G,哪怕同一块磁盘还剩 300G 空闲,分区也没法“借用”到相邻空间。更麻烦的是,跨磁盘合并空间这件事,传统分区根本做不到。

那次事故的背景是这样的:应用写日志和数据都放在/data,当初安装时给了 1TB 分区,结果半年不到就满了。我临时加了一块 500G 的盘,想把它并进/data。传统分区的方案只有一个:先把应用停掉,把 1TB 数据 rsync 到新盘,改挂载点,再重启服务。数据量大,迁移时间长达几个小时,业务方急到直接找上级投诉。整个过程还不敢断电,生怕中断后数据不一致。

后来我学乖了,新服务器一律 LVM。LVM 的逻辑其实很朴素,它把“磁盘空间”这件事拆成三层:

  • PV(Physical Volume,物理卷):对应一块真实磁盘或者一个磁盘分区,相当于“你买来的物理存储”。
  • VG(Volume Group,卷组):一个或多个 PV 组成一个存储池,相当于把所有硬盘空间倒进一个池子里统一管理。
  • LV(Logical Volume,逻辑卷):从 VG 池子里划出来的“虚拟分区”,可以被格式化、挂载、动态调整大小,这层就是最终给系统用的块设备。

用一个生活类比:PV 是你买回来的桶,VG 是你家的蓄水池,LV 则是从水池接出去的管子。传统分区相当于你在装修时直接把水管埋死在墙里,LVM 则是所有管子都从水池总闸引出,随时可以换粗管、加一组新水泵。理解了这个分层,你就明白了pvcreate是把桶带回家,vgcreate是把桶里的水倒进池子,lvcreate是从池子引出一条水管。

两种方案放在一起对比,差距立竿见影:

对比项传统分区LVM
分区容量扩展无法在线扩大,需备份重建支持在线lvextend
跨磁盘合并空间不支持,只能换大盘迁移PV 加入 VG 即可池化
缩减容量工具支持弱,风险高ext4 配合resize2fs可缩
创建快照需要文件系统快照支持LVM 原生快照,秒级创建
性能损耗无几乎可忽略,条带化可优化
运维复杂度低,适合固定规划稍高,需要理解分层概念

我的建议是:如果你的服务器会跑很久、数据会涨、以后大概率要加盘,不要犹豫,直接选 LVM。唯一不适合的场景是“空间永远不变、系统盘引导分区”这种简单固定需求,没必要为了 LVM 而 LVM。

2. 动手前的规划:盘符识别、整盘还是分区、设备名的坑

不要一上来就pvcreate,先搞清楚机器上到底有哪些磁盘、哪些已经被系统占用。

2.1 先看清楚机器上到底有哪些磁盘

最常用的命令是lsblk,它会把真实磁盘和分区关系以树状展示,一目了然:

lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT

输出示例:

NAME SIZE TYPE FSTYPE MOUNTPOINT sda 248G disk ├─sda1 500M part xfs /boot ├─sda2 4G part swap [SWAP] └─sda3 243G part LVM / sdb 500G disk

这个输出很关键:sda是系统盘,已经有 LVM 分区(FSTYPE 显示 LVM),而sdb是一块全新的 500G 裸盘,TYPE 是 disk,下面没有任何分区,也没挂载点。如果只是看某个分区用了多少空间,用df -hT就行,但它看不到“物理层”的设备关系,规划时必须lsblk结合使用。

再配合fdisk -l看磁盘的详细扇区信息,或者用lvmdiskscan让 LVM 自己扫描候选设备:

lvmdiskscan

它会把所有可用的块设备和已被 LVM 占用的设备列出来,很直观。注意:如果某些设备被 LVM 配置文件过滤掉了,lvmdiskscan不会显示,后面pvcreate也会报 “filtered” 之类的错误,这时去/etc/lvm/lvm.conf里看filter配置即可,一般默认不用动。

2.2 整块盘还是分区后做PV:两种方式怎么选

pvcreate可以直接作用在整块磁盘上,也可以作用在磁盘分区上。这两种方式我都用过,区别如下:

  • 整块盘直接做 PV:命令简单,pvcreate /dev/sdb,这块盘 100% 归 LVM 管,以后不用再操心它上面还有别的分区。缺点是如果以后想让这块盘挪作他用(比如拆出一个普通分区放别的东西),还得先把 PV 删掉,比较折腾。
  • 分区后做 PV:先用fdisk或parted把磁盘划分好,再pvcreate /dev/sdb1。好处是灵活,一块盘上可以既有 LVM PV,又有普通分区;坏处是多一步分区操作,而且分区类型必须设置正确。

如果要用传统 MBR 分区表创建 LVM 分区,fdisk交互过程大概是:

fdisk /dev/sdb

依次输入n(新建分区)、p(主分区)、1(分区号)、两次回车(默认起始和结束扇区)、t(改类型)、8e(Linux LVM)、w(写入)。

如果磁盘超过 2TB,或者你用的是 UEFI 启动,就要用 GPT 分区表。用parted操作更顺手:

parted /dev/sdb mklabel gpt parted /dev/sdb mkpart primary 1MiB 100% parted /dev/sdb set 1 lvm on

这里set 1 lvm on是给分区打 LVM 标记。注意,LVM 真正能不能用,取决于pvcreate写入的元数据,分区类型码只是辅助标识。但该标还是标,免得以后自己或者同事看lsblk时一脸懵。

我的习惯是:数据盘直接整块做 PV,系统盘绝不碰 LVM 以外的分区操作。把系统盘纳入 LVM 是可行的,但一旦出问题就是启动失败级别的故障,收益不大,风险不小,建议只在新建机器装系统阶段规划,不要在业务挂了再迁移。

2.3 设备名不会变的误区

这块是最容易翻车的环节。很多人以为/dev/sdb永远对应同一块盘,真实环境里,多块同型号硬盘、主板接口顺序变化、内核识别顺序不同,重启后盘符完全可能变成/dev/sdc或者/dev/sdd。如果 PV 元数据写在/dev/sdb上,盘符漂移后你用vgscan可能找不到卷组,或者更糟,把一个全新空盘当成旧 PV 处理。

保险做法是用固定名称创建 PV:

ls -l /dev/disk/by-id/

输出里能看到每块盘的ata-XXX、nvme-XXX、wwn-XXX这类唯一标识。然后用这个标识去pvcreate:

pvcreate /dev/disk/by-id/ata-WDC_WD5000AADS-00M2B0_ WD-WCC12345678

By-id 名称是硬盘固件层面的标识,不随盘符漂移,比/dev/sdb稳得多。如果你已经用/dev/sdb建好了 PV,问题也不大:把新盘加进来时,一律用 by-id 来操作,并由/etc/fstab里的 UUID 挂载 LV,两层保险都加上。

3. 完整创建流程:从pvcreate到lvcreate一次跑通

这一节是核心实操,按顺序执行即可。我以一个场景演示:新机器上有一块空的sdb(500G),目标是用 LVM 创建一个 300G 的逻辑卷挂到/data,预留 200G 以后扩容用。

3.1 第一步:初始化物理卷(pvcreate)

pvcreate /dev/sdb

如果你前面做了分区,就写/dev/sdb1。正常输出:

Physical volume "/dev/sdb" successfully created.

然后可以用两个命令验证:

pvs pvdisplay /dev/sdb

pvs是精简摘要,pvdisplay是详细信息,能看到 PV 的 UUID、VG 归属、PE 大小和总数等。

pvcreate到底做了什么?它是在磁盘开头写入 LVM 元数据区域,默认会保留大约 1MiB 的偏移,把卷组、逻辑卷的映射信息放在这里。也就是说,它不会在乎盘上原来的文件系统签名在什么位置,但如果磁盘上已经有分区表或文件系统,它会拒绝执行。真的要处理一个已经用过的盘,并且确认数据不要了,可以:

wipefs -a /dev/sdb

这条命令会把文件系统签名、分区表签名全清掉。谨慎使用,它会让你瞬间失去盘上所有数据,生产环境执行前必须再三确认。

3.2 第二步:组建卷组(vgcreate)并理解PE

vgcreate datavg /dev/sdb

datavg是我给卷组起的名字,最好能体现用途,比如datavg、backupvg。创建后用vgs、vgdisplay datavg查看。

vgcreate默认会把物理卷加入卷组,并划分 PE(Physical Extent)。PE 是 LVM 分配空间的最小单位,相当于内存里的分页。默认 PE 大小是 4MiB,这个值可以通过-s参数指定:

vgcreate -s 16M datavg /dev/sdb

PE 越大,需要记录的条目越少,元数据体积更小,但空间分配粒度更粗,最后可能出现一个小文件占用一大块 PE 的浪费;PE 太小,元数据膨胀,管理开销变大。默认 4MiB 对绝大多数场景都合理。如果你知道以后会有大量小文件、或者卷组里要做细粒度分配,保持默认即可。

创建 VG 后,你会发现系统里多了/dev/datavg/这个目录,它是 LVM 设备映射的入口,逻辑卷会出现在这里。

3.3 第三步:创建逻辑卷(lvcreate)

创建逻辑卷的语法是:

lvcreate -n data_lv -L 300G datavg

-n data_lv指定逻辑卷名字,-L 300G指定大小。注意 LVM 的-L单位:不写单位时默认是 MiB,比如-L 512就是 512MiB;写G代表的是 GiB(1024 进制),跟硬盘厂商的 1000 进制有区别,规划容量时别算岔了。

如果你想把卷组里所有剩余空间都给这个逻辑卷,用百分比更省事:

lvcreate -n data_lv -l 100%FREE datavg

-l是按 PE 数量或者百分比分配。两条命令的区别:-L 300G是精确大小,可能会被自动向上取整到 PE 整数倍;-l 100%FREE是把可用空间全部用掉,之后扩 VG 也方便。

创建后用lvs或lvdisplay查看。逻辑卷对应的块设备路径有两个:

  • /dev/datavg/data_lv
  • /dev/mapper/datavg-data_lv

两个指向同一个设备。习惯上挂载时我用/dev/mapper/路径,脚本里则用 UUID,这样最不容易出错。

3.4 第四步:格式化、挂载并开机自动挂载

新建的 LV 是裸设备,格式化后才能用。以 ext4 为例:

mkfs.ext4 /dev/datavg/data_lv mkdir -p /data mount /dev/datavg/data_lv /data

如果你想用 XFS,执行mkfs.xfs,大部分新版系统默认也是 XFS。文件系统选择后面会细说。

然后写入/etc/fstab,否则重启后挂载会丢。最稳的做法是先用blkid查 UUID:

blkid /dev/datavg/data_lv

得到类似UUID="xxxx-xxxx-xxxx"的输出后,在/etc/fstab里添加:

UUID=xxxx-xxxx-xxxx /data ext4 defaults 0 2

也可以用设备路径:

/dev/mapper/datavg-data_lv /data ext4 defaults 0 2

两者我都试过,UUID 更稳。因为设备路径虽然基于 LVM 名字,一般不会变,但万一哪次 VG 名或 LV 名被改,或者/dev/mapper重建顺序出问题,UUID 不受影响。

最后全链路验证:

df -hT /data lvdisplay /dev/datavg/data_lv lsblk

看到/data的大小和 LV 一致,lsblk里正确显示datavg-data_lv的挂载关系,这单就算完成了。

4. 扩容链路:VG、LV、文件系统三层同步扩容

扩容是 LVM 最诱人的功能,但最容易犯的错是扩了 LV 却忘了扩容文件系统,导致df看到的大小没变。扩容必须拆成三步走。

4.1 卷组容量不够:先扩VG再扩LV

如果vgs显示 VFree(卷组剩余空间)不够,就得先从“池子”层扩容。比如你原来只有一块 500G 盘,现在再加一块 500G 盘:

pvcreate /dev/sdc vgextend datavg /dev/sdc

vgextend就是把新 PV 加入已有 VG。执行完再看vgs,VFree 会直接增加 500G,池子扩容成功。这一步跨磁盘合并空间,传统分区想都不敢想。

如果你需要把某个 PV 从 VG 中移除,用vgreduce datavg /dev/sdc,但前提是把该 PV 上的逻辑卷数据先pvmove挪到别处,否则会丢数据。pvmove /dev/sdc是迁移数据到同 VG 内其他 PV 的命令,很实用,不过这里不多展开。

4.2 逻辑卷扩容:lvextend与文件系统同步

VG 空间充足时,直接拉长 LV:

lvextend -L +50G /dev/datavg/data_lv

+50G表示在现有基础上增加 50G;不带+则会把 LV 直接设定为 50G,如果当前 LV 已经大于 50G 就有缩减风险,务必看清。

也可以按百分比:

lvextend -l +100%FREE /dev/datavg/data_lv

LVM 层扩容完成后,lsblk会发现 LV 变大了,但df -hT /data依旧显示旧容量。原因很简单:文件系统不知道底层块设备已经变大了,需要主动通知它。

ext4 用resize2fs:

resize2fs /dev/datavg/data_lv

XFS 用xfs_growfs,注意它的参数不是设备路径,而是挂载点:

xfs_growfs /data

一条命令扩完,再df -hT /data就能看到新容量。实测下来,ext4 在线扩容和 XFS 在线扩容都非常稳定,业务不需要停机。这也是 LVM 进入生产环境最值钱的地方。

4.3 xfs与ext4的扩容差异

很多人在第一次扩容时直接卡在xfs_growfs和resize2fs的区别上,这里用表格理清:

文件系统在线扩容在线缩减扩容工具工具参数
ext4支持不支持在线缩,需卸载后缩resize2fs设备路径
XFS支持完全不支持xfs_growfs挂载点路径

也就是说,XFS 只能大不能小,这是它最大的限制。扩容 XFS 时用xfs_growfs /data,千万别写成xfs_growfs /dev/datavg/data_lv,工具会直接报错或不认设备。

另外,很多老教程推荐用lvextend -r一步到位扩展文件系统,-r的意思是由 LVM 自动识别文件系统类型并调用对应工具。我试过,ext4 和 XFS 都能识别,但生产环境我更偏向手动分两步:先lvextend,再分别执行resize2fs或xfs_growfs。原因在于-r自动扩展时的日志输出不如手动操作直观,出问题后定位稍麻烦。分两步,每一步都能验证。

5. 缩减逻辑卷:能不做就不做,非做不可时的安全顺序

缩减逻辑卷是 LVM 里风险最高、回报最低的操作。能通过加盘扩容解决的,就别缩减。但偶尔会遇到“空间规划过大要挪给别的卷”的情况,这里讲清楚安全流程。

5.1 为什么缩减这么危险:先动文件系统再动LV

LVM 本身是无状态的块映射,LV 缩减的本质是:告诉 LVM 放弃一部分 PE,而这些 PE 可能还存储着文件系统的数据。如果你先lvreduce再缩文件系统,文件系统里的元数据、数据块索引还指向已经被 LVM 回收的 PE,等文件系统真正读写到那片区域时,数据已经没了,后果基本是灾难性的。

所以顺序必须是:先缩文件系统,后缩 LV。文件系统缩小到某个大小后,它就不会再使用那部分空间,LVM 再回收对应 PE 才不会产生冲突。整个过程要像拆炸弹一样谨慎,最保险的是先做一次完整备份,或者至少打一个 LVM 快照。

5.2 ext4缩减的完整步骤

以下流程只对 ext4 有效,并且必须先卸载文件系统:

umount /data e2fsck -f /dev/datavg/data_lv

e2fsck -f是强制检查文件系统,缩容前必须执行,否则resize2fs会拒绝操作,或者缩完出现逻辑错误。检查完后,把文件系统缩到目标大小。假设要把 LV 从 100G 减到 60G:

resize2fs /dev/datavg/data_lv 60G

这里 60G 是文件系统新的大小,可以略小于最终目标。然后缩减 LV 本身:

lvreduce -L 60G /dev/datavg/data_lv

最后重新挂载并验证:

mount /data df -hT /data

整个过程要求业务停机窗口,因为文件系统被卸载的期间应用无法写数据。如果挂载状态下执行resize2fs缩小,ext4 会给出错误提示,不要强行操作。使用lvreduce -r虽然会自动调用resize2fs,但它可能在你未卸载时也拒绝或尝试自动挂载处理,我更建议手工串行执行每一步,出错时能清楚知道卡在哪一环。

5.3 xfs为何不能在线缩减

XFS 的文件系统结构设计不适合动态缩小,目前官方没有提供xfs_shrink工具。这意味着如果你用的是 XFS,想缩小逻辑卷,只能走“备份-重建-恢复”的老路:

  1. 把/data数据完整备份到别处。
  2. lvremove或lvreduce重建一个更小的 LV。
  3. mkfs.xfs重新格式化。
  4. 挂载后把数据恢复到新的文件系统。

这套流程非常耗时,而且备份环节一旦遗漏任何隐藏文件,恢复后就是一个残缺的数据集。所以我的建议很直白:不确定未来容量方向时,优先用 ext4。特别是那些要进行灵活缩放的逻辑卷,ext4 给了你后路,XFS 则完全锁死。如果你确实想用 XFS,就按“只增不减”来规划,留足余量。

6. 我踩过的坑:元数据恢复、PE选择、误删与快照

最后这部分是纯实战经验,每一条都是真实折腾过的教训。

6.1 元数据丢失与pvdisplay找不到设备

有一次服务器重启后,vgscan扫不到卷组,pvdisplay也提示找不到 PV,当时吓出一身冷汗。后来发现是盘符漂移加 PV 未激活。处理方法是先扫描,再手动激活:

vgscan vgchange -ay

vgchange -ay会把所有卷组标记为活动状态,设备映射建立后,逻辑卷又重新出现在/dev/mapper/下。

真正危险的情况是元数据损坏或被覆盖。LVM 会在/etc/lvm/archive/和/etc/lvm/backup/留下每次变更前的元数据备份。如果 PV 元数据坏了,可以尝试恢复:

vgcfgrestore datavg --file /etc/lvm/backup/datavg

这个命令会用备份文件恢复卷组元数据,但是否能找回数据,取决于损坏发生之后有没有新的写操作占据原 PE。我的经验是:发现异常立刻停止一切读写,先备份当前错误状态,再动手恢复。盲目执行修复命令可能把仅存的元数据覆盖掉。

6.2 PE大小对空间浪费的影响

有一台机器,我为了追求“更细粒度”,把 VG 的 PE 设成了 1MiB。结果几百个逻辑卷建下来,元数据占了不小空间,而且频繁分配小块空间时,pvs里看到的碎片感明显。后来在一个 1TB 的卷组上把 PE 改成 16MiB,逻辑卷数量不变,管理端简洁很多,空间浪费也不明显。

选 PE 的原则:

业务场景建议PE大小
大量小逻辑卷、需要精细分配1MiB-4MiB
常规服务器,单卷几十G-几T4MiB 默认即可
超大容量、几十T级存储池16MiB 或更大

如果你的卷组已经建好,想改 PE 大小,只能备份后重建卷组。所以在vgcreate阶段就要想清楚,别学我事后拍大腿。

6.3 vgremove/lvremove误删后的恢复思路

某同事A在清理旧卷时手滑执行了lvremove /dev/datavg/data_lv,然后才发现里面还有一份没备份的报表数据。我们当时没有立刻在 VG 上新建任何逻辑卷,抓紧时间用元数据备份做恢复:

vgcfgrestore datavg --file /etc/lvm/backup/datavg

执行后lvscan居然又把那个逻辑卷扫回来了,挂载后文件系统还在,数据完好。这不是每次都能成功,但给了我们一个重要经验:LVM 元数据改动前,务必确认/etc/lvm/archive和/etc/lvm/backup的备份策略正在运行。默认机制是有的,但如果你手动删过这些目录,或者系统时间有问题,备份可能是残缺的。

更稳妥的做法是定期手动备份:

vgcfgbackup datavg --file /backup/lvm/datavg.$(date +%F)

放进 crontab 里跑,等于给整个 LVM 配置上了保险。

6.4 快照:LVM最容易被忽略的杀手锏

LVM 快照是运维干活的利器,却经常被忽略。创建快照非常快:

lvcreate -s -n data_snap -L 10G /dev/datavg/data_lv

-s表示快照,-L 10G是给快照预留的空间,不是原卷大小。快照基于 COW(写时复制)机制:快照创建后,对原 LV 的每次修改,旧数据会先复制到快照区域,所以快照保留的是创建时刻的数据状态。10G 的快照能支撑多久,取决于这段时间内原卷写入的数据量,写得多快照空间就消耗得快,空间耗尽后快照会失效,严重时可能拖累原卷 I/O。

实际使用中,我通常在版本升级、批量删数据、跑危险脚本之前打一个快照,出问题后直接回滚:

lvconvert --merge /dev/datavg/data_snap

合并前最好卸载原卷,合并完成后,原卷恢复到快照时刻的状态。比备份恢复快得多,尤其是大逻辑卷场景。注意,恢复动作会丢弃快照创建之后的所有改动,执行前想清楚。我自己的习惯是:重要数据除了日常备份,高危操作前一定打快照,这是花钱都买不到的后悔药。这也是我坚持用 LVM 管理数据盘最重要的原因之一——不只是扩容,更是给了自己“反悔”的余地。

如果你还没把服务迁到 LVM,趁数据量还不大的时候尽早规划。把数据盘初始化成 PV、组建 VG、按业务拆分 LV,一次性搭好骨架,以后再遇到加盘扩容、空间腾挪、回滚快照,都是几分钟的事。唯一要记得的底线:高危操作前备份、缩容前检查文件系统、别拿快照当永久备份。这些坑我替你先踩了,照着这套流程走,能省下不少半夜救火的精力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询