Ceph Reef 冻结(第 2 部分):RGW 性能

摘要
Ceph 社区最近冻结了即将发布的 Ceph Reef 版本,今天我们来看一下 Reef 的 RGW 性能和效率,测试环境为 10 个节点、60 个 NVMe 驱动器的集群。我们部署了 20 个 RGW 实例和 200 个 hsbench S3 客户端,以跨 512 个存储桶执行高度并行的工作负载。在大多数测试中,Reef 的速度通常比 Quincy 快 1-5%。在 3 倍复制的情况下,它实现了大约 53GB/s 的 4MB GET 和 18.6GB/s 的 4MB PUT。我们怀疑在两种情况下,我们都达到了或接近网络饱和点。Reef 还实现了大约 312K 4KB GET/s 和 178K 4KB PUT/s,同样是在 3 倍复制的情况下。在大对象测试中,CPU 使用率在两个版本之间是等效的。然而,在 4KB PUT 和 GET 测试中,Reef 使用的 CPU 资源比 Quincy 多高达 23%。随着 Reef 版本的临近,我们将密切关注这一点,并可能需要进行二分查找以了解原因。最后,我们注意到 OSD 和 RGW 之间的总 CPU 使用率存在显著差异,具体取决于正在运行的工作负载类型。这可能会对硬件购买和部署决策产生重大影响,我们希望本文能为此提供一些指导。
简介
在 本系列第一部分 中,我们研究了名为 CBT 的工具如何用于了解 RBD 性能在 Ceph 的多个版本之间是如何变化的。在第一部分中,CBT 利用 Jens Axboe 广为人知的 fio 工具来针对 RBD 镜像运行工作负载。CBT 还可以利用 S3 基准测试工具来测试 RGW。在 Ceph 的先前版本中,我们已经有效地利用了这种功能来捕获性能回归。结合 CBT、hsbench S3 基准测试和 git bisect,我们能够识别出两个单独的提交,这些提交损害了 Ceph Pacific 版本的 RGW 性能和效率。
一旦识别出这些提交,Ceph 出色的 RGW 团队就能够创建修复程序,使性能和 CPU 使用率恢复到我们在 Nautilus 中看到的水平。在本文中,我们不会执行任何二分分析,但我们将使用相同的工具来查看 Reef 功能冻结对 S3 工作负载的影响。
致谢
一如既往,感谢我在 Clyso GmbH 的朋友和同事们提供的鼓励和支持,在为社区创造类似的文章时。同时感谢 IBM / Red Hat 和 Samsung 为 Ceph 上游社区提供用于本次测试的硬件。最后,感谢所有为我们带来 Ceph 的又一个优秀版本的 Ceph 开发人员。今天,我特别要感谢 RGW 开发团队多年来为我们辛勤努力。你们的工作不仅让 RGW 更好,也让 Ceph 整体更好。
集群设置
| 节点 | 10 x Dell PowerEdge R6515 |
|---|---|
| CPU | 1 x AMD EPYC 7742 64C/128T |
| 内存 | 128GiB DDR4 |
| 网络 | 1 x 100GbE Mellanox ConnectX-6 |
| NVMe | 6 x 3.84TB Samsung PM983 |
| 操作系统版本 | CentOS Stream release 8 |
| Ceph 版本 1 | Quincy v17.2.5 (从源代码构建) |
| Ceph 版本 2 | Reef 9d5a260e (从源代码构建) |
所有节点都位于同一 Juniper QFX5200 交换机上,并通过单个 100GbE QSFP28 链路连接。Ceph 使用 CBT 部署,并启动了 fio 测试。每个节点配置为托管 6 个 OSD,并配置了 2 个共置 RGW 守护程序。对于所有测试,保持 3 个 OSD 与 1 个 RGW 守护程序的比例。在 Intel 系统上,一个重要的操作系统级别优化是将 tuned profile 设置为“latency-performance”或“network-latency”。这主要通过避免与 CPU C/P 状态转换相关的延迟峰值来实现。基于 AMD Rome 的系统似乎对这方面不太敏感,并且我尚未确认 tuned 实际上是否限制了 C/P 状态转换,但是,tuned profile 仍然设置为“network-latency”用于这些测试。
测试设置
CBT 被配置为使用一些修改后的设置来部署 Ceph,与默认设置不同。每个 OSD 被赋予 8GB 的内存目标,并且使用 msgr V1,同时禁用 cephx。未对 RGW 进行任何特殊调整。使用 hsbench 基准测试进行 S3 测试。每个节点启动 20 个 hsbench 进程,每个进程连接到不同的 RGW 实例。因此,每个 RGW 进程都有一个关联的 hsbench 进程从每个节点连接到它(总共 200 个 hsbench 进程)。每个 hsbench 进程被配置为使用 64 个线程,并使用公共存储桶前缀来定位 512 个存储桶。某些后台进程,例如 scrub、deep scrub、pg autoscaling 和 pg balancing 被禁用。所有 RGW 存储池都使用 3 倍复制。数据和索引存储池各被赋予 8192 个 PG,而 root、control、meta 和 log 存储池各被赋予 64 个 PG。针对 quincy 和 reef 运行了两个单独的测试套件,分别包含 200 万个 4MiB 对象和 2 亿个 4KiB 对象。每个套件中的测试按以下顺序运行
| 测试 | 描述 |
|---|---|
| cxi | 清除所有现有对象,删除存储桶,初始化存储桶 |
| p | 将对象放入存储桶 |
| l | 列出存储桶中的对象 |
| g | 从存储桶中获取对象 |
| d | 从存储桶中删除对象 |
4MB PUT
Reef 在所有三个测试迭代中略快于 Quincy,保持大约 2% 的领先优势。RGW 和 OSD 进程的 CPU 使用率在两个测试中相似。令人惊讶的是,Quincy 和 Reef 都显示了一个时期,RGW CPU 使用率徘徊在 5 个核心左右,然后在测试 2-3 分钟后翻倍到 10 个核心。
在 本系列第一部分 中,我们研究了 4MB 顺序写入吞吐量,并发现使用 librbd,我们可以保持大约 25GB/s(3 倍复制时 75GB/s)。为什么我们在这里看到的 4MB PUT 只有大约 18.5GB/s?一个主要原因是我们将数据传输了两次。一次是从客户端到 RGW,另一次是从 RGW 到 OSD。由于我们创建了一个网格,有些传输将发生在同一节点上的 RGW 实例或 OSD 上。我们也不能忽略复制,因为我们总是会产生至少 2 次额外的传输,从主 OSD 到辅助 OSD,这些传输必须降落在其他节点上。
Probability of 2 transfers = 1/10 * 1/10 = 1/100
Probability of 4 transfers = 9/10 * 9/10 = 81/100
Probability of 3 transfer = 1 - 1/100 - 81/100 = 18/100
相对于最大网络吞吐量,我们应该期望的总体最佳性能是
100 / (2 * (1/100) + 4 * (81/100) + 3 * (18/100)) = 26.31%
在 librbd 的情况下,我们始终有 3 次传输,3 倍复制(1 次到主存储,然后 1 次到每个辅助存储)
100 / 3 = 33.3%
应用我们的比率并相乘,我们得到
25GB/s * 26.31/33.3 = 19.75GB/s
看起来我们做得略逊于 RBD,但考虑到额外的网络开销,差距并不太大。
4MB LIST
存储桶列表时间完全由对象数量决定。在这种情况下,由于我们只有 200 万个对象,分布在 512 个存储桶中,单个存储桶列表时间非常短。Reef 再次与 Quincy 一样快或略快。
4MB GET
在此测试中,RGW 和 OSD 进程的 CPU 使用率相当一致。与 PUT 测试类似,我们必须考虑数据传输的概率。由于我们使用复制,我们将始终仅从 OSD 到 RGW 传输数据一次,然后传输到客户端。
Probability of 0 transfers = 1/10 * 1/10 = 1/100
Probability of 2 transfers = 9/10 * 9/10 = 81/100
Probability of 1 transfer = 1 - 1/100 - 81/100 = 18/100
100 / (0 * (1/100) + 2 * (81/100) + 1 * (18/100)) = 55.6%
在这里,我们保持 Quincy 约为 51GB/s,Reef 约为 53GB/s。这非常接近这些 100GbE 网卡的理论最大值。
4MB DELETE
这里的删除“吞吐量”数字看起来非常高,但是删除性能主要由正在删除的对象数量而不是对象大小决定,并且实际删除过程是异步的。尽管如此,Reef 平均比 Quincy 快一些。
4KB PUT
与之前的测试一样,Reef 略快于 Quincy。OSD CPU 使用率在两者中大致相同,但是,RGW CPU 使用率似乎增加了大约 15%。好的一点是,在 Quincy 的 RGW 中,在每个测试迭代结束时都出现了 CPU 使用量急剧上升的情况,而 Reef 中没有出现。一个重要的点是,RGW 和 OSD 都非常努力地保持 180K PUT/s。RGW 需要对主 OSD 进行 3 次往返(2 次同步,1 次异步)才能正确写入数据并使存储桶索引正确同步。对于这些 4K 对象工作负载,这让 RGW 和 OSD 都非常繁忙。
4KB LIST
由于对象数量增加,存储桶列表时间比之前的测试更长。Reef 在第一次迭代中略快,但除此之外,Quincy 和 Reef 几乎不分伯仲。
4KB GET
首先,Reef 中的 GET 性能比 Quincy 更快、更稳定。尽管如此,这里有一些非常有趣的行为。在 Quincy 中,测试的前 2 分钟由极高的 CPU 使用率主导。完成之后,稳定的 CPU 使用率比 Reef 低得多。OSD CPU 使用率也较低。Reef 在 RGW 端使用了大约 10-20% 更多的 CPU,在 OSD 端使用了大约 17-23% 更多的 CPU。这可能是我们需要跟进并在 Reef 发布之前进行二分查找的另一个回归。好消息是,Reef 的行为再次显得更加一致。虽然 RGW CPU 使用率在测试开始时较高,但它远不如 Quincy 测试中那么高。
4KB DELETE
最后,Reef 平均删除 4K 对象的速度快约 5%。再次强调,这是一个异步过程,因此结果可能与 RGW 在后台删除对象的速度不匹配。
结论
这些测试仅显示 RGW 性能特征的一小部分。我们没有时间在本篇文章中研究单操作延迟,或者尝试不同的客户端<->rgw 拓扑来最大限度地减少网络流量并更努力地推动 RGW 和 OSD。还有许多其他测试可以运行,以提供更多信息。尽管如此,在我们进行的测试中,我们看到了两种趋势。1) Reef 在大多数测试中比 Quincy 快 1-5% 左右,并且在测试和测试迭代中都相当一致。2) 在某些测试中,尤其是在 4K GET 测试中,Reef 显示出比 Quincy 更高的 CPU 使用率。这在 RGW 进程中更为明显,但我们也看到了 OSD 中的情况。我们可能会在 Reef 发布之前跟进这一点。
还有一些其他有趣的事情值得注意。在之前的测试中,我们使用了 60 个 NVMe 驱动器的 10 个 RGW 实例。在这些测试中,我们使用了 20 个 RGW 实例,并且与我们之前看到的相比,在小型对象 PUT 和 GET 测试中,我们看到了显著更高的性能。将 RGW 数量增加到更高的比例,也许是每个 OSD 1 个 RGW 实例甚至每个 OSD 2 个 RGW 实例,可能会产生更好的小型对象性能。
第二件有趣的事情是,CPU 消耗量在这些测试中差异很大,RGW 和 OSD 进程之间的 CPU 消耗率比例也发生了变化。如果我们查看 Reef 的结果并计算 RGW 和 OSD 使用的大致核心数,我们会得到
4MB
| 测试 | 结果 | 总 RGW 核心数 | 总 OSD 核心数 | 总核心数 | RGW/OSD 核心比率 |
|---|---|---|---|---|---|
| 4MB PUT | 18.6GB/s | 184 核心 | 152 核心 | 336 核心 | 6/5 |
| 4MB GET | 53GB/s | 88 核心 | 55 核心 | 143 核心 | 8/5 |
4KB
| 测试 | 结果 | 总 RGW 核心数 | 总 OSD 核心数 | 总核心数 | RGW/OSD 核心比率 |
|---|---|---|---|---|---|
| 4KB PUT | 178K IOPS | 269 核心 | 475 核心 | 744 核心 | 11/20 |
| 4KB GET | 312K IOPS | 302 核心 | 102 核心 | 404 核心 | 3/1 |
除了理解这些测试中使用的核心数量之外,这些结果还有另一个值得学习的地方。在容器中运行 Ceph 的想法非常吸引人。Ceph 的最新版本拥有大量的外部依赖项,软件包管理很快就会变得很麻烦。除此之外,许多用户已经为用户应用程序采用了容器,并希望以相同的方式部署 Ceph。这自然延伸到人们希望在容器级别为 Ceph 守护进程分配静态资源:一定数量的内存和一定数量的核心用于运行。这正是我们可能遇到麻烦的地方。我将把关于内存配额的完整讨论留到另一天,但简而言之:在没有专门为此设计的应用程序中,保证内存使用量极其困难。在不付出重大努力的情况下,我们能做的最好的是让 Ceph 进程监视其映射的内存,并自动调整非必要的内存使用量以进行补偿。我应该知道,我编写了 Ceph 底层的内存自动调整和缓存管理代码。
限制核心数量通常不会导致与限制内存相同类型的问题,但请查看 4K 对象测试中核心数量的比例。在这些测试中,PUT 和 GET 之间的差距接近 6 倍。如果您只针对其中一种情况进行优化,您要么会损害另一种情况,要么会在不同的时间点拥有大量处于空闲状态的多余核心。也许在 Ceph 的未来某个版本中,如果我们需要更多的 4K GET 吞吐量,我们可以按需启动或关闭 RGW 容器。但目前,请意识到,实现高性能和高效率(在目前可能的范围内)需要一定的技巧。
感谢您的阅读,如果您有任何问题或想进一步讨论 Ceph 性能,请随时 联系。