0%

NFS配合BTRFS的媒体下载播放组合拳

前情提要

在之前的文章”在OpenMediaVault上配置NFS over RDMA“中,我提到了我对内网软硬件设计的架构。

这样设计的原因是希望将各个业务模块拆分开来,方便维护,避免一个业务模块出错的时候引起整个系统崩溃。

需要解决什么问题?

我现在习惯通过BT/PT站点下载视频媒体资源,PT的理念是大家互相帮助,下载资源后也要提供上传资源,这样其他人才能获取到相应的资源。所以资源下载完后继续保持软件持续进行上传。

下载的资源多了,我们也就需要更大容量的存储空间,单一硬盘的空间终究是有限的,所以我们可能需要多块硬盘组合起来作为一个资源池。

总的来说,需要解决以下的问题

  • 如何利用多个硬盘的空间
  • 如何管理这些硬盘空间
  • 如何尽可能减少磁盘空间的浪费

之前的方案介绍

在此之前,我是通过MergerFS的方式来将多个磁盘合并,对于上层来说,MergerFS将多个磁盘中的文件组合到一个挂载点提供给用户,这样即便使用了多块硬盘,用户访问时,就像访问一个独立的分区一样,但磁盘空间是叠加的。

使用这种方式时,如果任意一块盘损坏,也不会影响其他盘上的内容,这也是一开始我选用MergerFS的一个很重要的原因。

但在实际使用中我发现,MergerFS会把文件打散存放在不同的硬盘上,对于目录来说,会在每个硬盘上创建一个同样层级关系的目录,但每个文件只会存在其中一个硬盘上,这就有可能导致有些文件东一个西一个,虽然MergerFS有提供不同的策略来存放新加入的文件,但总感觉后期维护的时候会比较麻烦。

但放弃这个方案的最主要原因是,在使用Emby、Plex等媒体服务器软件时,它们有时会无法识别出存储在MergerFS上的媒体文件。

曾经我是单独用一个RAID0阵列作为PT下载盘,下载完后通过脚本拷贝到MergerFS上,相当于每一个媒体文件我实际上都保存了两份,空间其实有比较大的浪费。

而之所以要拷贝一份,是因为后续媒体服务器运行时,可能会对媒体的nfo信息修改,我不希望媒体服务器与pt下载的软件产生冲突。

当前方案

  • NFS 4.2 + RDMA
  • BTRFS

NFS over RDMA可以提供更出色的性能,而必须指定使用4.2版本的NFS是因为,在这个版本中,NFS提供了Server-side Copy功能。换句话来说,如果我需要在NFS共享的目录中拷贝内容,相关的数据不需要流向NFS客户端再流回NFS服务端,所有拷贝操作可以在服务端自己完成,避免了拷贝时的带宽消耗。

理论上NFS换成SMB也可以,SMB也有支持RDMA的能力,并且SMB也有服务端拷贝的功能,但实际配置起来感觉NFS简单很多,而且我的业务也都运行在Linux上,所以就直接选NFS了。

而BTRFS是一个支持CoW(Copy on Write 写时复制)的文件系统,即复制文件时,并不会真正的创建一个新的空间用来保存这份文件,这份文件仍然指向原有的存储空间,而当文件产生修改的时候,才会消耗存储空间保存修改过后的文件。这样一来,我PT下载完后,保持原有的拷贝逻辑,但是不会额外占用一份空间,而当媒体服务器对nfo等信息修改时,才会对这些信息新开辟一个空间,而这些信息一般都比较小,额外报错一份修改后的并不会让硬盘空间有什么压力。

并且,BTRFS支持组建RAID,后期也可以很方便地往BTRFS资源池中添加硬盘进行扩容。

在扩容和利用磁盘空间这一块,其实跟MergerFS并没有分出本质的胜负,某种意义上来说,MergerFS单盘损毁不会影响其他硬盘,反而还略胜一筹。但考虑到CoW的特性,综合考虑下,我认为BTRFS更适合我的使用场景。

另外,我仔细想了想,即便组RAID模式,有硬盘坏了,这些资源全都损坏丢失,我也没什么所谓,因为保存的基本都是已经观看过的视频媒体文件了,真有需要,重新下载一份就好了。RAID0模式相当于把一个文件拆成很多个区块,然后把这些区块分散保存到不同的硬盘上,可以提升读写性能,但当有物理磁盘损坏时,就会导致文件损坏且无法恢复。(假设有4块硬盘,一个文件拆分成a b c d四个部分,任意一块硬盘损坏后,这个文件其中一个部分就丢失了,因此文件相当于损毁了)

但是怎么知道要重新下载那些文件呢?

btrfs的RAID将数据拆分成了metadata、system和data三个部分,其中data部分是存储我们实际的数据的,而metadata和system中则保存了硬盘分区相关的信息。而我们可以将metadata、system部分以RAID1镜像模式运行,而data以RAID0条带运行。这样一来,即便有物理硬盘损坏,由于其他硬盘上有metadata和system部分的镜像数据,所以btrfs文件系统仍然可以以降级模式继续运行。

当降级运行时,理论上我们仍然可以访问分区里的目录信息和文件名称等信息,这样我们就知道我们需要重新下载哪些数据了,然后替换掉损坏的硬盘后,重新下载数据就好了。

因此,这套方案有以下特点:

  1. 使用NFS over RDMA,性能相比传统基于TCPIP协议栈的文件共享性能更高
  2. NFS指定使用4.2版本,实现Server-side Copy,减少网络传输
  3. 文件服务器使用BTRFS文件系统,支持写时复制,复制文件时可以通过cp --reflink=always方式来快速复制创建引用关系,提高硬盘空间利用率
  4. 物理硬盘损坏时,仍然能获取到目录结构和文件名等信息。

配置BTRFS与扩容

我先通过OpenMediaVault WEB控制台创建了一个双盘RAID0的BTRFS文件系统

1
2
3
4
5
root@openmediavault:~# btrfs filesystem show
Label: none uuid: 5d347e39-e8b0-4ddc-b159-a7cb00649068
Total devices 2 FS bytes used 144.00KiB
devid 1 size 5.46TiB used 1.51GiB path /dev/sdc
devid 2 size 5.46TiB used 1.51GiB path /dev/sde

在WEB上似乎没有看到添加盘到已有文件系统的选项,因此使用命令手动添加

1
2
3
4
5
6
7
8
9
10
11
12
Disk /dev/sdg: 5.46 TiB, 6001175126016 bytes, 11721045168 sectors
Disk model: ST6000NM0034
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes


Disk /dev/sdi: 5.46 TiB, 6001175126016 bytes, 11721045168 sectors
Disk model: ST6000NM0034 X
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes

另外两个6T的硬盘符为/dev/sdg/dev/sdi,现有的btrfs文件系统实际挂载点在/srv/dev-disk-by-uuid-5d347e39-e8b0-4ddc-b159-a7cb00649068

1
2
root@openmediavault:~# df -h | grep 5d347e39-e8b0-4ddc-b159-a7cb00649068
/dev/sdc 11T 3.7M 11T 1% /srv/dev-disk-by-uuid-5d347e39-e8b0-4ddc-b159-a7cb00649068

使用如下命令添加硬盘到已有的btrfs文件系统

1
2
3
4
5
6
7
8
/srv/dev-disk-by-uuid-5d347e39-e8b0-4ddc-b159-a7cb00649068
root@openmediavault:~# btrfs device add /dev/sdg /srv/dev-disk-by-uuid-5d347e39-e8b0-4ddc-b159-a7cb00649068
root@openmediavault:~# btrfs filesystem show
Label: none uuid: 5d347e39-e8b0-4ddc-b159-a7cb00649068
Total devices 3 FS bytes used 144.00KiB
devid 1 size 5.46TiB used 1.51GiB path /dev/sdc
devid 2 size 5.46TiB used 1.51GiB path /dev/sde
devid 3 size 5.46TiB used 0.00B path /dev/sdg

可以看到SDG已经添加到btrfs文件系统中了,同样方法继续添加SDI

1
2
3
4
5
6
7
root@openmediavault:~# btrfs filesystem show
Label: none uuid: 5d347e39-e8b0-4ddc-b159-a7cb00649068
Total devices 4 FS bytes used 144.00KiB
devid 1 size 5.46TiB used 1.51GiB path /dev/sdc
devid 2 size 5.46TiB used 1.51GiB path /dev/sde
devid 3 size 5.46TiB used 0.00B path /dev/sdg
devid 4 size 5.46TiB used 0.00B path /dev/sdi

可以看到SDC和SDE已经使用了1.51GiB的空间

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
31
32
root@openmediavault:~# btrfs fi usage /srv/dev-disk-by-uuid-5d347e39-e8b0-4ddc-b159-a7cb00649068
Overall:
Device size: 21.83TiB
Device allocated: 3.02GiB
Device unallocated: 21.83TiB
Device missing: 0.00B
Device slack: 0.00B
Used: 144.00KiB
Free (estimated): 21.83TiB (min: 21.83TiB)
Free (statfs, df): 21.83TiB
Data ratio: 1.00
Metadata ratio: 1.00
Global reserve: 3.50MiB (used: 0.00B)
Multiple profiles: no

Data,RAID0: Size:2.00GiB, Used:0.00B (0.00%)
/dev/sdc 1.00GiB
/dev/sde 1.00GiB

Metadata,RAID0: Size:1.00GiB, Used:128.00KiB (0.01%)
/dev/sdc 512.00MiB
/dev/sde 512.00MiB

System,RAID0: Size:16.00MiB, Used:16.00KiB (0.10%)
/dev/sdc 8.00MiB
/dev/sde 8.00MiB

Unallocated:
/dev/sdc 5.46TiB
/dev/sde 5.46TiB
/dev/sdg 5.46TiB
/dev/sdi 5.46TiB

我们可以看到,目前metadata和system处于raid0状态,为了能够掉盘后仍然能看到分区和内部文件信息(虽然文件实际已经损坏),我们需要将metadata改为DUP或RAID1模式

  • DUP:在一个设备上存储多份
  • RAID-1:在多个设备上存储多份

我现在这种多设备的情况,metadata应该改为使用RAID1

因此使用如下命令配置更新btrfs

1
btrfs balance start -f -sconvert=RAID1c4 -mconvert=RAID1c4 -dconvert=RAID0 /srv/dev-disk-by-uuid-5d347e39-e8b0-4ddc-b159-a7cb00649068

上面的意思就是,将metadata部分内容以RAID1c4模式存储(即一份数据复制4份分别存储在4个设备上),然后data部分以raid0模式运行,运行完成后再次检查

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
31
32
33
34
35
36
37
38
root@openmediavault:/srv/dev-disk-by-uuid-5d347e39-e8b0-4ddc-b159-a7cb00649068# btrfs fi usage .
Overall:
Device size: 21.83TiB
Device allocated: 12.12GiB
Device unallocated: 21.82TiB
Device missing: 0.00B
Device slack: 0.00B
Used: 5.02GiB
Free (estimated): 21.82TiB (min: 5.46TiB)
Free (statfs, df): 21.82TiB
Data ratio: 1.00
Metadata ratio: 4.00
Global reserve: 5.72MiB (used: 0.00B)
Multiple profiles: no

Data,RAID0: Size:8.00GiB, Used:5.00GiB (62.50%)
/dev/sdc 2.00GiB
/dev/sde 2.00GiB
/dev/sdg 2.00GiB
/dev/sdi 2.00GiB

Metadata,RAID1C4: Size:1.00GiB, Used:6.17MiB (0.60%)
/dev/sdc 1.00GiB
/dev/sde 1.00GiB
/dev/sdg 1.00GiB
/dev/sdi 1.00GiB

System,RAID1C4: Size:32.00MiB, Used:16.00KiB (0.05%)
/dev/sdc 32.00MiB
/dev/sde 32.00MiB
/dev/sdg 32.00MiB
/dev/sdi 32.00MiB

Unallocated:
/dev/sdc 5.45TiB
/dev/sde 5.45TiB
/dev/sdg 5.45TiB
/dev/sdi 5.45TiB

用FIO跑个分

1
2
3
4
5
6
7
8
9
10
11
12
13
fio Disk Speed Tests (Mixed R/W 50/50) (Partition 192.168.4.23:/MEDIA_GROUP):
---------------------------------
Block Size | 4k (IOPS) | 64k (IOPS)
------ | --- ---- | ---- ----
Read | 1.05 MB/s (263) | 11.74 MB/s (183)
Write | 1.08 MB/s (271) | 12.27 MB/s (191)
Total | 2.14 MB/s (534) | 24.02 MB/s (374)
| |
Block Size | 512k (IOPS) | 1m (IOPS)
------ | --- ---- | ---- ----
Read | 78.24 MB/s (152) | 136.48 MB/s (133)
Write | 82.39 MB/s (160) | 145.57 MB/s (142)
Total | 160.63 MB/s (312) | 282.06 MB/s (275)

这个性能看起来一般般