注意
本文档适用于 Ceph 的开发版本。
本地可修复纠删码插件
使用 isa 插件时,当一个纠删码对象存储在多个 OSD 上时,从一个 OSD 丢失中恢复需要从另外 k 个 OSD 中读取数据。例如,如果 isa 配置为 k=8 和 m=4,那么从一个 OSD 丢失中恢复需要从八个 OSD 中读取数据。
lrc 纠删码插件创建本地奇偶校验块,以使用更少的幸存 OSD 来实现恢复。例如,如果 lrc 配置为 k=8、m=4 和 l=4,它将为每四个 OSD 创建一个额外的奇偶校验块。当单个 OSD 丢失时,它只需要四个 OSD 而不是八个即可恢复。
纠删码配置文件示例
减少主机之间的恢复带宽
尽管当所有主机连接到同一个交换机时,这可能不是一个有趣的用例,但实际上可以观察到带宽使用减少。
ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
k=4 m=2 l=3 \
crush-failure-domain=host
ceph osd pool create lrcpool erasure LRCprofile
减少机架之间的恢复带宽
在 Firefly 中,只有当主 OSD 与丢失的块位于同一机架时,才能观察到带宽减少。
ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
k=4 m=2 l=3 \
crush-locality=rack \
crush-failure-domain=host
ceph osd pool create lrcpool erasure LRCprofile
创建一个 lrc 配置文件
要创建一个新的 lrc 纠删码配置文件
ceph osd erasure-code-profile set {name} \
plugin=lrc \
k={data-chunks} \
m={coding-chunks} \
l={locality} \
[crush-root={root}] \
[crush-locality={bucket-type}] \
[crush-failure-domain={bucket-type}] \
[crush-device-class={device-class}] \
[directory={directory}] \
[--force]
其中
k={data chunks}
- 描述:
每个对象被分成 data-chunks 份,每份存储在一个不同的 OSD 上。
- 类型:
整数
- 必需:
是。
- 示例:
4
m={coding-chunks}
- 描述:
计算每个对象的 coding chunks 并将它们存储在不同的 OSD 上。编码块的数量也是在不丢失数据的情况下可以停止运行的 OSD 数量。
- 类型:
整数
- 必需:
是。
- 示例:
2
l={locality}
- 描述:
将编码块和数据块分组,每组大小为 locality。例如,对于 k=4 和 m=2,当 locality=3 时,将创建两组三块。每组都可以在不读取其他组中的块的情况下恢复。
- 类型:
整数
- 必需:
是。
- 示例:
3
crush-root={root}
- 描述:
用于 CRUSH 规则第一步的 crush 桶的名称。例如 step take default。
- 类型:
String
- 必需:
否。
- 默认值:
default
crush-locality={bucket-type}
- 描述:
由 l 定义的每组块将存储在其中的 CRUSH bucket 的类型。例如,如果设置为 rack,每组 l 个块将放置在不同的机架中。它用于创建 CRUSH 规则步骤,例如 step choose rack。如果未设置,则不进行此类分组。
- 类型:
String
- 必需:
否。
crush-failure-domain={bucket-type}
- 描述:
确保没有两个块位于具有相同故障域的桶中。例如,如果故障域是 host,则不会有两个块存储在同一主机上。它用于创建 CRUSH 规则步骤,例如 step chooseleaf host。
- 类型:
String
- 必需:
否。
- 默认值:
host
crush-device-class={device-class}
- 描述:
使用 CRUSH 映射中的 crush 设备类名称将放置限制为特定类的设备(例如,
ssd或hdd)。- 类型:
String
- 必需:
否。
- 默认值:
directory={directory}
- 描述:
设置从中加载纠删码插件的 directory 名称。
- 类型:
String
- 必需:
否。
- 默认值:
/usr/lib/ceph/erasure-code
--force
- 描述:
覆盖具有相同名称的现有配置文件。
- 类型:
String
- 必需:
否。
低级插件配置
k 和 m 的总和必须是 l 参数的倍数。然而,低级配置参数不强制执行此限制,并且使用它们可能对特定目的有益。例如,可以定义两组,一组有 4 个块,另一组有 3 个块。还可以递归地定义本地性集,例如数据中心内的数据中心和机架。k/m/l 是通过生成低级配置来实现的。
lrc 纠删码插件递归地应用纠删码技术,以便从某些块丢失中恢复只需要可用块的一个子集,在大多数情况下。
例如,当三个编码步骤描述为
chunk nr 01234567
step 1 _cDD_cDD
step 2 cDDD____
step 3 ____cDDD
其中 c 是从数据块 D 计算出的编码块,块 7 的丢失可以通过最后四个块恢复。块 2 的丢失可以通过前四个块恢复。
使用低级配置的纠删码配置文件示例
最小测试
它与使用 K=2 M=1 纠删码配置文件完全等效。DD 表示 K=2,c 表示 M=1,并且默认使用 isa 插件。
ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
mapping=DD_ \
layers='[ [ "DDc", "" ] ]'
ceph osd pool create lrcpool erasure LRCprofile
减少主机之间的恢复带宽
尽管当所有主机连接到同一个交换机时,这可能不是一个有趣的用例,但实际上可以观察到带宽使用减少。它等效于 k=4、m=2 和 l=3,尽管块的布局不同。警告:提示是可选的
$ ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
mapping=__DD__DD \
layers='[
[ "_cDD_cDD", "" ],
[ "cDDD____", "" ],
[ "____cDDD", "" ],
]'
$ ceph osd pool create lrcpool erasure LRCprofile
减少机架之间的恢复带宽
在 Firefly 中,只有当主 OSD 与丢失的块位于同一机架时,才能观察到带宽减少。警告:提示是可选的
$ ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
mapping=__DD__DD \
layers='[
[ "_cDD_cDD", "" ],
[ "cDDD____", "" ],
[ "____cDDD", "" ],
]' \
crush-steps='[
[ "choose", "rack", 2 ],
[ "chooseleaf", "host", 4 ],
]'
$ ceph osd pool create lrcpool erasure LRCprofile
使用不同纠删码后端进行测试
LRC 现在使用 ISA 作为默认的 EC 后端。可以使用低级配置按层指定 EC 后端/算法。layers='[ [ "DDc", "" ] ]' 中的第二个参数实际上是用于此级别的纠删码配置文件。下面的示例指定在 lrcpool 中使用 Jerasure 后端和 cauchy 技术。
ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
mapping=DD_ \
layers='[ [ "DDc", "plugin=jerasure technique=cauchy" ] ]'
ceph osd pool create lrcpool erasure LRCprofile
您还可以为每一层使用不同的纠删码配置文件。警告:提示是可选的
$ ceph osd erasure-code-profile set LRCprofile \
plugin=lrc \
mapping=__DD__DD \
layers='[
[ "_cDD_cDD", "plugin=isa technique=cauchy" ],
[ "cDDD____", "plugin=isa" ],
[ "____cDDD", "plugin=jerasure" ],
]'
$ ceph osd pool create lrcpool erasure LRCprofile
纠删码编码和解码算法
layers 描述中找到的步骤
chunk nr 01234567
step 1 _cDD_cDD
step 2 cDDD____
step 3 ____cDDD
按顺序应用。例如,如果编码一个 4K 对象,它将首先经过 step 1 并被分成四个 1K 块(四个大写字母 D)。它们依次存储在块 2、3、6 和 7 中。从这些块中计算出两个编码块(两个小写字母 c)。编码块分别存储在块 1 和 5 中。
step 2 以类似的方式重用 step 1 创建的内容,并在位置 0 存储单个编码块 c。最后四个块(为便于阅读用下划线(_)标记)被忽略。
step 3 在位置 4 存储单个编码块 c。使用 step 1 创建的三个块来计算此编码块,即来自 step 1 的编码块在 step 3 中成为数据块。
如果块 2 丢失
chunk nr 01234567
step 1 _c D_cDD
step 2 cD D____
step 3 __ _cDDD
解码将尝试通过按相反顺序遍历步骤来恢复它:step 3 然后 step 2,最后 step 1。
step 3 对块 2 一无所知(即它是一个下划线)并被跳过。
来自 step 2 的编码块(存储在块 0 中)允许它恢复块 2 的内容。没有更多要恢复的块,进程停止,不考虑 step 1。
恢复块 2 需要读取块 0, 1, 3 并写回块 2。
如果块 2, 3, 6 丢失
chunk nr 01234567
step 1 _c _c D
step 2 cD __ _
step 3 __ cD D
step 3 可以恢复块 6 的内容
chunk nr 01234567
step 1 _c _cDD
step 2 cD ____
step 3 __ cDDD
step 2 恢复失败并被跳过,因为它丢失了两个块(2, 3),而它只能从一个丢失的块中恢复。
来自 step 1 的编码块(存储在块 1, 5 中)允许它恢复块 2, 3 的内容
chunk nr 01234567
step 1 _cDD_cDD
step 2 cDDD____
step 3 ____cDDD
控制 CRUSH 放置
默认 CRUSH 规则提供位于不同主机上的 OSD。例如
chunk nr 01234567
step 1 _cDD_cDD
step 2 cDDD____
step 3 ____cDDD
精确需要 8 个 OSD,每个块一个。如果主机位于两个相邻的机架中,前四个块可以放置在第一个机架中,后四个块可以放置在第二个机架中。这样,从单个 OSD 丢失中恢复不需要使用两个机架之间的带宽。
例如
crush-steps='[ [ "choose", "rack", 2 ], [ "chooseleaf", "host", 4 ] ]'
将创建一个规则,选择两个类型为 rack 的 crush bucket,并为它们中的每一个选择四个 OSD,每个 OSD位于不同类型为 host 的 bucket 中。
CRUSH 规则也可以手动制作以进行更精细的控制。