总所周知不论是机械硬盘还是固态磁盘大小都是固定的,当磁盘空间满了后只能通过删除无用数据来保持磁盘的可用性,这篇介绍的LVM(Logical Volume Manager)是建立在磁盘和分区之上的一个逻辑层,用来提高磁盘分区管理的灵活性,可以随时随地的扩缩容分区大小。
LVM术语
Physical Volume(PV)
实际分区需要调整 System ID 成为 LVM 表示(8e) ,然后经过 pvcreate 命令将他转为 LVM 最低层的 PV, 然后才能使用磁盘。
Volume Group(VG)
将多个PV组合起来,使用vgcreate命令创建成卷组,这样卷组包含了多个PV就比较大了,相当于重新整合了多个分区后得到的磁盘。虽然VG是整合多个PV的,但是创建VG时会将VG所有的空间根据指定的PE大小划分为多个PE,在LVM模式下的存储都以PE为单元,类似于文件系统的Block。
Physical Extent(PE)
LVM 预设使用 4MB 的 PE 区块,每个 LV 最多允许有 65534 个 PE ,即 256GB 。PE 属于 LVM 最小存储区。
Logical Volume(LV)
VG相当于整合过的硬盘,那么LV就相当于分区,只不过该分区是通过VG来划分的。VG中有很多PE单元,可以指定将多少个PE划分给一个LV,也可以直接指定大小(如多少兆)来划分。划分为LV之后就相当于划分了分区,只需再对LV进行格式化即可变成普通的文件系统。
Logical extent(LE)
PE是物理存储单元,而LE则是逻辑存储单元,也即为lv中的逻辑存储单元,和pe的大小是一样的。从vg中划分lv,实际上是从vg中划分vg中的pe,只不过划分lv后它不再称为pe,而是成为le。
LVM之所以能够伸缩容量,其原因就在于能够将LV里空闲的PE移出,或向LV中添加空闲的PE。
LVM的写入机制 LV是从VG中划分出来的,LV中的PE很可能来自于多个PV。在向LV存储数据时,有多种存储机制,其中两种是:
线性模式(linear):先写完来自于同一个PV的PE,再写来自于下一个PV的PE。
条带模式(striped):一份数据拆分成多份,分别写入该LV对应的每个PV中,所以读写性能较好,类似于RAID 0。
尽管striped读写性能较好也不建议 使用该模式,因为lvm的着重点在于弹性容量扩展而非性能,要实现性能应该使用RAID来实现,而且使用striped模式时要进行容量的扩展和收缩将比较麻烦。默认的是使用线性模式。
LVM实现图解
LVM的实现 看下我本地的环境,/dev/sdb已经分好了4个区,并且system id都设置为了8e。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 20G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 19G 0 part ├─centos-root 253:0 0 18G 0 lvm / └─centos-swap 253:1 0 1020M 0 lvm [SWAP] sdb 8:16 0 20G 0 disk ├─sdb1 8:17 0 5G 0 part ├─sdb2 8:18 0 2G 0 part ├─sdb3 8:19 0 10G 0 part └─sdb4 8:20 0 3G 0 part sr0 11:0 1 10G 0 rom $ fdisk -l /dev/sdb 磁盘 /dev/sdb:21.5 GB, 21474836480 字节,41943040 个扇区 Units = 扇区 of 1 * 512 = 512 bytes 扇区大小(逻辑/物理):512 字节 / 512 字节 I/O 大小(最小/最佳):512 字节 / 512 字节 磁盘标签类型:dos 磁盘标识符:0x76721574 设备 Boot Start End Blocks Id System /dev/sdb1 2048 10487807 5242880 8e Linux LVM /dev/sdb2 10487808 14682111 2097152 8e Linux LVM /dev/sdb3 14682112 35653631 10485760 8e Linux LVM /dev/sdb4 35653632 41943039 3144704 8e Linux LVM
管理pv 管理PV有几个命令:pvscan、pvdisplay、pvcreate、pvremove和pvmove。
命令很简单,基本都不需要任何选项。
功能
命令
创建pv
pvcreate
扫描并列出所有的pv
pvscan
列出pv属性信息
pvdisplay
移除pv
pvremove
移动pv中的数据
pvmove
创建PV 将/dev/sdb[1-3]创建为pv。
1 2 3 4 5 $ pvcreate /dev/sdb[1-3] Physical volume "/dev/sdb1" successfully created. Physical volume "/dev/sdb2" successfully created. Physical volume "/dev/sdb3" successfully created.
查看pv属性 使用pvscan来查看哪些pv和基本属性。
1 2 3 4 5 6 $ pvscan PV /dev/sda2 VG centos lvm2 [<19.00 GiB / 0 free] PV /dev/sdb3 lvm2 [10.00 GiB] PV /dev/sdb1 lvm2 [5.00 GiB] PV /dev/sdb2 lvm2 [2.00 GiB] Total: 4 [<36.00 GiB] / in use: 1 [<19.00 GiB] / in no VG: 3 [17.00 GiB]
使用pvdisplay查看其中一个pv的属性信息。
1 2 3 4 5 6 7 8 9 10 11 12 $ pvdisplay /dev/sdb1 "/dev/sdb1" is a new physical volume of "5.00 GiB" --- NEW Physical volume --- PV Name /dev/sdb1 VG Name PV Size 5.00 GiB Allocatable NO PE Size 0 Total PE 0 Free PE 0 Allocated PE 0 PV UUID viN4Oq-ZeFx-3wTz-4zXf-0Z4N-Urcf-F2eMGi
查看pe分布 pvdisplay -m
可以查看该设备中PE的使用分布图。以下是某次显示结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ pvdisplay -m /dev/sda2 --- Physical volume --- PV Name /dev/sda2 VG Name centos PV Size <19.00 GiB / not usable 3.00 MiB Allocatable yes (but full) PE Size 4.00 MiB Total PE 4863 Free PE 0 Allocated PE 4863 PV UUID 0TXR4i-laLf-DqVh-lNVK-ybSt-io3c-QKDj5w --- Physical Segments --- Physical extent 0 to 4607: # 说明第0-4607的PE正被使用。PV中PE的序号是从0开始编号的 Logical volume /dev/centos/root Logical extents 0 to 4607 # 该PE在LV中的0-4607的LE位置上 Physical extent 4608 to 4862: # 说明4608-4862的PE正使用 Logical volume /dev/centos/swap Logical extents 0 to 254 # 该PE在LV中的位置是0-254
知道了PE的分布,就可以轻松地使用pvmove命令在设备之间进行PE数据的移动。具体关于pvmove的用法,可以自行百度,因为LVM缩容用处不大。
删除pv 1 2 3 4 5 6 7 $ pvremove /dev/sdb3 Labels on physical volume "/dev/sdb3" successfully wiped. $ pvscan PV /dev/sda2 VG centos lvm2 [<19.00 GiB / 0 free] PV /dev/sdb1 lvm2 [5.00 GiB] PV /dev/sdb2 lvm2 [2.00 GiB] Total: 3 [<26.00 GiB] / in use: 1 [<19.00 GiB] / in no VG: 2 [7.00 GiB]
管理VG
功能
命令
创建vg
vgcreate
扫描并列出所有的vg
vgscan
列出vg属性信息
vgdisplay
移除vg
vgremove
从vg中移除pv
vgreduce
将pv添加到vg中
vgextend
修改vg属性
vgchange
创建vg 创建一个名为slions_vg1的vg,并将/dev/sdb1与/dev/sdb2加入此vg,指定pe大小为8M(默认为4M)
创建vg后,是很难再修改pe大小的,只有空数据的vg可以修改,但这样还不如重新创建vg。
创建了vg实际上是在/dev目录下管理了一个vg目录/dev/slions_vg1,不过只有在创建了lv该目录才会被创建,而该vg中创建lv,将会在该目录下生成链接文件指向/dev/dm设备。
1 2 $ vgcreate -s 8M slions_vg1 /dev/sdb[1-2] Volume group "slions_vg1" successfully created
查看vg属性 1 2 3 4 $ vgscan Reading volume groups from cache. Found volume group "slions_vg1" using metadata type lvm2 Found volume group "centos" using metadata type lvm2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ vgdisplay slions_vg1 --- Volume group --- VG Name slions_vg1 System ID Format lvm2 Metadata Areas 2 Metadata Sequence No 1 VG Access read/write VG Status resizable MAX LV 0 Cur LV 0 Open LV 0 Max PV 0 Cur PV 2 Act PV 2 VG Size 6.98 GiB PE Size 8.00 MiB Total PE 894 Alloc PE / Size 0 / 0 Free PE / Size 894 / 6.98 GiB VG UUID PVvkTd-yRWc-PgGt-kBjy-loN3-Unmm-z37JrX
移除pv 从slions_vg1中移除一个pv,/dev/sdb2,再vgdisplay,发现pv少了一个,pe相应的也减少了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 $ vgreduce slions_vg1 /dev/sdb2 Removed "/dev/sdb2" from volume group "slions_vg1" $ vgdisplay slions_vg1 --- Volume group --- VG Name slions_vg1 System ID Format lvm2 Metadata Areas 1 Metadata Sequence No 2 VG Access read/write VG Status resizable MAX LV 0 Cur LV 0 Open LV 0 Max PV 0 Cur PV 1 Act PV 1 VG Size 4.99 GiB PE Size 8.00 MiB Total PE 639 Alloc PE / Size 0 / 0 Free PE / Size 639 / 4.99 GiB VG UUID PVvkTd-yRWc-PgGt-kBjy-loN3-Unmm-z37JrX
添加pv 再将刚才删掉的/dev/sdb2添加入slions_vg1中。
1 2 $ vgextend slions_vg1 /dev/sdb2 Volume group "slions_vg1" successfully extended
设置vg的状态 vgchange用于设置卷组的活动状态,卷组的激活状态主要影响的是lv。使用-a选项来设置。
将slions_vg1设置为活动状态。
1 2 $ vgchange -a y slions_vg1 0 logical volume(s) in volume group "slions_vg1" now active
将slions_vg1设置为非活动状态。
1 2 $ vgchange -a n slions_vg1 0 logical volume(s) in volume group "slions_vg1" now active
管理LV
功能
命令
创建lv
lvcreate
扫描并列出所有的lv
lvscan
列出lv属性信息
lvdisplay
移除lv
lvremove
缩小lv容量
lvreduce(lvresize)
增大lv容量
lvextend(lvresize)
改变lv容量
lvresize
创建lv 命令格式:
1 2 3 4 lvcreate {-L size(M/G) | -l PEnum} -n lv_name vg_name -L:根据大小来创建lv,即分配多大空间给此lv -l:根据PE的数量来创建lv,即分配多少个pe给此lv -n:指定lv的名称
当前slions_vg1有894个PE,大小为6.98G。
1 2 3 4 5 $ vgdisplay slions_vg1 |grep PE PE Size 8.00 MiB Total PE 894 Alloc PE / Size 0 / 0 Free PE / Size 894 / 6.98 GiB
使用-L和-l分别创建名称为slions_lv1和slions_lv2的lv。
1 2 3 4 $ lvcreate -L 3G -n slions_lv1 slions_vg1 Logical volume "slions_lv1" created. $ lvcreate -l +100%FREE -n slions_lv2 slions_vg1 Logical volume "slions_lv2" created.
创建lv后,将在/dev/firstvg目录中创建对应lv名称的软链接文件,同时也在/dev/mapper目录下创建链接文件,它们都指向/dev/dm设备。
1 2 3 4 5 6 7 8 9 10 11 $ ll /dev/slions_vg1/ 总用量 0 lrwxrwxrwx. 1 root root 7 8月 7 10:49 slions_lv1 -> ../dm-2 lrwxrwxrwx. 1 root root 7 8月 7 10:50 slions_lv2 -> ../dm-3 $ ll /dev/mapper/ 总用量 0 lrwxrwxrwx. 1 root root 7 8月 6 21:58 centos-root -> ../dm-0 lrwxrwxrwx. 1 root root 7 8月 6 21:58 centos-swap -> ../dm-1 crw-------. 1 root root 10, 236 8月 6 21:58 control lrwxrwxrwx. 1 root root 7 8月 7 10:49 slions_vg1-slions_lv1 -> ../dm-2 lrwxrwxrwx. 1 root root 7 8月 7 10:50 slions_vg1-slions_lv2 -> ../dm-3
查看lv属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $ lvscan ACTIVE '/dev/slions_vg1/slions_lv1' [3.00 GiB] inherit ACTIVE '/dev/slions_vg1/slions_lv2' [3.98 GiB] inherit ACTIVE '/dev/centos/root' [18.00 GiB] inherit ACTIVE '/dev/centos/swap' [1020.00 MiB] inherit $ lvdisplay /dev/slions_vg1/slions_lv1 --- Logical volume --- LV Path /dev/slions_vg1/slions_lv1 LV Name slions_lv1 VG Name slions_vg1 LV UUID aUGzfw-sypb-96Ux-hRxn-JXeS-2UIL-812m4T LV Write Access read/write LV Creation host, time slions_pc1, 2021-08-07 10:49:52 +0800 LV Status available # open 0 LV Size 3.00 GiB Current LE 384 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 253:2
格式化lv 我们通过格式化lv使其形成文件系统,就可以和普通磁盘一样挂载使用了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 $ mkfs.xfs /dev/slions_vg1/slions_lv1 meta-data=/dev/slions_vg1/slions_lv1 isize=512 agcount=4, agsize=196608 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=0, sparse=0 data = bsize=4096 blocks=786432, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal log bsize=4096 blocks=2560, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 $ mkdir /xfs_dir $ mount /dev/slions_vg1/slions_lv1 /xfs_dir/ $ df -Th|grep xfs_dir /dev/mapper/slions_vg1-slions_lv1 xfs 3.0G 33M 3.0G 2% /xfs_dir $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 20G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 19G 0 part ├─centos-root 253:0 0 18G 0 lvm / └─centos-swap 253:1 0 1020M 0 lvm [SWAP] sdb 8:16 0 20G 0 disk ├─sdb1 8:17 0 5G 0 part │ ├─slions_vg1-slions_lv1 253:2 0 3G 0 lvm /xfs_dir │ └─slions_vg1-slions_lv2 253:3 0 4G 0 lvm ├─sdb2 8:18 0 2G 0 part │ └─slions_vg1-slions_lv2 253:3 0 4G 0 lvm ├─sdb3 8:19 0 10G 0 part └─sdb4 8:20 0 3G 0 part sr0 11:0 1 10G 0 rom
也可以使用file -s查看lv的文件系统,由于/dev/slions_vg1和/dev/mapper下的lv都是链接到/dev/下块设备的链接文件,所以只能对块设备进行查看,否则查看的结果也仅仅只是个链接文件类型。
1 2 $ file -s /dev/dm-2 /dev/dm-2: SGI XFS filesystem data (blksz 4096, inosz 512, v2 dirs)
LVM扩容 在文章的开头已经说了,lvm最大的优势就是其可伸缩性,而其伸缩性又更偏重于扩容,这是使用lvm的最大原因。
扩容的实质是将vg中空闲的pe添加到lv中,所以只要vg中有空闲的pe,就可以进行扩容,即使没有空闲的pe,也可以添加pv,将pv加入到vg中增加空闲pe。
扩容流程
使用lvextend或者lvresize添加更多的pe或容量到lv中
使用resize2fs命令(xfs则使用xfs_growfs)将lv增加后的容量增加到对应的文件系统中
扩容示例 将/dev/sdb3创建为pv并加入slions_vg1,查看此时vg的pe状态,已经多了1279个PE,空余大小为9.99g。
1 2 3 4 5 6 7 8 9 10 $ pvcreate /dev/sdb3 Physical volume "/dev/sdb3" successfully created. $ vgextend slions_vg1 /dev/sdb3 Volume group "slions_vg1" successfully extended $ vgdisplay slions_vg1 |grep PE PE Size 8.00 MiB Total PE 2173 Alloc PE / Size 894 / 6.98 GiB Free PE / Size 1279 / 9.99 GiB
将其全部添加到slions_lv1中,有两种方式添加:按容量大小添加和按PE数量添加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $ umount /dev/slions_vg1/slions_lv1 $ lvextend -L +5G /dev/slions_vg1/slions_lv1 Size of logical volume slions_vg1/slions_lv1 changed from 3.00 GiB (384 extents) to 8.00 GiB (1024 extents). Logical volume slions_vg1/slions_lv1 successfully resized. $ vgdisplay slions_vg1 |grep PE PE Size 8.00 MiB Total PE 2173 Alloc PE / Size 1534 / 11.98 GiB Free PE / Size 639 / 4.99 GiB $ lvextend -l +639 /dev/slions_vg1/slions_lv1 Size of logical volume slions_vg1/slions_lv1 changed from 8.00 GiB (1024 extents) to 12.99 GiB (1663 extents). Logical volume slions_vg1/slions_lv1 successfully resized. $ lvscan ACTIVE '/dev/slions_vg1/slions_lv1' [12.99 GiB] inherit ACTIVE '/dev/slions_vg1/slions_lv2' [3.98 GiB] inherit ACTIVE '/dev/centos/root' [18.00 GiB] inherit ACTIVE '/dev/centos/swap' [1020.00 MiB] inherit
也可以使用lvresize来增加lv的容量方法和lvextend一样。如:
1 2 $ lvresize -L +5G /dev/slions_vg1/slions_lv1 $ lvresize -l +639 /dev/slions_vg1/slions_lv1
将slions_lv1挂载,查看该lv对应文件系统的容量。
1 2 3 $ df -Th /xfs_dir/ 文件系统 类型 容量 已用 可用 已用% 挂载点 /dev/mapper/slions_vg1-slions_lv1 xfs 3.0G 33M 3.0G 2% /xfs_dir
容量并没有增加,因为只是lv的容量增加了,而文件系统的容量却没有增加。
需要使用resize2fs工具来改变ext文件系统的大小,如果是xfs文件系统,则使用xfs_growfs。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ xfs_growfs /xfs_dir/ meta-data=/dev/mapper/slions_vg1-slions_lv1 isize=512 agcount=4, agsize=196608 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=0 spinodes=0 data = bsize=4096 blocks=786432, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal bsize=4096 blocks=2560, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 data blocks changed from 786432 to 3405824 $ df -Th /xfs_dir/ 文件系统 类型 容量 已用 可用 已用% 挂载点 /dev/mapper/slions_vg1-slions_lv1 xfs 13G 33M 13G 1% /xfs_dir
END 其实LVM里还包括了缩容与快照的功能,使用场景不多,这里也不多阐述,且现在大多文件系统都为xfs,其也不支持收缩,想要了解的可自行百度。