S_lion's Studio

逻辑卷管理LVM

字数统计: 3.5k阅读时长: 16 min
2021/08/06 Share

总所周知不论是机械硬盘还是固态磁盘大小都是固定的,当磁盘空间满了后只能通过删除无用数据来保持磁盘的可用性,这篇介绍的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

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 #使用剩余所有的PE
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。

扩容流程

  1. 使用lvextend或者lvresize添加更多的pe或容量到lv中
  2. 使用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,其也不支持收缩,想要了解的可自行百度。

CATALOG
  1. 1. LVM术语
  2. 2. LVM的写入机制
  3. 3. LVM实现图解
  4. 4. LVM的实现
    1. 4.1. 管理pv
      1. 4.1.1. 创建PV
      2. 4.1.2. 查看pv属性
      3. 4.1.3. 查看pe分布
      4. 4.1.4. 删除pv
    2. 4.2. 管理VG
      1. 4.2.1. 创建vg
      2. 4.2.2. 查看vg属性
      3. 4.2.3. 移除pv
      4. 4.2.4. 添加pv
      5. 4.2.5. 设置vg的状态
    3. 4.3. 管理LV
      1. 4.3.1. 创建lv
      2. 4.3.2. 查看lv属性
      3. 4.3.3. 格式化lv
    4. 4.4. LVM扩容
      1. 4.4.1. 扩容流程
      2. 4.4.2. 扩容示例
  5. 5. END