Tentacle性能更新的快速纠删码
深入探讨 Tentacle 中快速纠删码改进带来的优势。 本博客详细讨论了我们如何改进纠删码,使其成为替代复制的可行方案,并降低 Ceph 集群的总体拥有成本 (TCO)。
目录
简介 ¶
社区中的 Ceph 用户对 Ceph Tentacle 版本中的快速 EC 功能感到非常兴奋。 本博客讨论了与 Squid 相比,在 Tentacle 中启用快速 EC 的性能优势。
这些优化主要旨在受益于块和文件工作负载;对于具有小对象或随机访问读取的对象存储工作负载,可能存在好处。
在 Tentacle 中启用快速 EC 是基于每个池的,使用
ceph osd pool <mypool> set allow_ec_optimizations on
重要的是要注意,一旦启用 allow_ec_optimizations,就无法禁用它。
快速纠删码改进总结如下
- 读取优化 - 部分读取
- 空间效率改进 - 小对象填充
- 写入优化 – 部分写入、奇偶校验增量写入
- 建议用户将
stripe_unit大小增加到 16k,以获得启用了allow_ec_optimizations的池的性能提升。
纠删码基础 ¶
在深入讨论优化之前,让我们简要谈谈纠删码和 RAID 的基础知识。
Ceph 纠删码通过将对象拆分为 K 个数据块和 M 个奇偶校验编码块来工作,然后将这些块存储在不同的对象存储守护程序 (OSD) 上。 如果一个或多个 OSD 发生故障,可以使用剩余的数据和奇偶校验编码块来重建丢失的数据。 这种方法比传统的复制更节省存储空间,因为它不存储数据的完整副本。

工作原理
数据拆分:将对象划分为 K 个数据块。
奇偶校验生成:纠删码算法,例如 Reed-Solomon,基于数据块计算 M 个奇偶校验编码块。 奇偶校验块的数量 M 决定了在不丢失数据的情况下可以容忍多少个 OSD 发生故障。 用户可以使用可用的不同插件配置纠删码算法。 插件的选择不在本博客讨论范围内。
块分布:将 K 个数据块和 M 个奇偶校验块根据 CRUSH 规则分布并存储在单独的 OSD 上。
用户决定块的大小,这称为
stripe_unit,可以在创建erasure-code-profile时指定。 稍后会有一个部分讨论stripe_unit的选择。stripe_unit大小是写入数据块的数据量,然后将对象的下一部分写入下一个 OSD 上的下一个块。 条带是条带内的条目的集合,这些条目也构成了保护数据以防 OSD 丢失的编码奇偶校验。
在社区中,stripe_unit 通常被称为 chunk。 为了本博客的目的,stripe_unit 与块大小同义。
选择纠删码配置文件 ¶
用户主要使用 replica-3 池用于块和文件工作负载。 replica-3 池在不同的 OSD 上存储 3 个数据的副本,因此可以在不丢失数据的情况下承受两个 OSD 发生故障。 最常见的双重故障是驱动器故障加上另一个驱动器上的介质错误。 Replica-3 池具有 300% 的存储开销 - 对于 3GB 的原始容量,您可以存储 1GB 的应用程序数据。
使用纠删码池,您可以创建一个纠删码配置文件,选择 K+M 的值。 纠删码池所需的最小 OSD 数量为 K+M,就像 replica-3 池一样,建议这些 OSD 位于不同的服务器中以实现容错。 M 的选择定义了您拥有的冗余量,M=2 表示您可以承受两个 OSD 发生故障 - 与 replica-3 池相同。 纠删码池的存储开销为 (K+M / K),因此 4+2 池的存储开销为 150%。
本博客重点介绍具有 M=2 的纠删码性能,因为这提供了与 replica-3 池相同的保护级别。
读取优化(部分读取) ¶
在 Squid 中,读取条带内的单个条带,会读取整个条带,从条带数据中提取客户端请求所需的必要数据,然后丢弃其余数据。 对于小读取,纠删码配置文件中 K 值(数据条带)越大,浪费到 OSD 上的 IO 越多。
在 Tentacle 中,部分读取的改进是仅读取最小的数据以满足客户端请求。 这种改进有两个好处,首先,性能读取不受 K 增加的影响,并且您的驱动器介质将通过减少浪费的 IO 来获得更好的利用率,其次,使用更大的 stripe_unit,客户端读取只需要读取条带的一部分,并且来自其他 OSD 的带宽浪费更少。
这意味着在 Tentacle 中,使用快速 EC,您现在可以选择使用更高的 K 值,以便获得更好的容量利用率,而不会出现 Squid 中看到的性能下降。
空间效率改进 - 小对象填充 ¶
在 Squid 中,小对象填充到整个条带,导致空间浪费以及由于不必要地写入多个 OSD 而导致的写入性能下降。 快速 EC 不会将小对象填充到整个条带,而是仅将对象写入其需要的条带,从而提高性能并节省容量。
将 stripe_unit 大小增加到 16k ¶
拥有小的 stripe_unit 会增加客户端 IO 被拆分为多个请求到不同 OSD 的可能性。 对于大型 IO(例如 1MB 读取),将 IO 拆分为更小的请求到可以并行处理的单独 OSD 有性能优势。 对于较小的 IO,拆分 IO 只是增加了驱动器、CPU 和网络的负担,并降低了性能。
增加 stripe_unit 减少了处理小 IO 的开销,同时仍然拆分并获得大型 IO 的性能优势。
在 squid 及更早版本中,有以下两个原因导致 stripe_unit 很小
缺乏部分读取支持基本上是阻止增加
stripe_unit大小的障碍,因为更大的stripe_unit和更大的 K 值意味着 4-16k 的读取会导致 OSD 上的 IO 浪费更大。EC 曾经填充所有对象以使其成为条带大小的倍数。 较大的
stripe_unit意味着更多的填充,这会浪费存储容量。
在性能和容量使用之间仍然存在权衡。 将 stripe_unit 增加到 16K 以上,也许高达 256K 可以进一步提高性能,但对于小文件或对象仍然会浪费存储容量。 选择 16K 作为 stripe_unit 是一个很好的折衷方案 - 它提供了与旧 EC 相似的容量利用率,但性能更好。
Tentacle 中的默认 stripe_unit 仍然是 4K,但我们建议您在创建新的快速 EC 池时指定 16K stripe_unit,以获得更大的性能提升。
对于现有池,无法更改 stripe_unit,仍然可以为这些池启用快速 EC,但性能提升会略小。
写入优化 ¶
部分写入 ¶
在 squid 中,所有子条带写入都通过读取整个条带、将客户端的新数据合并到其中、编码新的奇偶校验并将条带写回,数据与编码奇偶校验来处理。
这意味着 EC 更适合大型块和大型对象工作负载,但对于小对象或小写入工作负载(例如 CephFS 或事务性工作负载)而言,它不是最佳的,因为更大的 K 值和小的写入意味着 IO 操作被放大。
部分写入仅读取未写入的数据条带,编码新的奇偶校验,并仅写回修改后的数据和奇偶校验条带。
这种优化意味着对于小写入和大的 K 值,快速 EC 可以节省读取和写入未更改数据的驱动器操作。
奇偶校验增量写入 ¶
奇偶校验增量写入 (PDW) 建立在快速 EC 中的部分写入改进之上。
块存储控制器使用的常见技术,实现 RAID-5 和 RAID-6 是实现奇偶校验增量写入。 当条带的一部分被覆盖时,可以通过读取旧数据、将旧数据与新数据进行 XOR 以创建增量,然后读取每个编码奇偶校验、应用增量并写入新的奇偶校验来执行更新。 此技术的优点是,它可以涉及更少的 IO,尤其是在具有较大 K 值的 K+M 编码中。 该技术不特定于 M=1 和 M=2,可以与任何数量的编码奇偶校验一起使用。 对于 M=2,此技术涉及每个条带内的客户端请求进行 3 次读取 + 3 次写入,然后通过缓存合并到条带内的奇偶校验更新,以最大程度地减少条带内的奇偶校验更新数量。(对于 M=1,每个写入需要 2 次读取和 2 次写入)。
在某些情况下,具体取决于 K 的值和写入操作的大小,可能更不利于使用 PDW。
快速 EC 中的 PDW 实现会动态调整每个 IO 的写入技术,以实现最佳写入性能。
这是一个说明表格,仅用于说明
| 纠删码 | stripe_unit | 写入大小 | PDW 写入 | PDW 关闭(部分写入) |
|---|---|---|---|---|
| 2+2 | 16k | 4 到 16k | 3 次读取+3 次写入 | 1 次读取+3 次写入 |
| 4+2 | 16k | 4 到 16k | 3 次读取+3 次写入 | 3 次读取+3 次写入 |
| 6+2 | 16k | 4 到 16k | 3 次读取+3 次写入 | 5 次读取+3 次写入 |
| 6+2 | 16k | 32k | 4 次读取+4 次写入 | 4 次读取+4 次写入 |
| 8+2 | 16k | 4 到 16k | 3 次读取+3 次写入 | 7 次读取+3 次写入 |
| 8+2 | 16k | 32k | 4 次读取+4 次写入 | 6 次读取+4 次写入 |
图 1:表格说明使用 PDW 和部分写入技术的写入开销
突出显示的 text 表示该场景下更有效的方法。
在 IO 总数在 PDW 打开和关闭之间相同的情况下(即使用部分写入方法),FastEC 将倾向于使用 PDW,因为在不同的 OSD 上读取和写入比读取和写入同一个 OSD 更有效,因为 bluestore 缓存元数据。
性能结果 ¶
为了本博客的目的,我们在单个节点上运行了性能测试。 使用单个节点意味着没有网络瓶颈,我们可以专注于 CPU 和驱动器瓶颈。 绝对性能测量值不会很高,但我们可以仍然比较相对性能,因为优化将证明我们已经提取了受 CPU 或驱动器限制的工作负载中的更多性能。
系统的配置如下
- 单个节点 – 8 个 OSD - NVME 闪存
- 2 x Intel(R) Xeon(R) Platinum 8276M CPU @ 2.20GHz – 每个插槽 28 个核心
- LibRBD FIO 客户端 – 16 个卷 – 每个 RBD 卷 1 个客户端
- ISAL 插件
如何读取响应曲线 ¶
对于接下来的部分,我需要解释响应曲线(也称为曲棍球棒曲线)。

图 2:如何读取响应曲线。
响应曲线绘制的是每秒输入/输出 (IOPS) 与延迟之间的关系。从图表的左下角开始,预期随着向存储系统的队列深度增加,IOPS 也会增加。在曲线的某个点,也称为拐点,这是饱和点,此时吞吐量不再增加,并且将额外的工作添加到存储系统队列只会增加延迟。 这就是产生曲线“曲棍球棒”形状的原因。
对于曲线的每个点,I/O 工作负载会在指定的队列深度下运行几分钟,然后计算平均 IOPS 和延迟。通常为 3 到 5 分钟(带预热时间)。
饱和点是系统特定的,并且可能有很多原因导致达到此限制,具体取决于工作负载,例如 CPU、CPU 核心、驱动器、网络接口或软件中的某些软件资源限制,只是几个可能的原因,可能还有其他原因。
通常,在客户端系统容量估算期间使用响应曲线来了解所售系统的限制,并评估系统剩余的裕量。通常,客户不会超过最大吞吐量的 70% 左右,以允许为扩展留出足够的裕量。 曲线开始到拐点的平直线表明延迟与吞吐量和延迟的低方差一致。
如何创建响应曲线或可能影响响应曲线的因素是性能最佳实践的主题。这超出了本博客文章的范围,将在 CBT(Ceph 基准测试工具)的一系列博客中讨论,这些博客将很快在 ceph.io 上发布
在比较响应曲线时,不可避免地会存在一些差异,通常在 5% 到 10% 左右。
现在,让我们开始讨论 Tentacle 中 Fast EC 性能改进,以便解释下一节图例以及本博客中的所有其他图表,例如
squid-ec-6+2-4K 表示我们正在运行 squid 构建,使用具有 6+2 配置和 4K 条带单元的擦除编码。因此,这些图表将 Squid 构建与具有 4K stripe_unit 6+2 擦除码的构建与启用 FastEC 和 16K stripe_unit 以及 6+2 配置的 Tentacle 构建进行比较。 其他图表使用不同的擦除码配置。
写入结果 - 小写 ¶

图 3:小写 - Squid 4k 6+2 EC 与 Tentacle 16k Fast EC 6+2 小写对于 Ceph FS、RBD 和小对象工作负载很常见。
在图 3 中,我们首先比较 Squid 4k stripe_unit 6+2 擦除码与启用 FastEC 16k stripe_unit 6+2 配置的 Tentacle。这是一个小型系统单节点,具有 8 个 OSD 的系统。 无论如何,20K IOPS 并不是存储系统的特别高的吞吐量,但是我们感兴趣的不是绝对数字,而是对两段软件的相对性能的兴趣,这突出了我们至少可以将驱动器的吞吐量提高一倍,同时实现相同的延迟,或者在某些情况下提高延迟。 如果您需要更高的性能,可以向配置中添加更多驱动器和节点。
Squid 4K 和 Tentacle 16k 之间的性能改进主要归功于 FastEC 的奇偶校验 Delta 写入功能,如图 1 所示,该图比较了根据 K 值和写入 IO 请求的大小而变化的读/写操作数量。
您的 K 选择会影响您从系统获得的性能。 这里有一组图表,它们执行相同的 4/8/16k 随机写入测试,比较 2+2、4+2 和 6+2 EC 配置

图 4:小写 - Squid – EC 2+2、4+2 和 6+2 – 4k 与 tentacle – FastEC 在 2+2、4+2、6+2 配置中
以前在 Squid 中,写入性能随着 K 的增加而降低,原因是整个条带始终被读取和写入,这意味着对于更宽的擦除码(例如 4+2 和 6+2),开销会更高,性能会降低。 将 K 增加到 6 以上会导致性能进一步下降。
对于带有 Fast EC 的 Tentacle,奇偶校验 delta 写入优化意味着更宽的擦除码性能随着 K 的增加而提高。 预计性能不会超过 6+2 提高。
稍后在本博客中,我们将讨论如何建议选择更大的 K 值,因为这可以提高存储效率,减少容量开销。
写入结果 - 大写 ¶

图 5:大写 - 比较 Squid 4k、Tentacle 16k 与三路复制
对于大写和大 S3 对象,与 Squid 相比,吞吐量略有增加,延迟降低。 您可以期望为更大的 1Mbyte 对象启用 FastEC 获得相同的性能,性能接近三路复制。
读取结果 - 小读 ¶

图 6:小读比较 4k stripe_unit Squid 6+2 EC 到 16k Tentacle 6+2 EC
由于 Fast EC 中添加的局部读取功能,小读提高了 2-3 倍。 这对于 RBD、Ceph FS 和小对象工作负载很有用。

图 7:小读 - 比较 2+2、4+2、6+2 Squid 到 Tentacle 到三路复制
比较 Squid 和 Tentacle 之间的不同擦除码配置。
这些结果突出了以下观察结果
- 对于 Squid,随着 K 从 2+2 -> 4+2 -> 6+2 增加。 最大吞吐量会降低,原因如下,Squid 没有局部读取。 随着 K 的增加,更多数据会在小读操作中被丢弃,因此会增加 OSD 和 CPU 利用率。
- 对于 Tentacle,随着 K 的增加,最大吞吐量会扩展到我们可以实现与三路复制几乎相同的读取性能的程度。
- Tentacle 和 3 路读取之间的延迟差距正在将非主 OSD 重定向到主 OSD。
直接读取,Ceph 未来版本中的一项功能将消除到主 OSD 的跳转,这将提高延迟以达到与三路复制性能相当的水平。
目前定于 Umbrella 时间范围,未来将发布有关此功能的博客。
读取结果 - 大读 ¶

图 8:大读 - 比较 6+2 Squid 4K 到 Tentacle 6+2 16k 到三路复制
对于大读、备份、大 S3 对象和流式工作负载,使用 Fast EC 与 Squid 相比,延迟略有降低,吞吐量提高了约 1.2 倍。
预计直接读取将进一步显着提高 EC 吞吐量,使其更接近三路复制,同时由于将大型请求分成块并并行将 IO 发送到条带中的所有 OSD 而降低延迟。
写入追加结果 ¶
写入追加是指将新数据附加到现有对象的末尾。 这通常常见于顺序写入、备份、AI 或 RGW PUT 工作负载。

图 9:写入追加 – Squid 4k 到 Tentacle 16k stripe_unit
这些结果突出了以下好处
- 对于高达 512k 的所有写入,延迟显着降低,并且在 1Mbyte 时略有改善。
- 对于高达 16k 的小块写入,可用 IOPs 吞吐量显着增加。
- 对于 16k 到 64k 的写入,吞吐量也有所适度提高。
- 512k 和 1Mbyte 写入的性能没有下降,同时显着提高了延迟。
有趣的是,增加 K(例如,从 2+2 到 4+2/6+2)会增加延迟。 这是因为在 2+2 配置中,50% 的 I/O 被写入 PG 的主 OSD,而在 4+2 配置中,25% 的 I/O 被写入 PG 的主 OSD。 写入非主 OSD 需要将请求转发到主 OSD,从而导致额外的信使跳跃操作。
混合读写工作负载 ¶

图 10:混合 16k 70/30 - Squid 4k 到 Tentacle 16k 到三路复制
事务和文件工作负载包含混合的读写,通常是小块,大约 16k 大小,读写比例为 70% 和 30%。 此图包含典型的 70/30 16k 混合工作负载。
与 Squid 相比,使用 FastEC 至少可以使吞吐量翻倍。 三路复制仍然更快,但是与 6+2 16k stripe_unit 擦除池和 Fast EC 相比,它大约是性能的 50%,但是您需要考虑 6+2 擦除码只有 33% 的开销,而三路配置需要 3 倍的物理容量。 三路复制是一种比使用 EC 更昂贵的选项。 因此,EC 在 6+2 形式下具有比三路复制更好的性价比。
在相同的存储系统上,由于 EC 的算法需要执行比复制更多的 IO,因此由 EC 主导的写入工作负载永远无法像复制那样执行得好。 但是,您可以减少物理容量并相应地重构存储来抵消这种成本。
重要的是要注意,传统的存储控制器通常在 RAID-1(镜像)和 RAID-6(擦除编码 K+2)之间提供选择,它们也具有类似的成本性能权衡。
使用更宽的擦除码,例如 6+2,需要 9 个节点,因此您可能需要向 Ceph 集群添加更多节点。 但是,存储解决方案的成本通常由您安装以存储数据的驱动器成本决定,尤其是在使用闪存时。 使用擦除码,您可以用更少的成本获得一半的性能,从而有机会扩展以构建与复制相同的性能水平。
总结 ¶
EC 性能增强的目标是使性能足够好,以便可以将其用于块和文件存储,特别是考虑到使用 EC 而不是三路复制的成本性能优势。
对于大多数用户来说,在选择 K 值时不应考虑性能。 用户应使用更高的 K 值(例如 6+2)以获得更好的存储效率,同时保持与复制相同的冗余度。
在 6+2 配置中使用 Fast EC,您可以利用这些节省来增加节点数量,将驱动器重新分配到节点,并实现与三路复制相同的性能,同时仍然节省资金。
Tentacle 中的 Fast EC 功能通过允许您使用擦除编码作为替代且更节省空间的存储方法,从而降低 Ceph 集群的总拥有成本,并具有比复制池更好的性价比。
我希望这篇博客文章能帮助您了解 Fast EC 的性能优势。 该团队正在进行更多改进
- 直接读取 – 此功能将显着提高读取性能,以提供与复制池相同的性能。
- 对象打包 – 此功能为希望在不降低空间利用率的情况下增加
stripe_unit增加到 16k 以上的用户带来实质性好处,这将为超过 16k 的读取和写入带来其他性能改进。 这对于更大的(4MB)对象将是一个有用的改进。
直接读取的目标是 Umbrella 版本。 对象打包将在未来的版本中发布。 更多关于这些功能的数据将在临近时提供。