Seaweedfs Erasure-coding 深度解析 纠删码 里德所罗门码 分布式对象存储 冗余纠错高可用测试

Seaweedfs Erasure-coding

介绍

https://github.com/seaweedfs/seaweedfs/wiki/Erasure-coding-for-warm-storage

SeaweedFS 实现了RS(10,4),每 10 个硬盘中允许丢失 4 块仍可正常访问

复制数据5次以实现相同的稳健性相比,它节省了3.6倍的磁盘空间。

服务启动

启动 master 服务器,4个卷服务器,一个 filer 文件管理服务器

mkdir disk1 disk2 disk3 disk4
./weed master -mdir=$PWD/master -volumeSizeLimitMB=64
./weed volume -port=8081 -dir=$PWD/disk1 -max=100 -mserver="localhost:9333" 
./weed volume -port=8082 -dir=$PWD/disk2 -max=100 -mserver="localhost:9333" 
./weed volume -port=8083 -dir=$PWD/disk3 -max=100 -mserver="localhost:9333" 
./weed volume -port=8084 -dir=$PWD/disk4 -max=100 -mserver="localhost:9333" 
./weed filer -master=localhost:9333

浏览器访问 master 服务器: http://192.168.1.24:9333

可以看到一些基本信息:

  • Volume Size Limit 每个卷大小 64MB
  • free 剩余卷数量 400
  • Max 最大卷数量 400
  • 也就是目前有 64*400 = 25G 对象存储大小
    Alt text

浏览器访问filer服务器 http://192.168.1.24:8888

拖动文件上传一个大小为 395M 的视频(2023-09-07-20-32-34.mp4)

Alt text

回到 master 网页,看到 volume 有如下变化:

Alt text

  • Free 剩余 393 个卷,也就是 master 为 filer 文件服务器一次性分配了 7个卷,总计 7*64 = 448M 大小
  • master 每次默认分配 7 个卷,如果用完会再次分配 7个
  • 7 个卷被分摊到端口号为 8081、8082、8084 的卷服务器中,如何分配是由master自主管理的
    • 8081 有3个卷,卷id为 2 4 7
    • 8082 有3个卷,对应卷id为 1 3 5
    • 8083 没有被分配卷
    • 8084 有1个卷,卷id为 6
    • 每个卷大小 64M
  • 如果此时这3台卷服务器任意一台掉线,或者 disk1、disk2、disk4 任意一个硬盘故障,数据将无法访问

因此需要在 Seaweedfs 中配置纠删码,提高可用性。

在配置纠删码之前,我们需要了解什么是数据块,因为纠删码是根据数据块进行编码解码的。

数据块(chunks)

master 分配 7 个卷的卷 id 为 1~7,每个卷 64M 大小,总计 448M。

刚刚上传的文件大小有 395M,可以推断它已经把 6 个卷都占满了,只剩最后一个卷没占满,我们可以用指令查看 filer 文件服务器对于该文件的分配情况:

# 这个指令会导出 filer 目录下所有文件信息,把结果下载到当前目录 fs.json 文件中
curl -H "Accept: application/json" http://192.168.1.24:8888/?pretty=y  -o fs.json

这是 fs.json 文件的内容:

  "Path": "",
  "Entries": [
    {
      "FullPath": "/2023-09-07-20-32-34.mp4",
      "Mtime": "2023-10-26T00:26:30+08:00",
       ...
      "chunks": [
        {
          "file_id": "5,06ed294c0f",
          "size": 4194304,
          "modified_ts_ns": 1698251187647289116,
          "e_tag": "VVvWUbQ+4E6gSL6yWq/Jjw==",
          "fid": {
            "volume_id": 5,
            "file_key": 6,
            "cookie": 3978906639
          }
        },
    ...
        {
          "file_id": "4,5eac18c4e1",
          "offset": 394264576,
          "size": 729504,
          "modified_ts_ns": 1698251190710407585,
          "e_tag": "uVx8HBfAD4i/FwZUvQnzOw==",
          "fid": {
            "volume_id": 4,
            "file_key": 94,
            "cookie": 2887304417
          }
        }
    ...

其中, chunks 代表的就是一个数据块,每个数据块大小为4M "size": 4194304 ,数据块由 filer 自动拆分,可以用指令 ./weed filer -h 查看 filer 服务默认拆分的块大小:

-maxMB int
    split files larger than the limit (default 4)

由于 fs.json 内容太长,我们可以用一个 python 脚本统计用了多少个数据块。

import json
f = open('./fs.json')
fs = json.load(f)

chunks = fs['Entries'][0]['chunks']
print("chkuns num:", len(chunks))
total_size = 0
for chkun in chunks:
    total_size += chkun['size']
print("total size:", total_size)

# output:
chkuns num: 95
total size: 394994080

可见它使用了 95 个数据块,每个 4M ,总计约等于(最后一个块没写满) 95*4*1024*1024 = 394994080(395M)

将大文件拆分成数据块有许多好处:

  • 便于纠删码编码和解码,校验数据
  • 减少计算机一次性加载的数据量,降低内存和计算需求
  • 分组有利于检索,提高效率
  • 提高并发性,意味着可以同时处理大量数据

纠删码(Erasure-coding)

纠删码(erasure coding,EC)是一种数据保护方法,它将数据分割成片段,把冗余数据块扩展、编码,并将其存储在不同的位置,比如磁盘、存储节点或者其它地理位置。

Seaweedfs纠删码架构

官方介绍:

SeaweedFS implemented 10.4 Reed-Solomon Erasure Coding (EC). The large volumes are split into chunks of 1GB, and every 10 data chunks are also encoded into 4 parity chunks. So a 30 GB data volume will be encoded into 14 EC shards, each shard is of size 3 GB and has 3 EC blocks.

For smaller volumes less than 10GB, and for edge cases, the volume is split into smaller 1MB chunks.

EC 分块策略

seaweedfs 除了 filer 会把文件分块,EC 模块也会把卷分割成许多不同的数据块(chunks):

  • 如果卷超过 10G,EC 会把卷分割成一个个 1GB 的数据块
  • 如果卷小于 10G ,则会分割成 1M 的数据块。
  • 与 filer 不同的是, filer 是基于单个文件分割数据块,而 EC 是基于卷分割数据块

RS(10,4) 纠删码策略

  • 假设一个卷大小是30G, EC 会把卷拆分30个成 1G 的数据块
  • 每 10 个1G数据块为一组,做一次 Erasure Coding ,生成 4个校验块,得到 14个块为一组 RS(10,4)纠删码数据
    • 在这一组 RS(10,4) 数据中,丢失任何4个数据块,都能完整恢复数据
    • 无论丢失的是数据块还是校验块
  • 30G 数据块就被编码成3组 RS(10,4) ,总计 42 个数据块
  • 所以一个卷 30G 会被编码成 14 个EC分片(EC shards),每个 EC 分片含有 3G 数据块,或者含有3个EC校验块,总计 42G

https://note.youdao.com/s/BZbp5Iy9

以上作者的假设是每个卷大小为 30G,而我为了方便测试,卷大小设置为 64M,下面将启用 EC 看看数据会发生什么变化

启用 Erasure-coding

启用 EC 的方式是运行 ./weed scaffold -config=master >> master.toml ,在当前路径生成一个 master.toml 文件,在文件中:

[master.maintenance]
# periodically run these scripts are the same as running them from 'weed shell'
scripts = """
  lock
  ec.encode -fullPercent=50 -quietFor=1h
  ec.rebuild -force
  ec.balance -force
  volume.deleteEmpty -quietFor=24h -force
  volume.balance -force
  volume.fix.replication
  s3.clean.uploads -timeAgo=24h
  unlock
"""
sleep_minutes = 17          # sleep minutes between each script execution

scripts 就是它的启动脚本,由于它是按时间间隔定时执行的,为了方便触发,我们进入 shell 后台,手动触发:

# 进入管理后台
./weed shell
# 查看帮助
help
lock
# 启用 EC ,将使用量大于 50% 的 volume ,最近2s内没有更新的冷数据使能 EC,  -quietFor 可选择 1h0m0s
ec.encode -fullPercent=50 -quietFor=2s
ec.rebuild -force
# 均匀分配 EC 碎片
ec.balance -force
volume.deleteEmpty -quietFor=24h -force
volume.balance -force
volume.fix.replication
s3.clean.uploads -timeAgo=24h
unlock

Alt text

  • Free 剩余数据卷由原来的 393 变成了 390,多了2个卷
  • volume id 原来有 1~7个卷,现在全部没有了
  • EC纠删码分片(ErasureCodingShards) 由原来的 0 变成了总计 98 个:
    • 8081 分配了 23 个 EC 纠删码分片
    • 8082 分配了 26 个EC 纠删码分片
    • 8083 分配了 26 个EC 纠删码分片
    • 8084 分配了 23 个EC 纠删码分片
  • RS(10,4) 表明我们丢失任意 4/10 个EC 纠删码分片,数据仍然可以正常访问。
  • 从目前的服务中,允许 4/10 * 98 = 32 个 EC 纠删码分片丢失,也就是可以容忍一个 disk 损坏,或者说容忍一个 volume server 下线。

随意下线一个 volume 测试:

Alt text
数据依然可以正常访问

Alt text

但是下线两个 volume 就无法访问了。

边缘情况

从上面的例子中,我们可以发现 fullPercent 是定义容量大于 50% 的卷才会被编码。

ec.encode -fullPercent=50 -quietFor=2m

假设我的卷大小是 64M ,文件大小是 395M,filer 分配的 7 个卷中,虽然是平均分的,但必然有些卷分配多一点,有些卷分配少一点

在 EC 编码之前,我每一个卷的分布情况如下:

  • 8081:
    • volume id 2 68M
    • volume id 4 56M
    • volume id 7 44M
  • 8082:
    • volume id 1 48M
    • volume id 3 40M
    • volume id 5 72M
  • 8083
    • null
  • 8084
    • volume id 6 48M

可以看到,文件被拆分到每一个卷的占比不同,假如 ec.encode -fullPercent=50 设定的百分比不是50,而是 95 或 80 ,那 EC encode 并非能对所有卷进行编码。

万一卷该卷恰好掉线,数据就无法访问。

如果想让所有的文件实现容错恢复,可使用 ec.encode -collection t -quietFor 1s -fullPercent=0.001 触发,对所有 1s 内无更新的卷进行编码。

不过,这不是最优策略:

  • 每次编码解码会带来占用CPU计算
  • 占用磁盘 IO 操作过多
  • 用户访问大量文件会很慢

冷热分离

为了避免对所有数据都进行编码校验,作者存储策略参考了 《Facebook ’s Warm BLOB Storage System》 的一些想法:

热数据是指访问频率较高、经常被更新的数据,所以使用备份可以提高数据的访问速度。

而冷数据的访问频率较低,使用 erasure coding 可以节省存储空间,同时仍然保证数据的可靠性。

对于冷数据使用 ec.encode ,默认 fullPercent 是 95,-quietFor 是 1h0m0s ,也就是卷容量超过 95% 且 1小时内没有更新的卷,进行 EC 编码。

而对于其他的卷,使用数据备份

同时启用编码和数据备份后,如果该卷数据“变冷”,编码操作仅会对源副本生效,编码成功后,其他副本会自动删除。

If the volume is replicated, only one copy will be erasure encoded. All the original copies will be purged after a successful erasure encoding.

热数据备份

关闭所有服务器,并删除测试数据,启用备份策略

rm -rf disk1/* disk2/* disk3/* disk4/* master filerldb2
# 开启 master 服务器,-defaultReplication 启用备份
./weed master -mdir=$PWD/master -volumeSizeLimitMB=64 -defaultReplication=001
# 设置 volume 服务器数据中心为 dc1 ,8081、8082机架为 rack1,8083、8084 为 rack2
./weed volume -port=8081 -dir=$PWD/disk1 -max=100 -mserver="localhost:9333" -dataCenter=dc1 -rack=rack1
./weed volume -port=8082 -dir=$PWD/disk2 -max=100 -mserver="localhost:9333" -dataCenter=dc1 -rack=rack1
./weed volume -port=8083 -dir=$PWD/disk3 -max=100 -mserver="localhost:9333" -dataCenter=dc1 -rack=rack2
./weed volume -port=8084 -dir=$PWD/disk4 -max=100 -mserver="localhost:9333" -dataCenter=dc1 -rack=rack2
./weed filer -master=localhost:9333

defaultReplication 的配置说明参考作者文档Replication

我使用的是 001 备份策略:备份一次在同一机架上。

在实际使用过程中,一个机架通常意味着很多台实体服务器,每台服务器都可以配置多块硬盘。由于我只在一台机器上测试,所以用不同端口区分。

Alt text

  • 这张图代表我有一个 dc1 数据中心,有两个机架(rack1和rack2),每个机架上有两台 volume 服务器
# 查看每个磁盘的初始大小
du -b disk*
4132    disk1
4132    disk2
4132    disk3
4132    disk4

随意上传一个 395M 的视频

再次查看磁盘变化,可以看到存储容量是大约是 790M,刚好是文件的两倍

du -b disk*
130759792       disk1   # 8081 rack1
130759792       disk2   # 8082 rack1
264052148       disk3   # 8083 rack2
264250668       disk4   # 8084 rack2

Alt text
390M 文件被 master 安排在 rack1 上存储 130M ,在 rack2 上存储 130M;同时备份策略要求“在同一机架上复制一次”,所以 disk2 和 disk4 获得了相同的副本。

这种情况下,任意掉线一个节点,由于副本的存在,依然可以正常读写。

冷数据封存

我们假定刚刚的数据为冷数据,将它进行 EC 编码

./weed shell
lock
# 启用 EC ,将使用量大于 95% 的 volume ,最近2分钟内没有更新的冷数据编码
ec.encode -fullPercent=95 -quietFor=2s
ec.rebuild -force
ec.balance -force
volume.deleteEmpty -quietFor=2s -force
volume.balance -force
volume.fix.replication
s3.clean.uploads -timeAgo=24h
unlock

编码后架构解析

💡 编码前:
Alt text
Alt text
Alt text
虽然在 master 中设置了卷大小为 64M,但是每个存满的卷,并非严格按照 64M 保存,可能会向上浮动 20M


💡 编码后:
Alt text
Alt text
Alt text
disk1 EC 分片
Alt text

磁盘数据总共为 641M 相对于 编码前 790M 少了 150M

du -b disk*
160444532       disk1
160444532       disk2
144709880       disk3
176167160       disk4

💡 解析

架构原理参考前面章节:Seaweedfs纠删码架构

  • 卷 id 1、2、4、6 因为存储空间大于 64M * 95 %,所以每个卷被拆分成 10 个1M的原始数据块为一组
  • 对这 10 个数据块EC编码成 4 个校验块,每个卷共计 14个块,4个卷共计56个块(也叫做 56个纠删码分片 ErasureCodingShards)
  • 将 56 个纠删码分片均匀地分布式存储在卷服务器中,同时清除原始卷及备份副本。
  • 举例:
    • 编码前卷1 是76M,向上取整 80M
    • 拆分成 10 个1M的原始数据块
    • 对 10 个数据块进行 RS(10,4) 编码,得到 4 个校验块,总计 14 个块,统称为纠删码分片(ErasureCodingShards),每个分片 8M
    • 卷6编码前64M,向上取整 70M,进行 RS(10,4) 编码得到 14 个纠删码分片(Shard Size) 每个分片 7M

✨注意,虽然我在 master 中将卷大小设置成了 64M ,但 volume server 并非严格按照 64M 来划分,卷大小会在 64M 上浮动 20M 左右


以卷服务器8081 disk1 为例,它存储了原始卷id为 1、2、4、6的纠删码分片(Shards):
disk1 所存储的纠删码分片
同理,disk2、disk3、disk4中,也存储了不同卷中各自剩余的分片。

硬盘/卷iddisk1disk2disk3disk4分片大小
voulme 1[1 5 9 13][2 6 10][3 7 11][0 4 8 12]8M
voulme 2[3 7 11][0 2 6 10][4 8 12][1 5 9 13]8M
voulme 3
48M
48M
没有被编码
voulme 4[1 3 7 11][2 6 10][5 9 13][0 4 8 12] 7M
voulme 5
48.1M
48.1M
没有被编码
voulme 6[2 6 10][1 5 9 13][3 7 11][0 4 8 12]7M
存储合计(7*8+7*7)
=105+48.1
=154M
(7*8+7*7)
=105+48.1
=154M
(6*8+6*7)
=105+48
=138M
(6*8+6*7)
=105+48
=138M

在shell中查看存储分布,与计算一致:

du -h disk*
154M    disk1
154M    disk2
139M    disk3
169M    disk4

下线硬盘测试

根据里德所罗门纠删码 RS(10,4): N = K + M

  • N 是 EC 纠删码分片 14,K 是原始数据块 10 个,M 是容忍丢失数量 4
  • 即存在纠删码分片大于等于 10,则数据可以恢复
  • 对于我这个 395M 的视频来说,总共用到了 7 个卷,4个卷被 EC 编码,剩余两个卷没有被编码,但各自有2份副本。
    • 总共 56个 EC 纠删码分片,4:14 = x:56,可容忍16个分片丢失
    • 但是备份策略在同一机架只有2个副本,因此同一个机架不允许同时两台卷服务器
单独下线任意一个硬盘

单独下线 8081:
Alt text
访问正常
Alt text

单独下线8082、8083、8084 访问正常

下线两个硬盘

下线 rack1 和一个 rack2
Alt text
无法访问
img

下线两个 rack1,
Alt text
无法访问
Alt text

下线两个 rack2
Alt text
Alt text

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值