AMQP 1.0 基准测试
这篇博客文章演示了 RabbitMQ 4.0 中的原生 AMQP 1.0 相较于 RabbitMQ 3.13 中的 AMQP 1.0,在性能和可扩展性方面提供了显著的改进。
此外,这篇博客文章表明,在 RabbitMQ 4.0 中,AMQP 1.0 的性能可能略优于 AMQP 0.9.1。
设置
以下设置适用于本博客文章中的所有基准测试
- Intel NUC 11
- 8 核 CPU
- 32 GB 内存
- Ubuntu 22.04
- 单节点 RabbitMQ 服务器
- 服务器运行(仅) 3 个调度器线程(通过 运行时标志 设置为
+S 3
) - Erlang/OTP 27.0.1
- 客户端和服务器在同一台机器上运行
我们使用撰写本文时最新的 RabbitMQ 版本
应用以下 advanced.config 配置
[
{rabbit, [
{loopback_users, []}
]},
{rabbitmq_management_agent, [
{disable_metrics_collector, true}
]}
].
在 rabbitmq_management_agent
插件中禁用了指标收集。 对于生产环境,建议使用 Prometheus。
RabbitMQ 服务器按如下方式启动
make run-broker \
TEST_TMPDIR="$HOME/scratch/rabbit/test" \
RABBITMQ_CONFIG_FILE="$HOME/scratch/rabbit/advanced.config" \
PLUGINS="rabbitmq_prometheus rabbitmq_management rabbitmq_amqp1_0" \
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+S 3"
rabbitmq_amqp1_0
插件在 RabbitMQ 4.0 中是一个 空操作插件。
AMQP 1.0 基准测试在 Docker 容器中运行 quiver
$ docker run -it --rm --add-host host.docker.internal:host-gateway ssorj/quiver:latest
bash-5.1# quiver --version
quiver 0.4.0-SNAPSHOT
经典队列
本节对 经典队列 进行基准测试。
我们声明一个名为 my-classic-queue
的经典队列
deps/rabbitmq_management/bin/rabbitmqadmin declare queue \
name=my-classic-queue queue_type=classic durable=true
RabbitMQ 4.0 中的 AMQP 1.0
客户端发送和接收 100 万条消息。每条消息包含 12 字节的有效负载。接收方一次性重复补充 200 个 链接信用。
# quiver //host.docker.internal//queues/my-classic-queue \
--durable --count 1m --duration 10m --body-size 12 --credit 200
RESULTS
Count ............................................. 1,000,000 messages
Duration ............................................... 10.1 seconds
Sender rate .......................................... 99,413 messages/s
Receiver rate ........................................ 99,423 messages/s
End-to-end rate ...................................... 99,413 messages/s
Latencies by percentile:
0% ........ 0 ms 90.00% ........ 1 ms
25% ........ 1 ms 99.00% ........ 2 ms
50% ........ 1 ms 99.90% ........ 2 ms
100% ........ 9 ms 99.99% ........ 9 ms
RabbitMQ 3.13 中的 AMQP 1.0
# quiver //host.docker.internal//amq/queue/my-classic-queue \
--durable --count 1m --duration 10m --body-size 12 --credit 200
RESULTS
Count ............................................. 1,000,000 messages
Duration ............................................... 45.9 seconds
Sender rate .......................................... 43,264 messages/s
Receiver rate ........................................ 21,822 messages/s
End-to-end rate ...................................... 21,790 messages/s
Latencies by percentile:
0% ....... 67 ms 90.00% .... 24445 ms
25% .... 23056 ms 99.00% .... 24780 ms
50% .... 23433 ms 99.90% .... 24869 ms
100% .... 24873 ms 99.99% .... 24873 ms
针对 RabbitMQ 3.13 的相同基准测试导致吞吐量降低 4.5 倍。
详细的测试执行
---------------------- Sender ----------------------- --------------------- Receiver ---------------------- --------
Time [s] Count [m] Rate [m/s] CPU [%] RSS [M] Time [s] Count [m] Rate [m/s] CPU [%] RSS [M] Lat [ms]
----------------------------------------------------- ----------------------------------------------------- --------
2.1 130,814 65,342 8 79.1 2.1 3,509 1,753 1 7.5 777
4.1 206,588 37,849 6 79.1 4.1 5,995 1,242 0 7.5 2,458
6.1 294,650 43,987 6 79.1 6.1 9,505 1,753 1 7.5 5,066
8.1 360,184 32,734 5 79.4 8.1 13,893 2,194 0 7.5 6,190
10.1 458,486 49,102 6 79.4 10.1 15,793 950 1 7.5 9,259
12.1 524,020 32,734 5 79.4 12.1 21,644 2,923 1 7.5 11,163
14.1 622,322 49,102 5 79.4 14.1 25,154 1,753 1 7.5 13,451
16.1 687,856 32,734 4 79.4 16.1 27,639 1,241 1 7.5 15,246
18.1 786,158 49,102 6 81.0 18.1 30,124 1,241 1 7.5 17,649
20.1 884,460 49,102 6 81.0 20.1 32,610 1,242 1 7.5 19,408
22.1 949,994 32,734 4 81.0 22.1 35,535 1,462 0 7.5 21,293
24.1 999,912 24,934 4 81.8 24.1 38,167 1,315 1 7.5 23,321
26.1 999,974 31 2 0.0 26.1 117,745 39,749 11 7.5 24,475
- - - - - 28.1 202,589 42,380 11 7.5 24,364
- - - - - 30.1 292,554 44,938 13 7.5 24,244
- - - - - 32.1 377,691 42,526 15 7.5 23,955
- - - - - 34.1 469,704 45,961 14 7.5 23,660
- - - - - 36.1 555,719 42,965 12 7.5 23,463
- - - - - 38.1 649,048 46,618 12 7.5 23,264
- - - - - 40.1 737,696 44,280 15 7.5 23,140
- - - - - 42.1 826,491 44,353 15 7.5 23,100
- - - - - 44.1 917,187 45,303 16 7.5 23,066
- - - - - 46.1 999,974 41,394 14 0.0 22,781
RabbitMQ 4.0 中的 AMQP 0.9.1
对于我们的 AMQP 0.9.1 基准测试,我们使用 PerfTest。我们尝试对之前的 AMQP 1.0 基准测试进行某种程度上公平的比较。
由于 AMQP 1.0 的 /queues/:queue 目标地址发送到默认交换机,我们也通过 AMQP 0.9.1 发送到默认交换机。 由于我们在 AMQP 1.0 中使用了 持久 消息,我们在 AMQP 0.9.1 中设置了 persistent
标志。 由于当消息无法路由时,RabbitMQ 使用 released 结果进行确认,我们在 AMQP 0.9.1 中设置了 mandatory
标志。 由于 RabbitMQ v4.0.0-beta.5
使用默认的 rabbit.max_link_credit
为 128,当剩余信用低于 0.5 * 128 时,会向发送客户端授予 128 个额外的信用,我们将 AMQP 0.9.1 发布者配置为最多有 1.5 * 128 = 192 条未确认的消息。 由于我们在之前的运行中使用了 200 个链接信用,我们将 AMQP 0.9.1 消费者配置为 预取 200。
$ java -jar target/perf-test.jar \
--predeclared --exchange amq.default \
--routing-key my-classic-queue --queue my-classic-queue \
--flag persistent --flag mandatory \
--pmessages 1000000 --size 12 --confirm 192 --qos 200 --multi-ack-every 200
id: test-151706-485, sending rate avg: 88534 msg/s
id: test-151706-485, receiving rate avg: 88534 msg/s
id: test-151706-485, consumer latency min/median/75th/95th/99th 99/975/1320/1900/2799 µs
id: test-151706-485, confirm latency min/median/75th/95th/99th 193/1691/2113/2887/3358 µs
总结
仲裁队列
本节对 仲裁队列 进行基准测试。
我们声明一个名为 my-quorum-queue
的仲裁队列
deps/rabbitmq_management/bin/rabbitmqadmin declare queue \
name=my-quorum-queue queue_type=quorum durable=true
流控制配置
为了获得最高的数据安全性,仲裁队列 fsync 所有 Ra 命令,包括
在仲裁队列向发布者确认收到消息之前,它会确保所有文件修改都已刷新到磁盘,即使 RabbitMQ 节点在不久后崩溃,也能保证数据安全。
我的 Linux 机器的 SSD 速度很慢,每次 fsync 需要 5-15 毫秒。由于我们想比较 AMQP 协议实现,而不希望受到廉价磁盘的瓶颈限制,因此本节中的测试增加了流控制设置
advanced.config
[
{rabbit, [
{loopback_users, []},
%% RabbitMQ internal flow control for AMQP 0.9.1
%% Default: {400, 200}
{credit_flow_default_credit, {5000, 2500}},
%% Maximum incoming-window of AMQP 1.0 session.
%% Default: 400
{max_incoming_window, 5000},
%% Maximum link-credit RabbitMQ grants to AMQP 1.0 sender.
%% Default: 128
{max_link_credit, 2000},
%% Maximum link-credit RabbitMQ AMQP 1.0 session grants to sending queue.
%% Default: 256
{max_queue_credit, 5000}
]},
{rabbitmq_management_agent, [
{disable_metrics_collector, true}
]}
].
此配置允许在 RabbitMQ 调用 fsync 之前批量处理更多 Ra 命令。 对于生产用例,我们建议使用 fsync 速度更快的企业级高性能磁盘,在这种情况下,可能不需要增加流控制设置。
RabbitMQ 流控制设置存在权衡
- 低值确保生产环境中的稳定性。
- 高值可以提高单个连接的性能,但当许多连接同时发布大型消息时,可能会导致更高的内存峰值。
RabbitMQ 使用保守的流控制默认设置,以在生产环境中优先考虑稳定性,而不是赢得性能基准测试。
RabbitMQ 4.0 中的 AMQP 1.0
# quiver //host.docker.internal//queues/my-quorum-queue \
--durable --count 1m --duration 10m --body-size 12 --credit 5000
RESULTS
Count ............................................. 1,000,000 messages
Duration ............................................... 12.0 seconds
Sender rate .......................................... 83,459 messages/s
Receiver rate ........................................ 83,396 messages/s
End-to-end rate ...................................... 83,181 messages/s
Latencies by percentile:
0% ........ 9 ms 90.00% ....... 47 ms
25% ....... 27 ms 99.00% ....... 61 ms
50% ....... 35 ms 99.90% ....... 76 ms
100% ....... 81 ms 99.99% ....... 81 ms
默认流控制设置
之前的基准测试在 ra_log_wal 模块(实现 Raft 预写日志)中调用了 1,244 次 fsync。
使用默认流控制设置的相同基准测试调用了 15,493 次 fsync,导致吞吐量显著降低
# quiver //host.docker.internal//queues/my-quorum-queue \
--durable --count 1m --duration 10m --body-size 12 --credit 5000
RESULTS
Count ............................................. 1,000,000 messages
Duration .............................................. 100.2 seconds
Sender rate ........................................... 9,986 messages/s
Receiver rate ......................................... 9,987 messages/s
End-to-end rate ....................................... 9,983 messages/s
Latencies by percentile:
0% ....... 10 ms 90.00% ....... 24 ms
25% ....... 14 ms 99.00% ....... 30 ms
50% ....... 18 ms 99.90% ....... 38 ms
100% ....... 55 ms 99.99% ....... 47 ms
每次 fsync 平均耗时 5.9 毫秒。
(15,493 - 1,244) * 5.9 ms = 84 seconds
因此,使用默认流控制设置的此基准测试在执行 fsync
时比之前使用增加的流控制设置的基准测试阻塞时间长 84 秒。 这表明企业级高性能磁盘对于从仲裁队列获得最佳结果至关重要。 对于您的生产工作负载,我们建议使用 fsync
延迟更低的磁盘,而不是调整 RabbitMQ 流控制设置。
值得注意的是,Raft WAL 日志由给定 RabbitMQ 节点上的所有仲裁队列副本共享。 这意味着当有数十个仲裁队列和数百个连接时,ra_log_wal
会自动将多个 Raft 命令(操作)批量处理到单个 fsync
调用中。 因此,当节点上的流量增加时,将单个 Ra 命令刷新到磁盘的平均成本会降低。 我们的基准测试在某种程度上人为地以尽可能快的单个连接运行。
RabbitMQ 3.13 中的 AMQP 1.0
# quiver //host.docker.internal//amq/queue/my-quorum-queue \
--durable --count 1m --duration 10m --body-size 12 --credit 5000
---------------------- Sender ----------------------- --------------------- Receiver ---------------------- --------
Time [s] Count [m] Rate [m/s] CPU [%] RSS [M] Time [s] Count [m] Rate [m/s] CPU [%] RSS [M] Lat [ms]
----------------------------------------------------- ----------------------------------------------------- --------
2.1 163,582 81,709 11 84.2 2.1 29,548 14,759 3 7.5 840
4.1 336,380 86,356 12 185.3 4.1 29,840 146 0 7.5 2,331
6.1 524,026 93,729 14 328.0 6.1 29,840 0 0 7.5 0
8.1 687,864 81,837 11 462.3 8.1 31,302 730 1 7.5 6,780
10.1 884,470 98,303 14 605.4 10.1 31,447 72 0 7.5 7,897
12.1 999,924 57,669 7 687.5 12.1 31,447 0 0 7.5 0
14.1 999,924 0 0 687.5 14.1 31,447 0 0 7.5 0
16.1 999,924 0 0 687.5 16.1 31,447 0 1 7.5 0
18.1 999,924 0 1 688.3 18.1 31,447 0 0 7.5 0
receiver timed out
20.1 999,924 0 0 688.3 20.1 31,447 0 0 7.5 0
RabbitMQ 3.13 无法处理此工作负载,基准测试失败。
默认流控制设置
使用默认流控制设置时,基准测试也失败
# quiver //host.docker.internal//amq/queue/my-quorum-queue \
--durable --count 1m --duration 10m --body-size 12 --credit 5000
---------------------- Sender ----------------------- --------------------- Receiver ---------------------- --------
Time [s] Count [m] Rate [m/s] CPU [%] RSS [M] Time [s] Count [m] Rate [m/s] CPU [%] RSS [M] Lat [ms]
----------------------------------------------------- ----------------------------------------------------- --------
2.1 130,814 65,342 9 70.0 2.1 26,915 13,437 6 7.5 1,213
4.1 196,348 32,718 5 70.2 4.1 28,084 584 0 7.5 3,093
6.1 261,882 32,734 7 70.2 6.1 30,131 1,022 1 7.5 4,952
8.1 360,184 49,126 6 70.2 8.1 32,325 1,096 0 7.5 6,637
10.1 425,718 32,734 6 70.2 10.1 34,225 949 1 7.5 8,089
12.1 491,252 32,734 5 70.2 12.1 34,225 0 0 7.5 0
14.1 589,554 49,102 7 70.2 14.1 34,225 0 0 7.5 0
16.1 655,088 32,734 5 70.2 16.1 34,225 0 0 7.5 0
18.1 720,622 32,734 6 70.2 18.1 34,225 0 0 7.5 0
receiver timed out
RabbitMQ 4.0 中的 AMQP 0.9.1
由于我们将 max_link_credit
设置为 2,000,我们允许发布者最多有 2,000 * 1.5 = 3,000 条未确认的消息。
$ java -jar target/perf-test.jar \
--predeclared --exchange amq.default \
--routing-key my-quorum-queue --queue my-quorum-queue \
--flag persistent --flag mandatory \
--pmessages 1000000 --size 12 --confirm 3000 --qos 5000 --multi-ack-every 5000
id: test-085526-136, sending rate avg: 70067 msg/s
id: test-085526-136, receiving rate avg: 70067 msg/s
id: test-085526-136, consumer latency min/median/75th/95th/99th 8803/33127/40424/53407/62883 µs
id: test-085526-136, confirm latency min/median/75th/95th/99th 8551/30323/38317/52103/63131 µs
默认流控制设置
$ java -jar target/perf-test.jar \
--predeclared --exchange amq.default \
--routing-key my-quorum-queue --queue my-quorum-queue \
--flag persistent --flag mandatory \
--pmessages 1000000 --size 12 --confirm 192 --qos 5000 --multi-ack-every 5000
id: test-084359-441, sending rate avg: 9931 msg/s
id: test-084359-441, receiving rate avg: 9931 msg/s
id: test-084359-441, consumer latency min/median/75th/95th/99th 7512/17054/26256/34249/38641 µs
id: test-084359-441, confirm latency min/median/75th/95th/99th 9432/16586/23918/32636/36858 µs
这些结果与 RabbitMQ 4.0 中 AMQP 1.0 的默认流控制设置的结果相似,因为这两个基准测试都受到我的慢速磁盘的瓶颈限制。
总结
流
本节对 流 进行基准测试。
我们声明一个名为 my-stream
的流
deps/rabbitmq_management/bin/rabbitmqadmin declare queue \
name=my-stream queue_type=stream durable=true
(我们使用默认的 RabbitMQ 流控制设置运行。)
我们希望接收者从流的开头开始消费。 Quiver 不支持将 filter
字段传递给 source,我们可以在其中指定 rabbitmq:stream-offset-spec
值 first
。 因此,对于此基准测试,更简单的方法是修补 RabbitMQ,使其默认使用流偏移规范 first
而不是 next
git diff
diff --git a/deps/rabbit/src/rabbit_stream_queue.erl b/deps/rabbit/src/rabbit_stream_queue.erl
index e36ad708eb..acd193d76f 100644
--- a/deps/rabbit/src/rabbit_stream_queue.erl
+++ b/deps/rabbit/src/rabbit_stream_queue.erl
@@ -344,7 +344,7 @@ consume(Q, Spec, #stream_client{} = QState0)
{term(), non_neg_integer()}) ->
{ok, osiris:offset_spec()} | {error, term()}.
parse_offset_arg(undefined) ->
- {ok, next};
+ {ok, first};
parse_offset_arg({_, <<"first">>}) ->
{ok, first};
parse_offset_arg({_, <<"last">>}) ->
RabbitMQ 4.0 中的 AMQP 1.0
# quiver //host.docker.internal//queues/my-stream \
--durable --count 1m --duration 10m --body-size 12 --credit 5000
---------------------- Sender ----------------------- --------------------- Receiver ---------------------- --------
Time [s] Count [m] Rate [m/s] CPU [%] RSS [M] Time [s] Count [m] Rate [m/s] CPU [%] RSS [M] Lat [ms]
----------------------------------------------------- ----------------------------------------------------- --------
2.1 278,782 139,321 25 8.0 2.1 215,185 107,539 22 7.6 224
4.1 554,492 137,717 25 8.0 4.1 434,027 109,312 24 7.6 651
6.1 825,082 135,160 25 8.0 6.1 650,236 107,997 26 7.6 1,079
8.1 999,992 87,368 17 0.0 8.1 888,973 119,249 29 7.6 1,469
- - - - - 10.1 999,993 55,455 13 0.0 1,583
RESULTS
Count ............................................. 1,000,000 messages
Duration ................................................ 8.9 seconds
Sender rate ......................................... 136,705 messages/s
Receiver rate ....................................... 112,587 messages/s
End-to-end rate ..................................... 112,196 messages/s
Latencies by percentile:
0% ........ 7 ms 90.00% ..... 1553 ms
25% ...... 519 ms 99.00% ..... 1612 ms
50% ..... 1011 ms 99.90% ..... 1615 ms
100% ..... 1616 ms 99.99% ..... 1616 ms
很容易观察到吞吐量大幅提高。
请注意,端到端延迟非常高,仅仅是因为发送者写入流的速度高于 RabbitMQ 将消息分发给消费者(在 quiver
术语中为“接收者”)的速度。
RabbitMQ 3.13 中的 AMQP 1.0
# quiver //host.docker.internal//amq/queue/my-stream \
--durable --count 1m --duration 10m --body-size 12 --credit 5000
---------------------- Sender ----------------------- --------------------- Receiver ---------------------- --------
Time [s] Count [m] Rate [m/s] CPU [%] RSS [M] Time [s] Count [m] Rate [m/s] CPU [%] RSS [M] Lat [ms]
----------------------------------------------------- ----------------------------------------------------- --------
2.1 196,350 98,077 12 70.1 2.1 4,094 2,045 0 7.7 195
4.1 392,956 98,205 13 138.5 4.1 4,094 0 0 7.7 0
6.1 524,026 65,470 10 196.5 6.1 4,094 0 0 7.7 0
8.1 655,096 65,470 11 259.4 8.1 4,094 0 0 7.7 0
10.1 786,166 65,470 10 307.5 10.1 4,094 0 0 7.7 0
receiver timed out
12.1 917,236 65,470 9 355.5 12.1 4,094 0 0 7.7 0
RabbitMQ 3.13 无法处理此工作负载,基准测试失败。
RabbitMQ 4.0 中的 AMQP 0.9.1
$ java -jar target/perf-test.jar \
--predeclared --exchange amq.default \
--routing-key my-stream --queue my-stream \
--flag persistent --flag mandatory \
--pmessages 1000000 --size 12 --confirm 192 --qos 5000 --multi-ack-every 5000
id: test-104223-225, sending rate avg: 88912 msg/s
id: test-104223-225, receiving rate avg: 88912 msg/s
id: test-104223-225, consumer latency min/median/75th/95th/99th 701/1340/1523/2500/4524 µs
id: test-104223-225, confirm latency min/median/75th/95th/99th 788/1983/2130/2437/2970 µs
由于流以 AMQP 1.0 格式存储消息,因此此工作负载需要 RabbitMQ 在 AMQP 0.9.1 和 AMQP 1.0 之间转换每条消息。 这解释了为什么与使用 AMQP 1.0 客户端相比,使用 AMQP 0.9.1 客户端时流吞吐量较低。
总结
大量连接
本节比较了连接 40,000 个客户端,每个连接具有两个 AMQP 1.0 会话 / AMQP 0.9.1 通道的内存使用情况。
设置
make run-broker \
TEST_TMPDIR="$HOME/scratch/rabbit/test" \
RABBITMQ_CONFIG_FILE="$HOME/scratch/rabbit/rabbitmq.conf" \
PLUGINS="rabbitmq_amqp1_0" \
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+P 3000000 +S 6" \
ERL_MAX_PORTS=3000000
在以下 rabbitmq.conf
中,我们使用较小的缓冲区大小,以便更好地比较协议实现的内存使用情况。
tcp_listen_options.sndbuf = 2048
tcp_listen_options.recbuf = 2048
vm_memory_high_watermark.relative = 0.95
vm_memory_high_watermark_paging_ratio = 0.95
loopback_users = none
AMQP 1.0
package main
import (
"context"
"log"
"time"
"github.com/Azure/go-amqp"
)
func main() {
for i := 0; i < 40_000; i++ {
if i%1000 == 0 {
log.Printf("opened %d connections", i)
}
conn, err := amqp.Dial(
context.TODO(),
"amqp://localhost",
&amqp.ConnOptions{SASLType: amqp.SASLTypeAnonymous()})
if err != nil {
log.Fatal("open connection:", err)
}
_, err = conn.NewSession(context.TODO(), nil)
if err != nil {
log.Fatal("begin session:", err)
}
_, err = conn.NewSession(context.TODO(), nil)
if err != nil {
log.Fatal("begin session:", err)
}
}
log.Println("opened all connections")
time.Sleep(5 * time.Hour)
}
AMQP 0.9.1
package main
import (
"log"
"time"
amqp "github.com/rabbitmq/amqp091-go"
)
func main() {
for i := 0; i < 40_000; i++ {
if i%1000 == 0 {
log.Printf("opened %d connections", i)
}
conn, err := amqp.Dial("amqp://guest:guest@localhost")
if err != nil {
log.Fatal("open connection:", err)
}
_, err = conn.Channel()
if err != nil {
log.Fatal("open channel:", err)
}
_, err = conn.Channel()
if err != nil {
log.Fatal("open channel:", err)
}
}
log.Println("opened all connections")
time.Sleep(5 * time.Hour)
}
下面的示例直接在节点上调用 erlang:memory/0
,这是一个返回每种内存类型的内存大小(以字节为单位)的函数。
rabbitmq-diagnostics
要从正在运行的节点检索相同的信息,请使用 CLI 命令 rabbitmq-diagnostics,如下所示
rabbitmq-diagnostics memory_breakdown
此命令可以使用不同的信息单位(例如 MiB、GiB)格式化数字,并支持使用 --formatter=json
的 JSON 输出
# pipes the output to `jq` for more readable formatting
rabbitmq-diagnostics memory_breakdown --formatter=json | jq
RabbitMQ 4.0 中的 AMQP 1.0
以下是运行时报告的内存占用量数字
1> erlang:memory().
[{total,5330809208},
{processes,4788022888},
{processes_used,4787945960},
{system,542786320},
{atom,999681},
{atom_used,974364},
{binary,194810368},
{code,19328950},
{ets,94161808}]
2> erlang:system_info(process_count).
360312
RabbitMQ 3.13 中的 AMQP 1.0
为了进行比较,此测试中运行时报告的内存占用量数字为
1> erlang:memory().
[{total,12066294144},
{processes,11156497904},
{processes_used,11156461208},
{system,909796240},
{atom,1089809},
{atom_used,1062780},
{binary,192784464},
{code,22068126},
{ets,318872128}]
2> erlang:system_info(process_count).
1480318
我们观察到,RabbitMQ 3.13 中 processes
的内存使用量为 11.1 GB,而 RabbitMQ 4.0 中仅为 4.8 GB(减少了约 56%)。 正如在之前的博客文章中解释的那样,RabbitMQ 3.13 中 AMQP 1.0 的实现资源密集,因为插件中的每个 AMQP 1.0 会话都包含一个 AMQP 0.9.1 客户端并维护 AMQP 0.9.1 状态。
RabbitMQ 4.0 中的 AMQP 0.9.1
1> erlang:memory().
[{total,5409763512},
{processes,4716150248},
{processes_used,4715945080},
{system,693613264},
{atom,991489},
{atom_used,962578},
{binary,187229040},
{code,19118766},
{ets,235605424}]
2> erlang:system_info(process_count).
600314
总结
结论
这篇博客文章证明,RabbitMQ 4.0 中新的原生 AMQP 1.0 实现比 RabbitMQ 3.13 中的 AMQP 1.0 性能提升数倍。
我们还观察到 AMQP 1.0 的性能可能优于 AMQP 0.9.1。 然而,提供公平的比较具有挑战性。 这篇博客文章使用了用 C 编写的 AMQP 1.0 客户端和用 Java 编写的 AMQP 0.9.1 客户端。 因此,我们不声明或承诺您将在 AMQP 1.0 工作负载中观察到更好的吞吐量。 RabbitMQ 中的 AMQP 0.9.1 实现性能良好,因为它已经稳定并优化了 15 年以上。
AMQP 1.0 可能优于 AMQP 0.9.1 的用例包括
- 发送到流或从流接收,因为流以 AMQP 1.0 格式编码消息(如本博客文章所述)。
- 利用队列局部性,使用 RabbitMQ AMQP 1.0 Java 客户端。(此功能将另行介绍。)
- 当同一连接上的一个目标队列达到其限制时,发布到其他队列或从其他队列消费(如 AMQP 1.0 流控制 博客文章中所述)。