注意
本文档适用于 Ceph 的开发版本。
纠删码
默认情况下,Ceph 池 以“replicated”(复制)类型创建。在复制类型池中,每个对象都被复制到多个磁盘。这种多重复制是称为“复制”的数据保护方法。
相比之下,纠删码池使用与复制不同的数据保护方法。在纠删码中,数据被分解为两种片段:数据块和奇偶校验块。如果驱动器发生故障或损坏,奇偶校验块用于重建数据。从规模上看,纠删码相对于复制节省了空间。
在本文档中,数据块被称为“data chunks”(数据块),奇偶校验块被称为“coding chunks”(编码块)。
纠删码也称为“前向纠错码”。第一个前向纠错码于1950年由贝尔实验室的Richard Hamming开发。
创建一个示例纠删码池
最简单的纠删码池类似于 RAID5,并且至少需要三台主机
ceph osd pool create ecpool erasure
pool 'ecpool' created
echo ABCDEFGHI | rados --pool ecpool put NYAN -
rados --pool ecpool get NYAN -
ABCDEFGHI
纠删码配置文件
默认的纠删码配置文件可以承受两个OSD重叠丢失而不会丢失数据。此纠删码配置文件等同于大小为三的复制池,但存储要求不同:它只需2TB即可存储1TB,而不是需要3TB来存储1TB。默认配置文件可以使用此命令显示
ceph osd erasure-code-profile get default
k=2
m=2
plugin=isa
crush-failure-domain=host
technique=reed_sol_van
注意
刚刚显示的配置文件是针对 默认 纠删码池的,而不是 最简单 纠删码池的。这两个池不一样
默认纠删码池有两个数据块(K)和两个编码块(M)。默认纠删码池的配置文件是“k=2 m=2”。
最简单的纠删码池有两个数据块(K)和一个编码块(M)。最简单纠删码池的配置文件是“k=2 m=1”。
选择正确的配置文件非常重要,因为池创建后无法修改配置文件。如果您发现需要一个配置文件与已创建的池不同的纠删码池,则必须创建一个具有不同(并且可能经过更仔细考虑的)配置文件的新池。创建新池后,必须将来自配置错误的池中的所有对象移动到新创建的池中。池创建后无法更改其配置文件。
但是,您可以在不创建新池的情况下更改 crush-failure-domain,通过使用 ceph osd pool set <pool-name> crush_rule <rule-name> 更改池的 CRUSH 规则,如 设备类 中所示(您应该确保新的 CRUSH 规则除了故障域之外与旧规则在所有方面都相同!)。一旦您这样做,ceph osd pool ls detail 仍将显示您用于初始创建的配置文件(它指的是旧的 crush-failure-domain),但生效的 CRUSH 规则将是新的规则,因为配置文件中的 crush-failure-domain 仅在池的初始创建期间使用。
配置文件中最重要的参数是 K、M 和 crush-failure-domain,因为它们定义了存储开销和数据持久性。例如,如果所需的架构必须承受两个机架的丢失,且存储开销为67%,则可以定义以下配置文件
ceph osd erasure-code-profile set myprofile \
k=3 \
m=2 \
crush-failure-domain=rack
ceph osd pool create ecpool erasure myprofile
echo ABCDEFGHI | rados --pool ecpool put NYAN -
rados --pool ecpool get NYAN -
ABCDEFGHI
对象 NYAN 将被分成三份 (K=3),并创建两个额外的 chunks (M=2)。M 的值定义了集群中可以同时丢失多少个 OSD 而不会丢失任何数据。crush-failure-domain=rack 将创建一个 CRUSH 规则,确保没有两个 chunks 存储在同一个机架中。
可以在 纠删码配置文件 文档中找到更多信息。
带覆盖写入的纠删码
默认情况下,纠删码池仅适用于执行完整 RADOS 对象写入的操作,例如 RGW。
自 Luminous 版本以来,可以通过每个池的设置启用纠删码池的局部写入。这使得 RBD、CephFS 和 librados 能够将数据存储在纠删码池中
ceph osd pool set ec_pool allow_ec_overwrites true
这只能在位于 BlueStore OSD 上的池上启用,因为 BlueStore 的校验和在深度擦洗期间用于检测位腐烂和其他损坏。将 Filestore 与 EC 覆盖写入一起使用不仅不安全,而且与 BlueStore 相比性能也较低。此外,Filestore 已弃用,集群中的任何 Filestore OSD 都应迁移到 BlueStore。
启用 EC 覆盖写入没有缺点,因此例行启用它是最佳实践。
纠删码池不支持 omap,因此要将它们与 RBD 和 CephFS 一起使用,您必须指示它们及其客户端将数据存储在 EC 池中,而将元数据存储在复制池中。对于 RBD,这意味着在创建映像时使用纠删码池作为 --data-pool
rbd create --size 1G --data-pool ec_pool replicated_pool/image_name
对于 CephFS,可以在文件系统创建期间或通过 文件布局 将纠删码池设置为默认数据池。
纠删码优化
自 Tentacle 版本以来,可以通过每个池的设置启用纠删码池的优化。这可以提高较小 I/O 的性能并消除填充,从而显着减少空间放大和浪费的容量
ceph osd pool set ec_pool allow_ec_optimizations true
这些优化将使纠删码池更适合与 RBD 或 CephFS 一起使用。对于具有大对象且按顺序读写的 RGW 工作负载,这些优化带来的好处很小;但对于具有大量非常小的对象或小随机访问读取的 RGW 工作负载,将看到性能和容量优势。
此标志可以为现有池启用,并且可以使用中心配置选项 osd_pool_default_flag_ec_optimizations 配置为新池的默认值。一旦为池启用了该标志,就无法禁用它,因为它会改变新数据的存储方式。
除非所有 Monitor 和 OSD 都已升级到 Tentacle 或更高版本,否则无法设置该标志。无需升级网关和客户端即可启用和使用优化。
目前仅在使用 reed_sol_van 技术时支持 Jerasure 和 ISA-L 插件的优化(这些是旧的和当前的默认值,并且是最广泛使用的插件和技术)。尝试为使用不受支持的插件和技术组合的池设置标志将因错误消息而被阻止。
默认条带单元为 4K,适用于标准 EC 池。对于大多数 I/O 工作负载,建议在使用优化时将条带单元增加到至少 16K。性能测试表明 16K 是通用 I/O 工作负载的最佳选择。增加此值将显着提高小读取性能,但会略微降低小顺序写入的性能。对于以读取为主的 I/O 工作负载,高达 256KB 的较大值将进一步提高读取性能,但会进一步降低小顺序写入的性能。大于 256KB 的值不太可能带来任何性能优势。条带单元是池创建时选项,可以在纠删码配置文件中设置,也可以通过设置中心配置选项 osd_pool_erasure_code_stripe_unit 来设置。条带单元在池创建后无法更改,因此如果为现有池启用优化,您将无法获得优化的全部好处。
未启用优化时,纠删码配置文件中 k+m 的选择会影响性能。 k 和 m 的值越高,性能越低。启用优化后,随着 k 的增加,性能只会非常轻微地降低,因此使用更高的 k 值变得更可行。增加 m 仍然会影响写入性能,尤其是对于小写入,因此对于块和文件工作负载,建议 m 值不大于3。
纠删码池开销
纠删码池的开销因子(空间放大)为 (k+m) / k。对于 4,2 配置文件,开销为 1.5,这意味着使用 1.5 GiB 的底层存储来存储 1 GiB 的用户数据。与 size-3 的默认复制相比,开销因子为 3.0。不要将纠删码误认为是免费的午餐:存在显著的性能权衡,尤其是在使用 HDD 以及执行集群恢复或回填时。
下表显示了 k 和 m 的不同值的开销因子。当 k 增加到大于 4 时,增量容量开销收益迅速递减,但性能影响按比例增长。除非您完全理解其后果,包括集群拓扑呈现的故障域数量,否则我们建议您不要选择 k > 4 或 m > 2 的配置文件。如果您选择 m=1,在维护期间会遇到数据不可用,并且当组件故障重叠时会丢失数据。因此,强烈不建议将 m=1 的配置文件用于生产数据。
必须保持活动状态并避免在大量重叠组件故障中丢失数据的部署可能倾向于选择 m > 2 的值。请注意,此类配置文件会导致较低的空间效率和降低的性能,尤其是在回填和恢复期间。
如果您确定希望将纠删码用于一个或多个池,但不确定使用哪个配置文件,请选择 k=4 和 m=2。与 size=3 的复制相比,您将获得两倍的可用空间,并且写入和恢复性能影响相对可容忍。
注意
大多数纠删码池部署需要至少 k+m 个 CRUSH 故障域,在大多数情况下意味着 rack`s 或 `hosts。规划 EC 配置文件和集群拓扑以使至少有 k+m+1 个故障域具有操作优势。在大多数情况下,不鼓励使用 k > 8 的值。
注意
对于具有相当比例的小用户文件/对象的 CephFS 和 RGW 部署,可能需要仔细规划,因为纠删码数据池可能导致相当大的额外空间放大。CephFS 和 RGW 都支持具有不同介质、性能和数据保护策略的多个数据池,这可以实现高效且有效的部署。例如,RGW 部署可能会配置适度的 TLC SSD 补充用于复制索引和默认存储桶数据池,以及通过存储类、放置目标或 Lua 脚本将较大和较冷对象定向到的较大补充的纠删码 QLC SSD 或 HDD。
m=1 |
m=2 |
m=3 |
m=4 |
m=5 |
m=6 |
m=7 |
m=8 |
m=9 |
m=10 |
m=11 |
|
|---|---|---|---|---|---|---|---|---|---|---|---|
k=1 |
2.00 |
3.00 |
4.00 |
5.00 |
6.00 |
7.00 |
8.00 |
9.00 |
10.00 |
11.00 |
12.00 |
k=2 |
1.50 |
2.00 |
2.50 |
3.00 |
3.50 |
4.00 |
4.50 |
5.00 |
5.50 |
6.00 |
6.50 |
k=3 |
1.33 |
1.67 |
2.00 |
2.33 |
2.67 |
3.00 |
3.33 |
3.67 |
4.00 |
4.33 |
4.67 |
k=4 |
1.25 |
1.50 |
1.75 |
2.00 |
2.25 |
2.50 |
2.75 |
3.00 |
3.25 |
3.50 |
3.75 |
k=5 |
1.20 |
1.40 |
1.60 |
1.80 |
2.00 |
2.20 |
2.40 |
2.60 |
2.80 |
3.00 |
3.20 |
k=6 |
1.16 |
1.33 |
1.50 |
1.66 |
1.83 |
2.00 |
2.17 |
2.33 |
2.50 |
2.66 |
2.83 |
k=7 |
1.14 |
1.29 |
1.43 |
1.58 |
1.71 |
1.86 |
2.00 |
2.14 |
2.29 |
2.43 |
2.58 |
k=8 |
1.13 |
1.25 |
1.38 |
1.50 |
1.63 |
1.75 |
1.88 |
2.00 |
2.13 |
2.25 |
2.38 |
k=9 |
1.11 |
1.22 |
1.33 |
1.44 |
1.56 |
1.67 |
1.78 |
1.88 |
2.00 |
2.11 |
2.22 |
k=10 |
1.10 |
1.20 |
1.30 |
1.40 |
1.50 |
1.60 |
1.70 |
1.80 |
1.90 |
2.00 |
2.10 |
k=11 |
1.09 |
1.18 |
1.27 |
1.36 |
1.45 |
1.54 |
1.63 |
1.72 |
1.82 |
1.91 |
2.00 |
k=12 |
1.08 |
1.17 |
1.25 |
1.33 |
1.42 |
1.50 |
1.58 |
1.67 |
1.75 |
1.83 |
1.92 |
k=20 |
1.05 |
1.10 |
1.15 |
1.20 |
1.25 |
1.30 |
1.35 |
1.40 |
1.45 |
1.50 |
1.55 |
纠删码池和缓存分级
注意
缓存分级在 Reef 版本中已弃用。我们强烈建议不要部署新的缓存层,并努力将其从现有部署中移除。
纠删码池需要比复制池更多的资源,并且缺少复制池支持的一些功能(例如,omap)。为了克服这些限制,可以在设置纠删码池之前设置 缓存层。
例如,如果池 hot-storage 由快速存储组成,则以下命令将池 hot-storage 作为 ecpool 的一个层,处于 writeback 模式
ceph osd tier add ecpool hot-storage
ceph osd tier cache-mode hot-storage writeback
ceph osd tier set-overlay ecpool hot-storage
结果是,对 ecpool 的每次写入和读取实际上都使用 hot-storage 池,并受益于其灵活性和速度。
更多信息可以在 缓存分级 文档中找到。但请注意,缓存分级已弃用,并可能在未来版本中完全删除。
纠删码池恢复
如果纠删码池丢失任何数据分片,它必须从其他分片中恢复它们。此恢复涉及从剩余分片读取、重建数据并写入新分片。
在 Octopus 及更高版本中,只要至少有 K 个分片可用,纠删码池就可以恢复。(分片少于 K 时,您实际上丢失了数据!)
在 Octopus 之前,纠删码池要求至少有 min_size 个分片可用,即使 min_size 大于 K。这是在设计新池模式时出于谨慎而做出的保守决定。然而,结果是,丢失 OSD 但没有完全丢失数据的池无法恢复并变为活动状态,除非手动干预以临时更改 min_size 设置。
我们建议将 min_size 设置为 K+1 或更大,以防止写入丢失和数据丢失。
词汇表
- chunk
当调用编码函数时,它返回大小彼此相同的块。有两种块:(1) data chunks(数据块),可以串联以重建原始对象,以及(2) coding chunks(编码块),可用于重建丢失的块。
- K
对象被划分成的数据块数量。例如,如果 K = 2,则一个 10KB 的对象被分成两个各 5KB 的对象。
- M
通过编码函数计算出的编码块数量。 M 等于集群中可以丢失而不会导致数据丢失的 OSD 数量。例如,如果有两个编码块,则可以丢失两个 OSD 而不丢失数据。