注意
本文档适用于 Ceph 的开发版本。
CLAY 代码插件
CLAY(coupled-layer 的缩写)代码是一种纠删码,旨在在修复发生故障的节点/OSD/机架时,在网络带宽和磁盘 IO 方面实现显著节省。假设
d = 修复期间联系的 OSD 数量
如果 jerasure 配置为 k=8 和 m=4,丢失一个 OSD 需要从 d=8 个其他 OSD 读取才能修复。恢复 1GiB(例如)需要下载 8 X 1GiB = 8GiB 的信息。
然而,对于 clay 插件,d 在以下限制范围内可配置
k+1 <= d <= k+m-1
默认情况下,clay 代码插件选择 d=k+m-1,因为它在网络带宽和磁盘 IO 方面提供了最大的节省。对于配置为 k=8、m=4 和 d=11 的 clay 插件,当单个 OSD 发生故障时,将联系 d=11 个 OSD,并从每个 OSD 下载 250MiB,总共下载 11 X 250MiB = 2.75GiB 的信息量。下面提供了更通用的参数。当对存储信息量达到 TB 级别的机架执行修复时,这些好处是巨大的。
插件
磁盘 IO 总量
jerasure,isa
\(k S\)
clay
\(\frac{d S}{d - k + 1} = \frac{(k + m - 1) S}{m}\)
其中 S 是正在修复的单个 OSD 上存储的数据量。在上表中,我们使用了 d 的最大可能值,因为这将导致实现从 OSD 故障恢复所需的数据下载量最小。
纠删码配置文件示例
一个可用于观察减少带宽使用的配置示例
ceph osd erasure-code-profile set CLAYprofile \
plugin=clay \
k=4 m=2 d=5 \
crush-failure-domain=host
ceph osd pool create claypool erasure CLAYprofile
创建 clay 配置文件
要创建一个新的 clay 代码配置文件
ceph osd erasure-code-profile set {name} \
plugin=clay \
k={data-chunks} \
m={coding-chunks} \
[d={helper-chunks}] \
[scalar_mds={plugin-name}] \
[technique={technique-name}] \
[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
d={helper-chunks}
- 描述:
在恢复单个数据块期间请求发送数据的 OSD 数量。需要选择 d,使得 k+1 <= d <= k+m-1。d 越大,节省越多。
- 类型:
整数
- 必需:
否。
- 默认值:
k+m-1
scalar_mds={jerasure|isa|shec}
- 描述:
scalar_mds 指定了在分层构建中用作构建块的插件。它可以是 jerasure、isa、shec 之一
- 类型:
String
- 必需:
否。
- 默认值:
jerasure
technique={technique}
- 描述:
technique 指定了在指定的“scalar_mds”插件中将选择的技术。支持的技术包括 jerasure 的 'reed_sol_van'、'reed_sol_r6_op'、'cauchy_orig'、'cauchy_good'、'liber8tion',isa 的 'reed_sol_van'、'cauchy',以及 shec 的 'single'、'multiple'。
- 类型:
String
- 必需:
否。
- 默认值:
reed_sol_van (适用于 jerasure, isa), single (适用于 shec)
crush-root={root}
- 描述:
用于 CRUSH 规则第一步的 crush 桶的名称。例如 step take default。
- 类型:
String
- 必需:
否。
- 默认值:
default
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
- 必需:
否。
子块的概念
Clay 代码能够节省磁盘 IO、网络带宽,因为它是一种矢量代码,并且能够以更精细的粒度(称为子块)查看和操作数据块内的数据。Clay 代码中一个数据块内的子块数量由下式给出
子块数量 = \(q^{\frac{k+m}{q}}\),其中 \(q = d - k + 1\)
在修复 OSD 期间,从可用 OSD 请求的帮助信息只是数据块的一部分。事实上,在修复期间访问的数据块内子块的数量由下式给出
修复子块数量 = \(\frac{sub---chunk \: count}{q}\)
示例
对于 k=4、m=2、d=5 的配置,子块数量为 8,修复子块数量为 4。因此,在修复期间只读取了数据块的一半。
当 k=8、m=4、d=11 时,子块数量为 64,修复子块数量为 16。从可用 OSD 读取数据块的四分之一用于修复发生故障的数据块。
如何根据工作负载选择配置
在一个数据块的所有子块中,只读取了少数几个子块。这些子块不一定在数据块内连续存储。为了获得最佳磁盘 IO 性能,读取连续数据是有帮助的。因此,建议您选择条带大小,使子块大小足够大。
对于给定的条带大小(根据工作负载固定),选择 k、m、d,使得
子块大小 = \(\frac{stripe-size}{k sub-chunk count}\) = 4KB, 8KB, 12KB …
对于条带大小较大的大型工作负载,选择 k、m、d 很简单。例如,考虑条带大小为 64MB,选择 k=16、m=4 和 d=19 将导致子块数量为 1024,子块大小为 4KB。
对于小型工作负载,k=4、m=2 是一个很好的配置,可以提供网络和磁盘 IO 方面的优势。
与 LRC 的比较
本地可恢复代码(LRC)也旨在在单个 OSD 恢复期间节省网络带宽和磁盘 IO。然而,LRC 的重点是使修复期间联系的 OSD 数量(d)最小化,但这以存储开销为代价。clay 代码的存储开销为 m/k。对于 lrc,除了 m 个奇偶校验块之外,它还存储 (k+m)/d 个奇偶校验块,导致存储开销为 (m+(k+m)/d)/k。clay 和 lrc 都可以从任意 m 个 OSD 故障中恢复。
参数
磁盘 IO, 存储开销 (LRC)
磁盘 IO, 存储开销 (CLAY)
(k=10, m=4)
7 * S, 0.6 (d=7)
3.25 * S, 0.4 (d=13)
(k=16, m=4)
4 * S, 0.5625 (d=4)
4.75 * S, 0.25 (d=19)
其中 S 是正在恢复的单个 OSD 上存储的数据量。