1. 为什么我把“磁盘满了”当成事故,而不是故障
先说一段真实经历。前阵子某套系统的数据库服务器突然报写入失败,我登录上去一查,根分区用了 98%。这个根分区当年规划了 50GB,谁也想不到三个月就能撑满。更要命的是,这台机器用的是传统分区表方式,旁边明明还空着一块 2TB 的物理硬盘,却没办法直接并进根分区里。
1.1 传统分区表的“一次性”困局
传统分区方式下,一块磁盘被分成若干固定大小的分区,比如/dev/sda1对应根分区,/dev/sda2是 swap。这个布局在安装系统时敲定,之后几乎就焊死了。数据量增长超出预期时,你能做的只有几种:
- 把新磁盘分好区、格式化、挂载到某个目录,然后迁移数据;
- 用
parted在有空闲空间的前提下调整分区大小,但风险高、操作繁琐,而且很多文件系统不支持在线调整; - 直接重建分区表,那意味着重装系统或者做完整备份恢复。
这几种方案我全都试过。迁移数据最痛苦,因为涉及停应用、改挂载点、改配置;调整分区则要担惊受怕,一旦断电或者中途报错,很可能连现有数据都保不住。传统分区的问题本质是:物理磁盘边界直接暴露给了业务分区,分区大小在创建时就被物理位置和相邻分区给锁死了。
1.2 LVM 怎么打破这个局面
LVM(Logical Volume Manager,逻辑卷管理)解决的核心问题,是给物理存储加了一层“逻辑抽象”。你可以把多块物理磁盘或分区先合并成一个大资源池,再从这个池里切出任意大小的逻辑卷给系统用。业务分区不再直接落在物理磁盘边界上,而是落在逻辑卷里。
这样带来三个最直观的好处:
- 空间不够了,直接从资源池里划一块新空间塞给现有逻辑卷,在线就能搞定;
- 多个物理磁盘可以合并成一个卷组,对上层表现为一整块大磁盘;
- 逻辑卷可以做快照,配合备份和回滚,比裸分区灵活得多。
那次事故之后,我把所有新机器的磁盘规划全部改成了 LVM。可以这么说:在绝大多数服务器场景下,直接裸分区等于放弃了未来所有的调整空间,而 LVM 给了你后悔药。
1.3 什么场景下最该用 LVM
也不是所有情况都必须上 LVM。我自己的判断标准很简单:
- 需要在线扩容、缩容,或者对空间规划没信心——用 LVM;
- 数据库、日志、文件服务器等数据增长不确定的业务,强烈建议用 LVM;
- 桌面环境、简单的个人测试机,怎么都行,但 LVM 也不亏;
- 如果你对性能有极致要求,并且非常清楚分区未来不会变,裸分区也可以接受。
LVM 带来的性能损耗在绝大多数场景下可以忽略,除非你跑的是那种对 IOPS 极其敏感的万兆级数据库,那样的话另说。对普通生产业务来说,灵活性的价值远大于那点可忽略的开销。
2. LVM 的底层逻辑:物理卷、卷组、逻辑卷到底在干嘛
很多教程一上来就让人敲pvcreate、vgcreate、lvcreate,但不解释这三层到底是什么关系。结果就是命令记住了,出问题时完全不知道在折腾谁。我换一种方式讲。
2.1 三层结构的映射关系
LVM 的模型非常像仓库管理:
- 物理卷(PV,Physical Volume):仓库的场地,可以是一整块硬盘,也可以是硬盘上的一个分区。它的作用就是把实际存储空间划成一个个等大的小格子,这些小格子在 LVM 里叫物理扩展块(PE,Physical Extent),默认大小是 4MB。
- 卷组(VG,Volume Group):若干个仓库场地合并成的一个大仓库。你只管这个大仓库总共有多少面积,不用管它分布在几栋楼里。
- 逻辑卷(LV,Logical Volume):从大仓库里划出来的具体库房。上层系统看到的是一个块设备,可以格式化、挂载、读写,完全感觉不到底层跨了几块硬盘。
数据写入时,文件系统把数据放在逻辑卷的地址空间里,LVM 再把这个地址翻译成物理卷上的某个具体位置。对上层文件系统来说,它只跟逻辑卷打交道,物理磁盘的变化被完全屏蔽了。
2.2 常用术语速查表
| 术语 | 缩写 | 作用 | 常见命令 |
|---|---|---|---|
| 物理卷 | PV | 把磁盘或分区初始化为 LVM 可用的存储单元 | pvcreate、pvdisplay、pvremove |
| 卷组 | VG | 一个或多个 PV 组成的大存储池 | vgcreate、vgextend、vgreduce |
| 逻辑卷 | LV | 从 VG 中划分出的最终可用卷 | lvcreate、lvextend、lvreduce |
| 物理扩展块 | PE | PV 上的最小存储单元,默认 4MB | 相关参数:-s |
| 卷组元数据 | - | 记录 PV、VG、LV 对应关系的数据 | /etc/lvm/backup、vgcfgbackup |
这个表的重点是:PE 是物理卷的“砖块”,逻辑卷分配的其实是一堆 PE 的集合。你执行lvextend -L +10G时,LVM 做的事就是从卷组的空闲 PE 里挑出足够的数量,映射给目标逻辑卷。
2.3 用抽屉柜类比 LVM
想象一个巨大的抽屉柜,下面摆着好几个不同尺寸的抽屉(物理磁盘),你把这些抽屉全塞进一个大柜子里,这个柜子就是卷组。你不需要关心文件具体落在哪个抽屉里,只要跟柜子说“我要一个能装 200GB 东西的抽屉”,柜子就会给你划分逻辑卷。
哪天抽屉不够装了,就再买一个新的抽屉塞进柜子里,然后告诉柜子“把这个新抽屉也算进柜子”,这就是vgextend。柜子里的空间又多出来,逻辑卷就能继续扩。整个过程不影响你从旧抽屉里取放东西。
这套抽象机制的好处,在于把“物理存储布局”和“业务空间需求”彻底解耦。底层换硬盘、加硬盘、迁移数据,在传统分区下是天大的事,在 LVM 下往往只是几条命令。
3. 实操第一课:从裸盘到可用文件系统的完整命令
概念再熟,不动手都是白搭。这一节我用一套实际命令,带你走完“裸盘 -> PV -> VG -> LV -> 文件系统 -> 挂载”的完整链路。以下操作默认你有一块新加的物理磁盘,比如/dev/sdb,且这是一台 RHEL 系发行版。
3.1 环境准备与工具安装
LVM 工具链在大多数发行版里是默认安装的,但有些精简安装不带你想要的命令。检查方法很简单:
which pvcreate vgcreate lvcreate如果提示找不到,RHEL 系发行版执行:
yum install lvm2Debian 系发行版执行:
apt install lvm2装完后先确认磁盘确实被系统识别到了:
lsblk fdisk -l假设输出里能看到/dev/sdb,容量 500GB,没有任何分区表信息,那就进入下一步。
3.2 选择:用整块盘还是建分区?
关于“PV 到底要建在分区上还是整块磁盘上”,我直接给结论:能直接用整块盘,就别先分区。
很多旧教程喜欢让你先fdisk建一个8e类型的 LVM 分区,再把分区做成 PV。这在 MBR 时代合理,因为有些老系统的分区工具不认识整块盘的 PV。但现在的 GRUB2 和内核都能直接识别整块硬盘上的 PV,没必要多此一举。直接用整块盘有额外好处:以后想缩容物理盘、删除重建,都不用处理分区表。
如果你的磁盘上已经有分区,但想把它变成 PV,也可以用pvcreate直接对分区操作,系统会提示是否需要擦除分区表,确认一下就行。
3.3 创建 PV、VG、LV 的完整流程
先初始化物理卷:
pvcreate /dev/sdb执行后可以用pvs或pvdisplay查看状态。正常输出里,/dev/sdb会显示PV /dev/sdb VG <none>,说明还没加入任何卷组。
创建卷组。假设卷组名叫vg_data:
vgcreate vg_data /dev/sdb此时整个 500GB 都归了vg_data。如果以后又加了一块盘,想并进来:
vgextend vg_data /dev/sdc创建逻辑卷。假设需要一个 200GB 的逻辑卷,名字叫lv_data:
lvcreate -L 200G -n lv_data vg_data这里-L 200G指定容量,-n lv_data指定名称,最后是卷组名。执行后会在/dev/mapper/下生成/dev/mapper/vg_data-lv_data这个设备,也可以写作/dev/vg_data/lv_data。两种写法指向同一个东西。
3.4 格式化、挂载并写入 fstab
逻辑卷本身只是一个块设备,要格式化文件系统才能用。比如格式化成 XFS:
mkfs.xfs /dev/vg_data/lv_data如果是生产环境,我习惯在格式化之前再确认一遍设备路径,别手滑格式错盘。
挂载到/data:
mkdir /data mount /dev/vg_data/lv_data /data要让开机自动挂载,必须写进/etc/fstab。建议用 UUID 而不是设备路径,因为逻辑卷路径虽然比物理分区稳定,但也可能因为刷新顺序变化出现临时错乱。获取 UUID 的方式:
blkid /dev/vg_data/lv_data然后编辑/etc/fstab,加一行:
UUID=xxxx-xxxx /data xfs defaults 0 0加完之后别急着重启,先执行mount -a看有没有报错。这一步能避免因为 fstab 写错导致开不了机的尴尬。
4. 扩容缩容:在线调整大小时的顺序与文件系统限制
LVM 最实用、也最容易被新手搞错的地方,就是扩容和缩容的顺序。我在运维过程中见过太多人一上来就resize2fs,结果空间没变大,系统还提示文件系统不一致。这一节先把顺序刻进脑子。
4.1 扩容的正确流程:先扩逻辑卷,再扩文件系统
扩容的逻辑其实就两步:第一步让 LVM 把空间划给逻辑卷,第二步让文件系统“知道”并接管这些新空间。顺序绝对反不得。
假设/dev/vg_data/lv_data初始是 200GB,现在要扩到 300GB:
lvextend -L 300G /dev/vg_data/lv_data如果你只是想增加 100GB,也可以这么写:
lvextend -L +100G /dev/vg_data/lv_data区别在于第一个是最终大小,第二个是增加大小。我推荐用带+的写法,逻辑更明确,不容易受当前大小记错影响。
扩完逻辑卷后,检查卷组剩余空间:
vgs重点看VFree列,确认没有多给。接下来关键一步:让文件系统扩容。
对于 XFS,使用
xfs_growfs,它需要传挂载点:xfs_growfs /data对于 ext4,使用
resize2fs,传设备路径:resize2fs /dev/vg_data/lv_data
执行完df -h验证。
4.2 ext4、XFS、Btrfs 三种文件系统的扩容差异
| 文件系统 | 在线扩容 | 在线缩容 | 扩容命令 | 缩容命令 | 说明 |
|---|---|---|---|---|---|
| ext4 | 支持 | 支持 | resize2fs | resize2fs | 缩容必须先卸载,且有数据丢失风险 |
| XFS | 支持 | 不支持 | xfs_growfs | 无 | XFS 只能扩不能缩,这是硬限制 |
| Btrfs | 支持 | 支持 | btrfs filesystem resize | btrfs filesystem resize | 相对灵活,但 Btrfs 在其他方面有适用场景限制 |
这个表格值得你截图保存。扩容顺序别搞反,缩容前先确认文件系统类型。我见过连续几台机器用 XFS,有人拿 ext4 的思维去缩容,直接报错。
4.3 缩容操作与限制:为什么 XFS 不能缩容
XFS 在设计上是一种只支持增长的文件系统,因为它的分配组和日志机制天生不支持收缩元数据。这意味着如果你用 XFS 做根分区或关键数据分区,事前一定要估算好最大容量,宁可多加空间也别想着以后能缩回来。
ext4 可以缩容,但限制很严格:
- 必须卸载文件系统,生产环境基本只有停机窗口能操作;
- 缩容只能缩小到“存储了最多数据的地方”之后,也就是要保证缩容后容量大于当前已用空间;
- 操作顺序与扩容相反:先缩文件系统,再缩逻辑卷。
umount /data resize2fs /dev/vg_data/lv_data 150G lvreduce -L 150G /dev/vg_data/lv_data mount /dataresize2fs命令里的目标大小一定要比lvreduce的目标大小小或者相等,否则逻辑卷比文件系统还小,数据必然损坏。整个缩容过程我强烈建议先做备份,哪怕只是逻辑卷快照也行。
5. 快照回滚:被人忽视的备份与恢复利器
LVM 快照是我认为最被低估的功能。很多人觉得快照只是“暂时冻结一下”,实际上它做数据库备份、跑升级前安全网、验证迁移方案时能省太多事。
5.1 快照原理:写时复制(CoW)
LVM 快照的核心机制是写时复制(Copy-on-Write)。创建快照时,LVM 并不会复制整份数据,而是先记录一个时间点的“元数据状态”。之后原始卷上如果有数据要修改,LVM 会先把旧数据复制到快照区保存,再写入新数据。所以快照区里存的是“即将被覆盖的旧数据”。
因此,快照占用的空间会随原始卷数据变动量增长,而不是随原始卷总大小增长。如果快照空间耗尽,快照就会失效甚至导致整个卷组出问题。这是很多人踩坑的重灾区。
5.2 快照实践:创建、挂载、恢复
假设/dev/vg_data/lv_data上跑着一个数据库,你要做一次安全备份前的快照。创建快照逻辑卷,分配 10GB 空间:
lvcreate -L 10G -s -n lv_data_snap /dev/vg_data/lv_data-s表示 snapshot(快照),-n指定快照名,后面是源逻辑卷。创建完成后,你可以把快照挂载到某个目录,直接对挂载后的文件做备份:
mkdir /mnt/snap mount -o ro /dev/vg_data/lv_data_snap /mnt/snap注意,快照卷通常以只读方式挂载,这样可以保证备份数据的一致性。备份完成后卸载:
umount /mnt/snap lvremove /dev/vg_data/lv_data_snap如果要回滚到快照时间点的状态,需要先卸载原始逻辑卷,再用lvconvert --merge合并:
umount /data lvconvert --merge /dev/vg_data/lv_data_snap mount /data合并完成后,快照卷会自动消失,原始卷回到快照时刻的数据状态。整个过程比从备份磁带恢复快得多。
5.3 快照空间规划与监控
快照空间到底给多大,没有固定答案,取决于数据写入频率和持续时间。我给个经验公式:如果预计在快照存在期间,原始卷最多会有 10% 的数据变动,那快照区至少给源卷大小的 10% 到 20%。
千万别等快照空间耗尽再看监控。检查命令:
lvs快照卷的属性列里,Data%就是已用空间比例。一旦超过 80%,建议尽快处理:要么删除快照,要么扩大快照容量。如果快照被写满,它会被自动标记为无效,回滚可能直接失败。
6. 实战踩坑复盘:高危操作与急救方案
最后分享几个我真实遇到过的坑。这些坑在文档里不会写得那么细,但每个都足以让你折腾半夜。
6.1 vgreduce 误删卷组的惊魂时刻
有一次,我需要从卷组里移除一块故障物理盘,执行了:
vgreduce vg_data /dev/sdc结果因为操作失误,我把物理盘路径打成了/dev/sdb,而这块盘上还承载着大量逻辑卷数据。vgreduce执行后直接告诉我有 PV 正在使用中,但当时的 PV 已经被强制移除,逻辑卷立即变成不可用状态。
事后复盘,正确做法是先把该 PV 上的数据迁移到其他 PV,再移除:
pvmove /dev/sdb vgreduce vg_data /dev/sdbpvmove会把源 PV 上的数据搬到同卷组的其他空闲空间,如果卷组没有足够空间,它会拒绝执行。这起事故其实可以通过提前查看pvs里Used列避免:凡是 Used 列不为 0 的 PV,都不能直接vgreduce。
6.2 快照空间不足导致整卷失效
另一次是给一个 500GB 的数据卷创建了 5GB 快照。我当时想当然以为“反正过一会儿就删掉”,结果数据库夜里做了一次大事务,瞬间大量写入,5GB 快照区直接写满。快照失效,而且影响波及到了同一卷组里的其他逻辑卷。
那一次给我教训很深刻:快照和源卷共享同一个卷组空间。如果卷组本身空间不够,快照区被撑爆时,LVM 会尝试自动扩展快照区,或者直接标记快照无效。更严重的可能是后续写入请求都受影响。我的建议是:生产环境做快照前,先vgs看一眼卷组剩余空间,再按前面说的 10%-20% 比例来分配快照大小。
6.3 XFS 缩容失败的教训与规划启示
一个同事以为 XFS 能像 ext4 一样在线缩容,在数据盘上直接执行了lvreduce,想当然地以为减小逻辑卷后 XFS 会自动适配。结果可想而知,文件系统元数据被破坏,磁盘变成了原始块设备,数据全部丢失。
这件事之后,我在团队里立了一条规矩:凡是 XFS 文件系统,除非有绝对充分的容量规划,否则不要给它做“留一点空间”的缩容操作。真要缩容,只能另建一个小逻辑卷,用xfsdump/xfsrestore或者rsync把数据搬过去,再删掉原来的卷。
6.4 fstab 写错导致无法开机的急救方法
fstab 写挂载项时,如果写错了设备路径或挂载选项,重启之后系统大概率会掉进 emergency mode。很多新手以为只能重装,其实救回来不难。
在急救模式下,根文件系统通常已经以只读方式挂载。先重新挂载为可写:
mount -o remount,rw /然后注释掉 fstab 里错误的一行,或者直接改成正确的内容:
vi /etc/fstab改完之后执行:
umount -a mount -a如果mount -a没有报错,再重启即可。预防措施就是每次修改 fstab 后,马上执行mount -a验证,验证通过再做下一步操作。
最后再分享一个实际体会
操作 LVM 这几年,我最深的感觉是:它把“磁盘规划错了”的成本从灾难级别降到了日常级别。学会 LVM 不是多背几条命令的事,而是建立一种“存储资源可编排、可回收、可回滚”的思维方式。
如果你刚上手,我建议先拿一台虚拟机,把整块盘创建 PV、建卷组、切逻辑卷、扩容、缩容、做快照、删除重来,每个动作都跑一遍。折腾坏了大不了重装,这种试错成本远低于在生产环境里踩坑。等这套流程熟练了,再上生产机器,你就知道什么时候该看pvs,什么时候该用lvextend -r一步到位扩展文件系统,什么时候千万别手滑。
我自己现在每台新服务器的磁盘规划,基本都是 LVM 起步,连系统盘也尽量留出独立卷组给业务数据用。真正把 LVM 用起来之后,你会觉得裸分区就像只能在固定位置打隔断的房子,而 LVM 给了你一道随时可以移动的隔断墙,这才是它最值的部分。