概述
LVM全称Logical Volume Manger,即逻辑卷管理,是Linux环境下对磁盘分区进行管理的一种机制。相比起传统的磁盘分区管理,作用是可以让我们不在容量不足的时候做数据迁移,只需要动态的添加容量即可。
我们来回忆一下传统的服务器磁盘的管理方式。
传统的存储管理
给服务器新增一块硬盘,通过【fdisk -l】的命令来查看硬盘信息,然后对其进行分区,最后使用【mount】命令来挂载。
这样我们就能得到该硬盘对应的挂载路径,像这样:
shell
文件系统 容量 已用 可用 已用% 挂载点
/dev/sdb1 3.7T 1002G 2.7T 27% /home/data
这种方式简单直接,但是我们在对系统分区,或者添加新硬盘的时候,都会有一个困扰,就是如何精确的评估和分配各个硬盘分区的容量,如果太小,未来容量不够时就要做数据迁移,迁移到另一个更大容量的硬盘上;如果太大,则容易造成磁盘容量的浪费。
浪费磁盘空间还是小事,主要问题在容量不够需要数据迁移时,要对整个文件系统做备份,然后停机、迁移、恢复,过程中还容易导致服务的异常,这是一件非常麻烦的事情,LVM技术则可以解决这个问题。
LVM磁盘分区
LVM在物理设备也就是磁盘和文件系统上做了一层抽象,使得我们最终得到的文件路径可以有动态调整的容量,也就是说,我们一开始将一个硬盘容量映射到指定路径,当容量不够时,添加一个新的硬盘并进行一些LVM的设置,使得两个硬盘的容量可以共同提供给一个文件路径,由此实现了容量的动态扩容,还不会影响上层使用的应用,应用无需再进行数据迁移。
同时,每一个硬盘的容量是可以按需分配的,每一个硬盘就像一个个水桶,需要的地方舀一勺即可,不用理会是哪一个硬盘在提供容量。
两者比较
传统的存储管理方式效率最高,因为LVM做了一层抽象,所以相比较效率会低,虽然说应该根据实际场景来选择,但是LVM是趋势,以后服务器的硬盘只会越来越多,所以学习LVM还是十分有必要的。
LVM必学知识
实战之前先过一遍LVM的几个概念:
-
PV:物理卷(Physical Volume),指磁盘分区,也就是一块磁盘进行了LVM分区后得到的分区路径,如:
shell/dev/sdb1
这是添加新磁盘后,对其进行的第一步操作:制作成LVM分区格式。
-
VG:卷组(Volume Group),由一个或多个物理卷PV组成,通过VG我们可以创建一个或多个LV(逻辑卷,下面会说到)。
-
LV:逻辑卷(Logical Volume),在此之上可以建立文件系统,比如映射到/home或/data路径下。
-
PE:物理块(Physical Extent),是物理卷PV的基本划分单元,属于基础知识,新手可以先不理会,先关注PV、VG和LV。
从上面的结构可以初步了解到,相比于传统模式,LVM多了一层VG的封装,正是因为这层封装,使得我们的文件系统变得十分的灵活,接下来我们通过实战来加深理解。
LVM实战
实战的步骤如下:
- 利用VG剩余可用容量
- 添加硬盘,制作成LVM分区格式。
- 重新分区
- 创建PV及删除PV
- 创建VG及删除VG
- 创建LV及删除LV
- 扩容和缩容
在实战前先查看一下当前的磁盘信息,有一个大概的了解:
shell
# 命令(查看磁盘设备信息):
lsblk
# 输出:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 63.9M 1 loop /snap/core20/2105
loop1 7:1 0 87M 1 loop /snap/lxd/27037
loop2 7:2 0 40.4M 1 loop /snap/snapd/20671
loop3 7:3 0 63.9M 1 loop /snap/core20/2264
# 第一块磁盘(100G)
sda 8:0 0 100G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 2G 0 part /boot
└─sda3 8:3 0 98G 0 part
# 类型(Type)是LVM,表示此LV上建立了文件系统:根路径
└─ubuntu--vg-ubuntu--lv 253:0 0 49G 0 lvm /
sr0 11:0 1 2G 0 rom
通过上面我们可以了解到,当前系统只有一块硬盘(100G),并制作成了LVM分区,可以看到根路径就建立在LV上面,容量为49G。
疑问:sda3分区明明有98G,为什么LV只有49G?,剩下的49G哪去了?
因为此LV是通过VG创建,VG在创建LV的时候是可以选择指定的容量的,我们看看VG信息就能明白。
shell
# 命令(查看VG详细信息):
vgdisplay
# 输出:
--- Volume group ---
VG Name ubuntu-vg
System ID
Format lvm2
Metadata Areas 1
Metadata Sequence No 2
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 1
Open LV 1
Max PV 0
Cur PV 1
Act PV 1
# VG总容量
VG Size <98.00 GiB
PE Size 4.00 MiB
Total PE 25087
# 已分配的容量
Alloc PE / Size 12543 / <49.00 GiB
# 剩余可用容量
Free PE / Size 12544 / 49.00 GiB
VG UUID NTQ00F-s9bd-c0ma-h64J-wdEL-vn5x-N3iJMY
上面显示剩余可用容量为49G,也就是说VG总容量98G,其中49G拿去建立了根路径的文件系统,还剩下49闲置着没有用,这闲置的容量,我们可以用来给根路径继续增加容量,也可以去建立新的LV,映射一个新的路径,具体操作后面会说到。
利用VG剩余可用容量进行扩容
查看磁盘使用情况:
shell
# 命令(磁盘使用情况):
df -h
# 输出:
Filesystem Size Used Avail Use% Mounted on
tmpfs 388M 1.6M 387M 1% /run
# 看这里
/dev/mapper/ubuntu--vg-ubuntu--lv 48G 6.8G 39G 15% /
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/sda2 2.0G 129M 1.7G 8% /boot
tmpfs 388M 4.0K 388M 1% /run/user/0
根路径LV的容量为49G,假设现在不够了,要扩容。
查看VG剩余容量,在VG没有更多容量时,我们才考虑添加新的硬盘。
shell
# 命令(查看更为精简的VG信息,也可以使用vgdisplay):
vgs
# 输出:
VG #PV #LV #SN Attr VSize VFree
ubuntu-vg 1 1 0 wz--n- <98.00g 49.00g
还有剩余容量(VFree)还有49G,那就用上。
扩容命令有以下几种方式。
扩容到指定大小
shell
# 命令格式
lvextend -L <容量> <LV路径>
# 如扩容到60G,相比原来的49G增加了11G
lvextend -L 60G /dev/mapper/ubuntu--vg-ubuntu--lv
# 通过lsblk查看效果
lsblk
在原有基础上增加多少
shell
# 命令格式,注意这里有个【+】号
lvextend -L +<容量> <LV路径>
# 如
lvextend -L 10G /dev/mapper/ubuntu--vg-ubuntu--lv
lvextend -L +38G /dev/mapper/ubuntu--vg-ubuntu--lv
# 通过lsblk查看
lsblk
将VG剩余容量全部分给LV
shell
# 命令格式:
lvextend <LV> <分区>
# 如:
lvextend /dev/mapper/ubuntu--vg-ubuntu--lv /dev/sda3
扩容后要使用resize2fs命令重新计算大小
shell
# 通过df -h查看
df -h
Filesystem Size Used Avail Use% Mounted on
tmpfs 388M 1.6M 387M 1% /run
# 这里并没有正确显示,因为我们还需要通过resize2fs来修改文件系统的大小
/dev/mapper/ubuntu--vg-ubuntu--lv 48G 6.9G 39G 16% /
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/sda2 2.0G 129M 1.7G 8% /boot
tmpfs 388M 4.0K 388M 1% /run/user/0
shell
# 命令格式
resize2fs <LV路径>
# 如:
resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv
扩容后通过【df -h】命令显示的还是原来的数据,需要使用【resize2fs】命令来重新计算才能正确显示。
数据精确问题
命令默认显示的容量单位是G,有时候我们扩容时会提示容量不够,比如剩余容量显示为【<10G】,当我们扩容10G会提示不够空间,是因为实际上剩余的容量是9G-10G,那么这时候我们就应该把单位修改成M了,通过给命令增加【--units m】来显示M单位的信息:
shell
pvs --units m
输出:
shell
PV VG Fmt Attr PSize PFree
/dev/sda3 ubuntu-vg lvm2 a-- 100348.00m 38908.00m
那么扩容命令就可以为:
shell
lvextend -L +38908m /dev/mapper/ubuntu--vg-ubuntu--lv
注:df -h命令改成df -hm,也能看到mb单位的显示。
新增硬盘扩容
好了,现有VG全部用完,
先插入一块硬盘,我使用的是VMware,所以很容易模拟。
shell
# 通过lsblk查看
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 63.9M 1 loop /snap/core20/2105
loop1 7:1 0 87M 1 loop /snap/lxd/27037
loop2 7:2 0 40.4M 1 loop /snap/snapd/20671
loop3 7:3 0 63.9M 1 loop /snap/core20/2264
sda 8:0 0 100G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 2G 0 part /boot
└─sda3 8:3 0 98G 0 part
└─ubuntu--vg-ubuntu--lv 253:0 0 98G 0 lvm /
# 看到我们新增加的硬盘,容量20G(看不到可以重启虚拟机试试)
sdb 8:16 0 20G 0 disk
sr0 11:0 1 2G 0 rom
制作成LVM分区
shell
# 通过fdisk -l或lsblk得知,新硬盘的路径为:/dev/sdb
# 分区
fdisk /dev/sdb
# 输入m查看所有可用命令,输入n表示创建新分区,这里输入:n
Command (m for help): n
# p为主分区,e为扩展分区,这里输入:p
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
# 确定主分区,默认1,这里输入:1(或不输出直接回车)
Partition number (1-4, default 1):
# 起始扇区,有默认就直接回车了
First sector (2048-41943039, default 2048):
# 结束扇区,默认回车
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-41943039, default 41943039):
# 然后提示下面这句话,表示成功创建了一个20G容量的分区
Created a new partition 1 of type 'Linux' and of size 20 GiB.
# 最后这里输入w表示保存
Command (m for help): w
# 输出此句表示分区完成。
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
# 此时用fdisk -l或lsblk可以看到分区信息
fdisk -l
# 输出:
Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 41943039 41940992 20G 83 Linux
新硬盘分完区,我们才能实际进行使用。
创建PV
shell
# 该路径为新磁盘分区后得到的路径
pvcreate /dev/sdb1
# 查看pv列表
pvs
# 输出:
PV VG Fmt Attr PSize PFree
/dev/sda3 ubuntu-vg lvm2 a-- <98.00g 0
/dev/sdb1 lvm2 --- <20.00g <20.00g
上面显示,/dev/sdb1的PV还没有分配给VG,所以我们可以选择将其分配给新创建的VG,或者是原有的VG。
扩容旧VG
shell
# 命令格式
vgextend <VG> <PV>
# 如:
vgextend ubuntu-vg /dev/sdb1
# 查看vg信息
vgs
# 输出:
VG #PV #LV #SN Attr VSize VFree
ubuntu-vg 2 1 0 wz--n- 117.99g <20.00g
这就成了,旧VG的容量原本是98G,现在增加了20G,就变成117.99G了,可用容量20G。
觉得单位不精确可以加上【--units -m】命令来显示Mb单位的信息。
移除已添加的PV卷
shell
# 命令格式
vgreduce <VG> <PV>
# 如:
vgreduce ubuntu-vg /dev/sdb1
后悔药,加错了可以撤销。
创建VG
shell
# 命令格式
vgcreate <VG> <分区路径>
# 如:
vgcreate test-vg /dev/sdb1
# 命令:
vps
# 输出:
VG #PV #LV #SN Attr VSize VFree
test-vg 1 0 0 wz--n- <20.00g <20.00g
ubuntu-vg 1 1 0 wz--n- <98.00g 0
创建了一个新VG,容量20G,等下想想怎么用。
创建LV
shell
# 命令格式一:(剩余可用PE数可以用命令【vgdisplay <VG> --units m】查看)
lvcreate -L <剩余可用PE数> <VG> -n <LV>
# 如:
lvcreate -L 20476m test-vg -n test-lv
# 或
lvcreate -L 10G test-vg -n test-lv
# 删除lv命令
lvremove <VG> <LV>
# 如:
lvremove test-vg test-lv
# 命令格式二:(使用100%的剩余可用空间,这里-l要记得小写,然后注意vg和lv顺序)
lvcreate -l +100%FREE -n <VG> <LV>
# 如:
lvcreate -l +100%FREE -n test-lv test-vg
# 格式化逻辑卷
# 命令格式
mkfs.ext4 /dev/<VG>/<LV>
# 如:
mkfs.ext4 /dev/test-vg/test-lv
# 挂载路径(临时挂载,重启后会失效)
# 命令格式
mount /dev/<VG>/<LV> <路径>
# 如:
mount /dev/test-vg/test-lv /data
# 命令(查看磁盘使用情况):
df -h
# 输出:
Filesystem Size Used Avail Use% Mounted on
tmpfs 388M 1.6M 387M 1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv 97G 7.6G 85G 9% /
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/sda2 2.0G 252M 1.6G 14% /boot
tmpfs 388M 4.0K 388M 1% /run/user/0
# 新LV有10G的容量(9.7G差不多了)
/dev/mapper/test--vg-test--lv 9.7G 24K 9.2G 1% /data
缩容和删除
LVM缩容之前需要先取消挂载源路径,是因为缩小逻辑卷可能会导致文件系统的大小超过逻辑卷的大小,从而导致数据丢失或文件系统损坏,所以要先取消挂载源路径,确保文件系统不再使用状态。
基于此原因,不建议工作路径使用根路径,应该创建一个LV路径来使用,这样以后还可以缩容,而挂载根路径缩容是很麻烦的。
缩容前切记先对数据进行备份,安全第一。
LV
先取消挂载:
shell
# 命令格式:
umount <挂载点路径>
# 如:
umount /data
缩容:
shell
# 命令格式
lvreduce --resizefs -L <缩容大小> <LV>
# 如(缩小5G):
lvreduce --resizefs -L 5G /dev/mapper/test--vg-test--lv
删除LV:
干脆不要了:
shell
# 删除lv命令
lvremove <VG> <LV>
# 如:
lvremove test-vg test-lv
VG
vgreduce:从卷组VG中一处物理卷PV,但是卷组中剩余的最后一个物理卷是不能删除的。
shell
# 命令格式
vgreduce <VG> <PV>
# 如:
vgreduce test-vg /dev/sdb1
vgremove:删除指定的卷组VG,如果VG上有逻辑卷LV时,需要进行确认删除,防止误删。
shell
# 命令格式:
vgremove <VG>
# 如(会有提示是否确定,根据内容进行回答即可):
vgremove test-vg
# 输出:
Do you really want to remove volume group "test-vg" containing 1 logical volumes? [y/n]: y
Do you really want to remove and DISCARD active logical volume test-vg/test-lv? [y/n]: y
Logical volume "test-lv" successfully removed
Volume group "test-vg" successfully removed
PV
删除:
shell
# 命令格式,如果有关联VG,需要先执行vgreduce命令移除后再执行
pvremove <PV>
# 如:
pvremove /dev/sdb1
转移:
shell
# 命令格式:
pvmove <PV> <PV>
# 如:
pvmove /dev/sdc1 /dev/sdb1
数据安全问题
LVM中,一个LV可能由多个磁盘供应容量,其中任意一块磁盘损坏都会导致服务不可用,也就是说服务稳定性低了很多,因为传统模式下只有一块硬盘,而在LVM模式下可能有多块硬盘,数据就不够安全了。
所以我们需要有一系列的措施来保障数据安全,可以有:
- 准备一个足够大容量的硬盘,将原来多个小硬盘的数据转移到这个大硬盘上,减少一点硬盘损坏概率。
- 定期做数据备份