[媒体库]NAS存盘缓存层实践

先介绍一下实践的背景：
一直以来，个人比较摈弃群晖向 NAS 系统，并不是类似于群晖这类 NAS 操作系统不好用，相反正是因为过于方便导致学习不到 linux 相关的命令操作，所以自打开始玩家庭流媒体以来，一直以 pve 作为底座，通过虚拟化 linux 操作系统来手动构建自己的流媒体，以此方式来激励自己学习 linux 方面的操作。

因此，nas 缓存也是构建于 pve 操作系统中的。

2023 年下半年，从玩 nas 开始，逐渐发现自己的磁盘空间不够，出于对速度的考虑，最早采用 RAID10 的方案将磁盘附加给虚拟机。由于当时 qb 和 nas 管理系统分离，通过 nfs 挂载的方式使得下载目录被下载器和媒体管理工具共同监控，因此并未实际感受到 hdd 磁盘写入速度带来的影响。直到 2024 年开春，因为工作调动，搬家后想着反正也有一个月没做种了，趁此机会重新整理一下我的 nas。于是乎，折腾之旅又双叒叕开始了。

1、重构系统底座

保留了 pve 底座，原先将 qb 部署于单独的虚拟机中，将 nas 管理工具、字幕工具、辅种工具统一部署到 k8s 环境中。现在将所有工具统一部署到了一个虚拟机中，为此，我创建了一个 6C64G 的 rocky linux 作为媒体库目录，并且将整合后的 30T 机械硬盘空间分配给 rocky

磁盘空间整合使用 lvm 逻辑卷的方式。

什么是 lvm 逻辑卷？

LVM（逻辑卷管理）是一种在 Linux 环境下用于管理磁盘驱动器和相似存储设备的一种方法。通过使用 LVM 可以更灵活地管理存储空间。逻辑卷是在 LVM 管理下创建和使用的存储空间单位。
LVM 的组件包括：物理卷（PV）、卷组（VG）、逻辑卷（LV）
LVM 允许动态调整磁盘大小、支持快照功能
lvm 的方式于 raid10 相比，不必牺牲一半的磁盘空间做数据冗余，但缺失了 raid10 的高性能

1.1 构建 lvm 逻辑卷

Copy
> root@ubuntu:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sdc 8:32 0 3.6T 0 disk
└─lvgroup-lv29_corig 253:12 0 29.1T 0 lvm
└─lvgroup-lv29 253:4 0 29.1T 0 lvm /mnt/lv29
sdd 8:48 0 3.6T 0 disk
└─lvgroup-lv29_corig 253:12 0 29.1T 0 lvm
└─lvgroup-lv29 253:4 0 29.1T 0 lvm /mnt/lv29
sde 8:64 0 3.6T 0 disk
sdf 8:80 0 3.6T 0 disk
└─lvgroup-lv29_corig 253:12 0 29.1T 0 lvm
└─lvgroup-lv29 253:4 0 29.1T 0 lvm /mnt/lv29
sdh 8:112 0 14.6T 0 disk
└─lvgroup-lv29_corig 253:12 0 29.1T 0 lvm
└─lvgroup-lv29 253:4 0 29.1T 0 lvm /mnt/lv29
sdi 8:128 0 3.6T 0 disk
└─lvgroup-lv29_corig 253:12 0 29.1T 0 lvm
└─lvgroup-lv29 253:4 0 29.1T 0 lvm /mnt/lv29
sdj 8:144 0 7.3T 0 disk
└─sdj1 8:145 0 7.3T 0 part

构建的结果如上所示，sdc、sdd、sdf、sdh、sdi、sdj 共 6 快磁盘组合成 29.1T 的 lv29 逻辑磁盘

具体操作如下：

Copy
## 创建pv物理卷
> pvcreate /dev/sdc /dev/sdd /dev/sdf /dev/sdh /dev/sdi /dev/sdj
## 创建lvgroup的卷组
> vgcreate lvgroup /dev/sdc /dev/sdd /dev/sdf /dev/sdh /dev/sdi /dev/sdj
## 创建lv逻辑卷,并将所有磁盘空间分配给卷组lvgroup
> lvcreate -n lv29 -l 100%VG lvgroup

创建好后逻辑卷就像一般磁盘一样存在于系统中，接下来需要对其设置文件系统格式，并且设定挂载点，之后就可以正常使用

Copy
## 格式化的方式创建ext4文件系统
> mkfs.ext4 /dev/lvgroup/lv29
## 创建挂载点
> mkdir -p /mnt/media
## 挂载逻辑卷
> mount /dev/lvgroup/lv29 /mnt/media
## 开机自动挂载
> echo "/dev/lvgroup/lv29 /mnt/media ext4 defaults 0 0" | tee -a /etc/fstab

1.2 在 pve 中将磁盘挂载到 linux 中

在虚拟机的硬件选项中添加新增好的 lvgroup 逻辑卷，并填写完整的可用空间即可完成对磁盘的添加

2、lvm 缓存层

实现磁盘挂载并且使用了一段时间后，无缓存层的弊端逐渐显现。例如在 nas 管理系统中添加种子文件进行下载，qb 接管多个下载任务时，nas 管理系统在搜索媒体或者进行其他操作时，由于 qb 正在对磁盘进行写入操作，此时会出现系统卡顿的情况。

下载的文件直接写入 hdd 的操作会占用内存作为第一个缓存硬件，这是为了提高文件的写入效率，减少对磁盘的写操作。

由于内存大小仅有 GB 量级的大小，在文件块在写入磁盘过程中，会经过磁盘的 IO（页缓冲区）进行缓存，当大量的文件、多个下载的内容同时对 hdd 逻辑卷执行写操作的时候，磁盘 IO 很容易被占满。在 nas 管理工具中对下载目录的监控则是对磁盘的读操作，在存在大量文件写入 hdd 的时候使用，此时读写同时使用磁盘 IO 就会出现磁盘卡 IO 的情况，严重影响了使用体验，具体表现在当我存在 3 个以上的下载任务时，nas 管理工具就会出现非常大的延迟，页面刷新都需要 5-30 秒。因为此时的磁盘 IO、内存都出现了非常严重的堵塞。

因此引入 lvm 缓存层的机制，借用 sdd 的高 IOPS 的特性可以有效缓解 hdd 容易卡 IO 这一现象，具体来说就是当用户执行下载任务时，被下载的文件块，先进入内存 memory，后写入到 lvm 缓存区（sdd），最后写入到 hdd。

2.1 为已有的 lvm 逻辑卷增加缓冲层

我有两块 ssd 磁盘，sdb 和 sdg，现在要附加给 lvm 并且用作写入的缓存，由于逻辑卷缓存层的缓存逻辑在 lvm 中是自管理的，因此，我仅需添加到 lvm 的缓存层即可

Copy
## 为ssd创建逻辑磁盘
pvcreate /dev/sdb /dev/sdg
## 扩展到逻辑卷lvgroup
vgextend lvgroup /dev/sdb /deb/sdg
## 将所有空间（当前仅剩ssd为空余空间）加入到缓存池
lvcreate --type cache-pool -l 100%FREE -n lv_cache_pool lvgroup
## 将现有的缓存池附加给逻辑卷lv29
lvconvert --type cache --cachepool lvgroup/lv_cache_pool lvgroup/lv29