LVM磁盘管理实战

概述

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模式下可能有多块硬盘,数据就不够安全了。

所以我们需要有一系列的措施来保障数据安全,可以有:

  • 准备一个足够大容量的硬盘,将原来多个小硬盘的数据转移到这个大硬盘上,减少一点硬盘损坏概率。
  • 定期做数据备份

参考资料

Linux LVM逻辑卷相关管理

相关推荐
一只叫煤球的猫3 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9653 小时前
tcp/ip 中的多路复用
后端
bobz9653 小时前
tls ingress 简单记录
后端
皮皮林5515 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友5 小时前
什么是OpenSSL
后端·安全·程序员
bobz9655 小时前
mcp 直接操作浏览器
后端
前端小张同学7 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook7 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康8 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在8 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net