3422 字
17 分钟
一文讲通 LVM 与传统扩容的异同

本文思维链:理解分区职能 → 拆开传统分区的两个角色 → 看清 LVM 的三层抽象 → 落到扩容流程与常见坑

基本概念#

Linux 的存储从上到下是一条链:物理磁盘 → 分区表 → 分区 / PV → (VG)→ 文件系统 → 挂载点。 日常最容易混淆的是”分区”和”文件系统”——把它们分开看,后面所有扩容操作才讲得通。

分区概念#

分区不是一块独立的设备,它只是分区表里的一条记录:「从第 X 个扇区开始,共 Y 个扇区」。内核读到这条记录后,生成一个块设备 /dev/sdb1,上层就能像读写整盘一样读写这段地址范围。

分区表写在磁盘最前面,常见两种:

类型位置分区数上限容量上限特点
MBR第 0 扇区(512 B)4 个主分区(或 3 主 + 1 扩展)2 TiB老、兼容性好,改完需重读
GPT头部 + 尾部各一份,带 CRC 校验默认 128 个远超 2 TiB自带备份表,主表损坏可恢复

分区与文件系统的分工mkfs.xfs /dev/sdb1 是把文件系统的超级块、空闲块位图、inode 表写进分区覆盖的地址范围。也就是说:

  • 分区决定「文件系统能用多大」——地址范围写在分区表里,建好即固定;
  • 文件系统决定「这些空间怎么组织数据」——元数据写在分区内部。

两边互不知情,所以扩容时要拆成两次扩:先改分区表/LV 映射让块设备变大,再通知文件系统吃满新空间。这是全文最关键的一句话。

flowchart TD
    A[物理磁盘 /dev/sdb] --> B[分区表 MBR / GPT]
    B --> C[分区 /dev/sdb1]
    C --> D[文件系统 XFS / EXT4]
    D --> E[挂载点 /data]

查看命令

Terminal window
lsblk -f # 树形展示:磁盘→分区→文件系统→挂载点
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT
blkid # 查看 UUID / 文件系统类型
fdisk -l /dev/sdb # 查看分区表

LVM概念#

LVM(Logical Volume Manager) 是架在 device-mapper(dm)之上的卷管理层:它把「物理空间」和「逻辑空间」解耦,用一张可动态修改的映射表取代固定地址。

层次结构:物理磁盘/分区 → PVVGLV → 文件系统

全称作用关键命令类比
PVPhysical Volume被 LVM 纳管的块设备;空间切成固定大小的 PE(默认 4 MiB),头部写入 LVM 元数据pvcreate / pvs / pvdisplay砖头
VGVolume Group把一个或多个 PV 汇总成存储池,池内空间以 PE 为单位统一编号vgcreate / vgextend / vgs砖堆
LVLogical Volume从 VG 里切出一段空间,由若干 LE 组成,与 PE 一一映射lvcreate / lvextend / lvs砌好的墙
PE / LEPhysical / Logical Extent分配的最小粒度:PE 在 PV 上,LE 在 LV 上,默认 4 MiBpvcreate -s / lvcreate -l砖的单位

映射是怎么实现的:LV 并不是”把某块盘的一部分划出来”,而是 dm 里的一张 linear 映射表——「LV 的第 0 ~ 10239 个 LE → /dev/sdb 上第 0 ~ 10239 个 PE」。由此得到三个直接结论:

  • 一个 LV 可以横跨多块 PV
  • 扩容只是往映射表尾部追加条目,已有条目的地址不动,所以不需要搬数据;
  • 设备节点其实是 /dev/mapper/vg_data-lv_data/dev/vg_data/lv_data 只是 udev 生成的软链接,两者是同一个设备。

元数据存在哪:LVM 自己的元数据(PV/VG/LV 结构、PE 分配表)有两份——磁盘上每个 PV 头部的 label + metadata area,以及 /etc/lvm/backup//etc/lvm/archive/ 里的文本备份,必要时可用 vgcfgrestore 回滚。这也是 LVM 比裸分区”更好救”的原因之一。

Terminal window
pvs # PV 清单
vgs # VG 清单(重点看 VFree:还剩多少可分配)
lvs -o +devices # LV 清单,+devices 可看到它落在哪些 PV 上
pvdisplay -m # 展开 PE → LE 的映射关系

两者关系#

传统分区 /dev/sdb1 同时干了两件事:

  1. 划分物理边界:把一块物理磁盘切成一段一段的存储区域
  2. 作为文件系统的载体mkfs /dev/sdb1,文件系统直接建在分区上

而 LVM 把这两个角色拆开了:

角色传统LVM
划分物理边界分区(fdisk)PV(pvcreate,切成 PE)
池化/合并空间不存在VG(vgextend 加入新 PV)
作为文件系统载体分区(sdb1)LV(lvcreate)
容量调整粒度整块磁盘的空闲区域VG 中任意可用 PE

注:VG ≈ 传统里没有的中间池化层(把多个物理范围合并成一个可分配空间)。

两者区别#

分区大小#

LV 的物理边界不是固定的,而传统分区大小固定:

  • 传统 /dev/sdb1 建好后,物理位置和大小就钉死了。
  • LVM 的 /dev/vg_data/lv_data 逻辑上 50G,但底层可能横跨 /dev/sda3/dev/sdb 两块盘,扩容后可以变成 150G。

也就是说,LV 只保留”文件系统载体”这个角色,丢掉了”固定物理边界”这个角色——物理边界被 PV/VG 接管了。这正是 LVM 灵活性的来源。

在线扩容#

传统分区必须挂载新目录或调整分区,LVM 可通过 LV 实现逻辑上的扩展:

  • PV 层面pvcreate /dev/sdb 只是初始化磁盘元数据,不涉及已挂载的磁盘。
  • VG 层面vgextend vg_data /dev/sdb 只是在卷组里新增一个物理存储池成员,不影响现有 LV 的数据分布。
  • LV 层面lvextend -l +100%FREE /dev/vg_data/lv_data 是逻辑上的扩展,内核支持动态调整映射表。
  • 文件系统层面xfs_growfs /dataresize2fs 专门设计为在线扩展,底层文件系统会动态分配新空间到已有目录中。

整个过程业务进程无需重启,正在读写的文件不受影响(因为扩展的是空闲区域,不移动已有数据)。

扩容能力的边界#

场景传统分区LVM
同一块盘有紧邻空闲空间时扩容可以(改分区表 + 重读 + resize2fs)可以
跨磁盘扩大同一个目录不可能,分区不能跨盘可以(vgextend + lvextend)
在线扩容(不 umount、不停业务)受盘内空间与内核重读分区表限制可以
缩容ext4 需 umount + e2fsck;XFS 完全不支持同样受限,lvreduce 必须离线且风险极高
秒级快照 / 克隆不支持lvcreate -s 支持

结论:LVM 换来灵活性,代价是多一层抽象(多一份要维护的元数据、多一处可能敲错的地方)。缩容不是它的强项,扩容才是它的主场

扩容流程#

扩容要先分清诉求,两种诉求的代价完全不同:

  • A. 新增挂载点:磁盘满了,加一块盘,把新盘挂到新目录(如 /data2)——不需要停机。
  • B. 扩大已有目录:磁盘满了,但业务路径不能改,必须让 /data 本身变大——这才是考验底层方案的地方。

新增磁盘(传统 & LVM)#

场景1:为新磁盘新建分区(或 LV)并挂载到新目录,即上面的诉求 A。

传统流程:OS 层执行 rescan → 确认 lsblk → fdisk 分区 → mkfs 格式化 → mount 挂载 → df 验证→ fstab 永久挂载 → mount -a 验证

Terminal window
# OS层发现新设备
echo "- - -" > /sys/class/scsi_host/host0/scan
lsblk # 确认新容量已识别
fdisk /dev/sdb # 分区
mkfs.xfs /dev/sdb1 # 格式化
mount /dev/sdb1 /mnt/data # 挂载
df -h # 验证
# 永久挂载:获取UUID → 写入 /etc/fstab
blkid /dev/sdb1 # 获取UUID
blkid /dev/sdb1 | grep -o ' UUID="[^"]*' | cut -d'"' -f2 # 获取纯UUID字段
vim /etc/fstab # vim 手动加一行或用 echo 追加
echo 'UUID=<UUID> /mnt/data xfs defaults 0 0' >> /etc/fstab
mount -a -v # 用 mount -a 测试 fstab 是否正确

LVM 流程:OS 层执行 rescan → 确认 lsblk → PV/VG/LV 操作 → mkfs → mount → df 验证 → fstab 永久挂载 → mount -a 验证

Terminal window
echo "- - -" > /sys/class/scsi_host/host0/scan
lsblk
pvcreate /dev/sdb # 相当于分区中的初始化物理边界
vgcreate vg_data /dev/sdb # 建存储池(传统没有这层)
lvcreate -L 50G -n lv_data vg_data # 相当于"切出分区"
mkfs.xfs /dev/vg_data/lv_data # 格式化
mount /dev/vg_data/lv_data /mnt/data # 挂载
df -h
blkid /dev/sdb1
vim /etc/fstab
mount -a -v

场景2:为新磁盘新建分区(或 LV)并挂载到已有目录,即上面的诉求 B。

流程:停业务 → 搬运现有业务数据 → 识别新容量 → umount → 其余流程

为什么该流程要停止业务/不支持在线操作?

“新盘 + 新挂载点”这套流程本身不需要停机mkfsmount 只作用于新的块设备与新的空目录,完全不碰正在服务的文件系统。真正要停机的,是「想把新盘并进已有目录」(诉求 B)——传统分区方案做不到,只能停机搬数据。

拆开看,原因有三层:

  1. 分区是固定地址,且不能跨盘/dev/sda1 的边界写死在分区表里,/dev/sdb1 是另一段独立地址。“把 sdb 的空间追加给 sda1 上的文件系统”在传统分区里根本不存在对应操作。
  2. 同一块盘内扩容也有限制:只有当盘上存在紧邻分区尾部的空闲空间时才能扩(growpart / parted resizepartresize2fs);改完分区表还要让内核重读(partprobe / partx -u),而分区正被挂载占用时,旧内核会直接拒绝重读,只能 umount。
  3. 做不到就只能搬数据:换新盘意味着 rsync 全量搬运 → umount → 重新分区、mkfs → 改 /etc/fstab → 重新 mount。停机时间和数据量成正比,且搬运期间的新写入无法保证一致,业务必须停。

另外,mkfs 这个动作永远不可能在线做:它是”在块设备上从零构建文件系统元数据”的破坏性操作,等于把原有超级块、inode 表、位图全部重建。这和”扩容文件系统(在原有结构上变大、保留数据)“是两件完全不同的事。

LVM 在线扩容#

生产环境中的最佳实践。不动现有磁盘/分区,而是把新磁盘加入卷组,再扩展 LV,让文件系统直接使用新空间。

流程:OS 层执行 rescan → 确认 lsblk → PV/VG/LV 操作 → xfs_growfs/resize2fs → df 验证

Terminal window
echo "- - -" > /sys/class/scsi_host/host0/scan
lsblk
pvcreate /dev/sdb # 新盘纳入 LVM
vgextend vg_data /dev/sdb # 加入卷组,VG 变大
lvextend -l +100%FREE /dev/vg_data/lv_data # LV 变大(也可以 -L +50G 指定增量)
# 扩容文件系统,通知文件系统用满新空间
xfs_growfs /data # XFS:接挂载点
resize2fs /dev/vg_data/lv_data # EXT4:接设备
# 检查
df -h

为什么扩容流程中没有格式化/挂载操作?

  • 格式化(mkfs)是对整个块设备”从无到有”创建文件系统的操作,只能做一次;而扩容是扩展文件系统(在原有基础上变大、保留数据),走的是另一条代码路径。
  • 挂载(mount)只在全新磁盘 / 全新 LV 第一次投入使用时做一次,作用是把文件系统接入目录树;扩容是对已挂载的对象操作,属于两个不同阶段。
  • 扩容其实是”拆成两次扩”:lvextend块设备变大(改 dm 映射表),xfs_growfs / resize2fs文件系统用满新空间。少做后一步,lsblk 已经变大而 df -h 毫无变化。

常见坑#

  1. 只扩了 LV,忘了扩文件系统:补一条 xfs_growfs /data(XFS)或 resize2fs /dev/vg_data/lv_data(EXT4)即可,对已挂载的文件系统是安全的(XFS 只支持扩、不支持缩)。
  2. 参数搞反xfs_growfs挂载点resize2fs设备lvextend 接 LV 路径,vgextendVG 名 + 新 PV
  3. 对已有数据的盘执行 pvcreate:会覆盖磁盘头部(含分区表),旧数据事实不可见。新盘整盘使用没问题;复用旧盘前务必确认盘上没有要保留的数据。
  4. 整盘做 PV 还是分区做 PVpvcreate /dev/sdb 最省事;若这块盘还要分给别的用途、或需要保留分区表结构,就先建一个类型为 8e(Linux LVM)的分区,再 pvcreate /dev/sdb1
  5. 虚拟机扩完盘系统没识别:SCSI 用 echo "- - -" > /sys/class/scsi_host/host0/scan;NVMe 用 echo 1 > /sys/class/nvme/nvme0/rescan_controller;只改了分区表则用 partprobe /dev/sdbpartx -u /dev/sdb
  6. 缩容是另一回事:ext4 缩容要先 umount + e2fsck -f + resize2fs,顺序错一步就丢数据;XFS 根本不支持缩容。生产上想”腾出空间”,通常是新建 LV、迁移数据、再删旧 LV。
  7. 变更前留后路:动 LV 之前可以先 lvcreate -s 打个快照,或确认有可用备份,扩容失败时可回滚。

小结#

问题一句话答案
分区和文件系统有什么区别?分区是「地址范围」(写在分区表里),文件系统是「数据的组织方式」(写在分区内部),扩容要分别扩两次。
LVM 比传统分区多了什么?多了 VG 池化层和一张可动态修改的映射表,所以空间能跨盘拼、容量能在线追加。
为什么还要执行 xfs_growfs / resize2fslvextend 只改块设备大小,文件系统必须被显式通知才能用满新空间。
为什么扩容不需要 mkfs / mount?格式化是”从无到有创建”,扩容是”在原有基础上变大”;挂载只在对象第一次投入使用时做一次。
传统方案什么时候必须停机?当诉求是”扩大已有目录”,且可用空间不在同一块盘的紧邻位置时——只能停机搬数据,这正是 LVM 存在的理由。
一文讲通 LVM 与传统扩容的异同
https://blog-l7wd3.pages.dev/posts/lvm/
作者
L7WD3-Xiao
发布于
2026-09-11
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取