集群规模案例研究 – 仲裁队列 第 1 部分
在本系列规模的文章的第一篇文章中,我们介绍了工作负载、测试以及 AWS ec2 上的集群和存储卷配置。在这篇文章中,我们将运行一个带有仲裁队列的规模分析。我们还运行了镜像队列的规模分析。
在这篇文章中,我们将运行强度递增的测试,这些测试将在理想条件下测量我们候选集群在不同发布速率下的规模。在下一篇文章中,我们将运行弹性测试,测量我们的集群是否能够在不利条件下处理我们的目标峰值负载。
所有仲裁队列都使用以下属性声明
- x-quorum-initial-group-size=3(复制因子)
- x-max-in-memory-length=0
x-max-in-memory-length 属性强制仲裁队列在安全的情况下立即从内存中删除消息体。您可以将其设置为更长的限制,这是最激进的设置 - 旨在避免内存的大量增长,但代价是在消费者跟不上时需要进行更多磁盘读取。如果没有此属性,消息体将始终保留在内存中,这会导致内存增长到触发内存警报的程度,从而严重影响发布速率 - 在此工作负载案例研究中,我们希望避免这种情况。
理想条件 – 强度递增测试
在之前的一篇文章中,我们讨论了运行基准测试的选项。您可以使用以下命令以这些强度运行此工作负载
bin/runjava com.rabbitmq.perf.PerfTest \
-H amqp://guest:guest@10.0.0.1:5672/%2f,amqp://guest:guest@10.0.0.2:5672/%2f,amqp://guest:guest@10.0.0.3:5672/%2f \
-z 1800 \
-f persistent \
-q 1000 \
-c 1000 \
-ct -1 \
-ad false \
--rate 50 \
--size 1024 \
--queue-pattern 'perf-test-%d' \
--queue-pattern-from 1 \
--queue-pattern-to 100 \
-qa auto-delete=false,durable=false,x-queue-type=quorum \
--producers 200 \
--consumers 200 \
--consumer-latency 10000 \
--producer-random-start-delay 30
只需将 --rate 参数更改为您每个测试所需的速率,并记住它是每个发布者的速率,而不是总的组合速率。由于消费者处理时间(消费者延迟)设置为 10 毫秒,因此对于更高的发布速率,我们还需要增加消费者的数量。
请注意,我们设置了 durable=false,因为此属性与仲裁队列无关。
io1 - 高性能 SSD
在仲裁队列达到其限制的强度下,它们往往会累积消息积压,导致 95 百分位数及以上端到端延迟增加。以下是 50 和 75 百分位的延迟。
我们看到,在某些情况下,当仲裁队列达到吞吐量容量时,延迟会大幅上升。
除了 3x16 和 5x8 集群之外,所有集群都管理了 30k msg/s 的目标峰值,并且所有集群的端到端延迟都低于 1 秒的要求。正如预期的那样,更大的集群实现了最高的吞吐量。
吞吐量最低的集群(3x16)服务器指标
我们看到,对于这个小型集群,CPU 似乎是资源瓶颈。
首先,我们看到与镜像队列相比,IOPs 的数量要少得多。随着强度递增,IOPs 实际上下降了,每次写入操作都变得越来越大。
吞吐量最高的集群服务器指标
对于这个大型集群,CPU 没有达到饱和。网络带宽达到 500 Mbps,低于镜像队列的相同测试(即使镜像队列的复制因子较低)达到的 750 Mbps。镜像队列对网络的低效使用在之前的博文中进行了讨论。
就像镜像队列测试一样,性能最差的集群不仅管理的吞吐量较低,而且磁盘 IO 也较高。这是因为仲裁队列写入磁盘的方式。每条消息始终写入预写日志 (WAL)。为了控制 WAL 的大小,WAL 文件会被截断,这涉及将其消息写入段文件。有一种优化方法,如果消息在写入段文件之前被消费并确认,则不会执行第二次磁盘写入 - 就 RabbitMQ 而言,该消息不再存在。这意味着如果消费者跟得上,消息只会写入磁盘一次,但如果消费者落后,则消息最终可能会写入磁盘两次。
吞吐量最高的集群没有看到任何资源瓶颈,表明限制是协调(基于 Raft 的复制)的成本。
吞吐量最低的集群确实在早期达到了 90% 以上的 CPU 利用率,这与它停止达到目标吞吐量的时刻相对应。它在第四次测试中达到了 > 90%,从第五次测试开始,它未能可靠地匹配目标。
因此,仲裁队列将使用比镜像队列(最多写入磁盘一次)更多的磁盘带宽。
这就是每个集群如何应对 30k msg/s 的目标速率。
匹配目标吞吐量的排行榜
从 35k msg/s 开始,许多规模随着目标吞吐量的增加继续显示吞吐量的增加,但始终略低于目标。
能够在 30k msg/s 远超目标的规模是
- 集群:7 个节点,16 个 vCPU(c5.4xlarge) - 60k msg/s
其余规模在从 35k msg/s 开始的每个测试中都未能达到其目标,但在测试过程中仍然显示出更高的吞吐量。这是根据最高吞吐量排列的排行榜
- 集群:7 个节点,16 个 vCPU(c5.4xlarge)。速率:65k msg/s
- 集群:9 个节点,8 个 vCPU(c5.2xlarge)。速率:63k msg/s
- 集群:7 个节点,8 个 vCPU(c5.2xlarge)。速率:54k msg/s
- 集群:5 个节点,16 个 vCPU(c5.4xlarge)。速率:53k msg/s
- 集群:5 个节点,8 个 vCPU(c5.2xlarge)。速率:50k msg/s
- 集群:3 个节点,36 个 vCPU(c5.9xlarge)。速率:40k msg/s
- 集群:3 个节点,16 个 vCPU(c5.4xlarge)。速率:37k msg/s
横向扩展和纵向/横向扩展的中间地带显示了最佳结果。
每月每 1000 条消息的成本排行榜(在最高吞吐量下)。
- 集群:5 个节点,8 个 vCPU(c5.2xlarge)。成本:97 美元(50k)
- 集群:3 个节点,16 个 vCPU(c5.4xlarge。成本:98 美元(37k)
- 集群:5 个节点,16 个 vCPU(c5.4xlarge。成本:115 美元(53k)
- 集群:7 个节点,8 个 vCPU(c5.2xlarge。成本:126 美元(54k)
- 集群:3 个节点,36 个 vCPU(c5.9xlarge。成本:137 美元(40k)
- 集群:9 个节点,8 个 vCPU(c5.2xlarge。成本:139 美元(63k)
- 集群:7 个节点,16 个 vCPU(c5.4xlarge。成本:142 美元(65k)
每月每 1000 条消息的成本排行榜(在 30k msg/s 的目标下)。
我们看到有两个集群没有完全达到 30k msg/s 的目标。以下是达到目标的集群的排行榜
- 集群:5 个节点,16 个 vCPU(c5.4xlarge)。成本:135 美元
- 集群:7 个节点,8 个 vCPU(c5.2xlarge)。成本:151 美元
- 集群:3 个节点,36 个 vCPU(c5.9xlarge)。成本:183 美元
- 集群:9 个节点,8 个 vCPU(c5.2xlarge)。成本:194 美元
- 集群:7 个节点,16 个 vCPU(c5.4xlarge)。成本:204 美元
在此测试中,成本效益和性能相互矛盾。当存储卷是最昂贵的项目时,横向扩展会很昂贵。最佳价值来自纵向和横向扩展的中间地带。
我们真的需要那些昂贵的 io1 SSD 吗?此测试中的 IOPs 相对较低,我们没有超过 250MiB/s,因此廉价的 gp2 卷应该是不错的选择。让我们看看。
gp2 - 通用 SSD
与之前一样,第 50 和 75 百分位数仍然很低。
但在某些情况下,当集群达到其吞吐量容量时,第 95、99 和 99.9 百分位数会大幅上升。此延迟基本上意味着队列开始累积消息。这些积压仅发生在较大的 16 vCPU 集群上。
gp2 卷的结果并不比更昂贵的 io1 卷差。
吞吐量最低的集群(3x16)磁盘指标
吞吐量最高的集群(7x16)磁盘指标。
在这两种情况下,IOPs 起始时都较高,与 3000 IOPs 的限制相对接近(达到 2.3k),但随着负载增加,IO 大小变大,操作数量减少。
对于 30k msg/s 和 1kb 消息的目标,即使我们写入每条消息两次,我们仍然不会达到 gp2 的 250MiB/s 限制。与之前一样,较小的集群看到的磁盘 IO 更多,因为它执行的双重写入次数比更大、性能更高的集群更多。
以下是 30k msg/s 目标的结果。
匹配目标吞吐量的排行榜
从 35k msg/s 开始,许多规模随着目标吞吐量的增加继续显示吞吐量的增加,但始终略低于目标。
能够在 30k msg/s 远超目标的规模是
- 集群:7 个节点,c5.4xlarge - 60k msg/s
在超过 35k msg/s 的测试中,其余集群的吞吐量都略微或大幅低于目标值,但在测试过程中仍然显示出更高的吞吐量。以下是根据最高吞吐量排列的排行榜。
- 集群:7 个节点,16 个 vCPU (c5.4xlarge)。速率:67k msg/s
- 集群:9 个节点,8 个 vCPU (c5.2xlarge)。速率:66k msg/s
- 集群:5 个节点,16 个 vCPU (c5.4xlarge)。速率:54k msg/s
- 集群:7 个节点,8 个 vCPU(c5.2xlarge)。速率:54k msg/s
- 集群:5 个节点,8 个 vCPU (c5.2xlarge)。速率:42k msg/s
- 集群:3 个节点,36 个 vCPU (c5.9xlarge)。速率:37k msg/s
- 集群:3 个节点,16 个 vCPU (c5.4xlarge)。速率:36k msg/s
横向扩展和纵向/横向扩展的中间地带显示了最佳结果。
每月每 1000 条消息的成本排行榜(在最高吞吐量下)。
- 集群:5 个节点,8 个 vCPU (c5.2xlarge)。成本:$41 (42k)
- 集群:7 个节点,8 个 vCPU (c5.2xlarge)。成本:$45 (54k)
- 集群:9 个节点,8 个 vCPU (c5.2xlarge)。成本:$47 (66k)
- 集群:3 个节点,16 个 vCPU (c5.4xlarge)。成本:$49 (36k)
- 集群:5 个节点,16 个 vCPU (c5.4xlarge)。成本:$55 (54k)
- 集群:7 个节点,16 个 vCPU (c5.4xlarge)。成本:$72 (67k)
- 集群:3 个节点,36 个 vCPU (c5.9xlarge)。成本:$97 (37k)
每月每 1000 条消息的成本排行榜(在 30k msg/s 的目标下)。
达到 30k msg/s 目标的集群
- 集群:7 个节点,8 个 vCPU (c5.2xlarge)。成本:$54
- 集群:9 个节点,8 个 vCPU (c5.2xlarge)。成本:$69
- 集群:5 个节点,16 个 vCPU (c5.4xlarge)。成本:$98
- 集群:7 个节点,16 个 vCPU (c5.4xlarge)。成本:$107
- 集群:3 个节点,36 个 vCPU (c5.9xlarge)。成本:$120
成本效益和性能在此测试中更加一致。由于存储卷成本低廉,小型扩展的虚拟机展现出极高的投资回报率。对于此工作负载,io1 根本不值得使用。
在之前的文章中,我们建议使用带有仲裁队列的 SSD。我们证明了仲裁队列在仅使用仲裁队列的工作负载下,在 HDD 上也能表现良好。但是,当运行经典队列和仲裁队列的混合工作负载时,我们发现 HDD 无法提供仲裁队列所需的性能。鉴于这是一个纯粹的仲裁队列工作负载,让我们看看它们在 HDD 上的表现如何。
st1 - HDD
仲裁队列在 HDD 上表现良好,尽管一旦集群达到其吞吐量容量,吞吐量就会变得更加不稳定。除 7x16 集群外,所有集群的吞吐量也略有降低,而该集群在这些测试中始终保持在顶端。我们通常建议使用 SSD,因为由于经典队列的随机 I/O 特性,混合经典/仲裁队列工作负载的性能可能会大幅下降。但此测试表明,对于纯仲裁队列工作负载,HDD 可以表现良好。
50% 和 75% 百分位延迟高于 SSD,但都低于一秒,除了 5x8 集群,它在更高的强度下出现了消息积压。
与 SSD 一样,在某些情况下,当集群达到其吞吐量容量时,延迟会飙升(这意味着发生了少量消息积压)。
重要的是,在 30k msg/s 目标下,所有延迟都低于一秒。
查看磁盘指标,正如 HDD 所预期的那样,IOPS 通常再次较低,相应的写入大小也较大。
以下是 30k msg/s 目标的结果。
这次我们可以说 5x8 集群已经达到了 30k msg/s 的目标,而它在 SSD 上时却没有达到。
从 35k msg/s 及以上,许多集群在目标吞吐量增加时继续显示吞吐量增加,但略低于目标。
能够在 35k msg/s 以上达到目标的集群有:
- 集群:7 个节点,16 个 vCPU (c5.4xlarge)。速率:60k msg/s
- 集群:9 个节点,8 个 vCPU (c5.2xlarge)。速率:40k msg/s
其余集群在 35k msg/s 以上的每个测试中都未达到目标,但在测试过程中仍然显示出更高的吞吐量。以下是根据最高吞吐量排列的排行榜。
- 集群:7 个节点,16 个 vCPU (c5.4xlarge)。速率:67k msg/s
- 集群:9 个节点,8 个 vCPU (c5.2xlarge)。速率:62k msg/s
- 集群:5 个节点,16 个 vCPU (c5.4xlarge)。速率:54k msg/s
- 集群:7 个节点,8 个 vCPU (c5.2xlarge)。速率:50k msg/s
- 集群:5 个节点,8 个 vCPU (c5.2xlarge)。速率:37k msg/s
- 集群:3 个节点,36 个 vCPU (c5.9xlarge)。速率:32k msg/s
- 集群:3 个节点,16 个 vCPU (c5.4xlarge)。速率:27k msg/s
横向扩展和纵向/横向扩展的中间地带显示了最佳结果。
每月每 1000 条消息的成本排行榜(在最高吞吐量下)。
- 集群:5 个节点,16 个 vCPU (c5.4xlarge)。成本:$74 (54k)
- 集群:5 个节点,8 个 vCPU (c5.2xlarge)。成本:$76 (37k)
- 集群:7 个节点,8 个 vCPU (c5.2xlarge)。成本:$78 (50k)
- 集群:9 个节点,8 个 vCPU (c5.2xlarge)。成本:$81 (62k)
- 集群:3 个节点,16 个 vCPU (c5.4xlarge)。成本:$89 (27k)
- 集群:7 个节点,16 个 vCPU (c5.4xlarge)。成本:$94 (67k)
- 集群:3 个节点,36 个 vCPU (c5.9xlarge)。成本:$132 (32k)
每月每 1000 条消息的成本排行榜(在 30k msg/s 的目标下)。
- 集群:5 个节点,8 个 vCPU (c5.2xlarge)。成本:$93
- 集群:7 个节点,8 个 vCPU (c5.2xlarge)。成本:$131
- 集群:5 个节点,16 个 vCPU (c5.4xlarge)。成本:$134
- 集群:3 个节点,36 个 vCPU (c5.9xlarge)。成本:$142
- 集群:9 个节点,8 个 vCPU (c5.2xlarge)。成本:$168
- 集群:7 个节点,16 个 vCPU (c5.4xlarge)。成本:$211
在这种情况下,成本效益和性能并不相互矛盾(如 io1),但它们也不一致(如 gp2)。横向扩展最有利于性能,但更昂贵的卷意味着横向扩展现在也不是最具成本效益的。折衷方案,即横向和纵向扩展,是最佳选择。
端到端延迟和三种卷类型
在这些测试中,我们将端到端延迟视为消息从发布到消费之间的时间。如果我们查看 30k msg/s 的目标速率和 7x16 集群类型,我们会看到
io1 SSD
gp2 SSD
st1 HDD
与镜像队列不同,与 gp2 相比,我们没有看到使用昂贵的 io1 卷时延迟有任何改善。正如预期的那样,HDD 显示出比 SSD 更高的端到端延迟。
强度递增基准测试 - 结论
到目前为止,结论是
- 昂贵的 io1 卷根本不值得使用。它的性能与 gp2 没有区别。但是,如果我们有更大的工作负载或更大的消息,我们可能需要一个能够处理超过 250 MiB/s 的卷,在这种情况下,我们可能会选择 io1,但不是高 IOPS 的 io1。对于 io1,您需要按 GB 支付卷的费用,还需要支付 IOPS 的费用。因此,支付 3000(或更少)而不是 10000 更有意义。
- 经济实惠的 gp2 卷提供了性能和成本的最佳组合,是大多数工作负载的最佳选择。请记住,我们使用了 1TB 的大小,它没有突发 IOPS,并且有 250 MiB 的限制(我们从未达到)。
- 使用廉价的存储卷,扩展较小的 8 个 vCPU 虚拟机在成本效益和性能方面都是最佳选择。
- 使用昂贵的卷,采用横向和纵向扩展的折衷方案是最具成本效益的。
- 使用 3 个大型虚拟机进行纵向扩展从来都不是最佳选择。
30k msg/s 吞吐量下,每月每 1000 msg/s 成本前 5 名配置
- 集群:7 个节点,8 个 vCPU (c5.2xlarge),gp2 SDD。成本:$54
- 集群:9 个节点,8 个 vCPU (c5.2xlarge),gp2 SDD。成本:$69
- 集群:5 个节点,8 个 vCPU (c5.2xlarge),st1 HDD。成本:$93
- 集群:5 个节点,16 个 vCPU (c5.4xlarge),gp2 SDD。成本:$98
- 集群:7 个节点,16 个 vCPU (c5.4xlarge),gp2 SDD。成本:$107
我们仅在理想条件下进行了测试...
我们从 21 种不同的集群配置在 15 种不同的工作负载强度下收集了大量数据。我们认为,到目前为止,我们应该使用中等至大型的小型虚拟机集群,并使用经济实惠的 gp2 卷。但这只是测试了队列为空或接近空闲的理想情况,RabbitMQ 在这种情况下可以发挥其最佳性能。接下来,我们将进行更多测试,以确保即使代理丢失且发生队列积压,我们选择的集群大小也能继续提供我们所需的性能。 接下来我们将测试弹性。