RabbitMQ 4.1 性能改进
RabbitMQ 4.1 即将发布,与往常一样,除了新功能外,我们还进行了一些内部更改,这些更改应提供更好的性能。
至少有 4 项值得注意的更改
- 仲裁队列更低且更稳定的内存使用率
- 消费长仲裁队列时性能大幅提升
- WebSocket 连接的性能更好
- TCP 连接的内存使用率更低和/或吞吐量更高
仲裁队列:更低的内存使用率
在许多情况下,RabbitMQ 4.1 中的仲裁队列应使用更少的内存。您可能知道,过去仲裁队列具有锯齿状的内存使用模式。它们会为最近的 Raft 操作填充内存缓冲区(缓存),一旦缓冲区满了,就会清空然后再填充。
在 RabbitMQ 4.1 中,这些条目删除得更加频繁,从而在许多条件下实现更稳定的内存使用率。以下是集群最初运行 4.0,然后升级到 4.1 的内存使用情况

工作负载的确切细节不是非常重要,因为这种差异对于许多不同的工作负载都应该是可见的,但为了完整性,这里列出它们
- 有 10 个仲裁队列
- 所有消息的大小均为 1kb
- 每个队列每秒从单个发布者接收 500 条消息(因此所有队列总共每秒 5000 条消息)
- 每个队列都有一个消费者(绝大多数消息在发布后 10 毫秒内被消费)
- 队列实际上是空的,因为所有消息都立即被消费了
值得记住的是,在所有条件下都不能期望如此低且稳定的内存使用率。例如,仲裁队列将队列中消息的元数据保存在内存中,因此,如果队列中有大量消息(消息未立即消费),则此元数据将消耗内存。还有其他因素和内存结构会根据工作负载而增长。尽管如此,在许多常见情况下,内存使用率应该更低且更少突兀。
仲裁队列:卸载磁盘读取
让我们考虑一个完全不同的工作负载 - 消息在队列中累积,然后消费者需要赶上进度以清空队列的工作负载。从历史上看,仲裁队列可能会被大量涌入的消费者压垮,特别是当消息很大且消费者请求大量消息时(要么他们有很大的预取缓冲区,要么有很多消费者,或者两者都有)。在这种情况下,队列可能会因为从磁盘读取旧消息(以将它们分派给消费者)而变得非常繁忙,以至于发布者不得不等待很长时间才能让他们的消息被队列接受。
在 RabbitMQ 4.1 中,此类磁盘读取被卸载到 AMQP 0.9.1 通道或 AMQP 1.0 会话进程(基于使用的协议)。队列需要做的工作少得多,并且可以继续为发布者提供服务。
让我们看一下 4.0 和 4.1 之间发布和消费速率的差异

以下是此图中发生的情况
- 我们有两个集群在运行,4.0(绿线)和 4.1(黄线)
- 两个集群都接收约每秒 6000 条消息,每条消息 20kb
- 最初,没有消费者;因此,消费率为零
- 一段时间后,消费者开始并尝试消费消息
- 在每个环境中,现在都有 10 个消费者,每个消费者都有 300 条消息的预取缓冲区
- 4.0 环境不堪重负 - 发布速率降至每秒仅约 100 条消息
- 与此同时,4.1 环境继续为发布者提供服务,没有明显的性能影响
- 此外,4.1 环境中的消费率几乎翻了一番
- 一旦消费了消息积压,两个环境都可以处理每秒约 7000 条消息的进出
不仅发布者没有受到限制,而且消费者也能够更快地消费消息!
WebSocket 连接的更好性能
为了服务 HTTP 连接,RabbitMQ 使用了一个流行的 Erlang HTTP 服务器,名为 Cowboy(由 Loïc Hoguin 在他加入 RabbitMQ 团队之前很久开发)。RabbitMQ 4.1 将 Cowboy 升级到 2.13.0 版本,该版本显著提高了 WebSocket 性能,适用于所有依赖 Cowboy 的系统,包括 RabbitMQ。因此,升级到 RabbitMQ 4.1 对于任何使用 WebSocket 上的 AMQP、MQTT 或 STOMP 的人来说都应该特别有利。
TCP 缓冲区自动调整
Cowboy 2.13.0 发布博文中描述的一个关键改进是动态 TCP 缓冲区自动调整。对于 WebSocket 连接,Cowboy 中的这些改进会自动使 RabbitMQ 用户受益,因为 Cowboy 处理与 RabbitMQ 的 HTTP 连接。
在 RabbitMQ 4.1 中,我们将相同的 TCP 缓冲区自动调整机制 incorporated 到 AMQP 监听器中,这是一个完全独立的代码路径,不使用 Cowboy(因为 Cowboy 是一个 HTTP 服务器)。 благодаря 这项工作,RabbitMQ 应该为 AMQP 0.9.1 和 1.0 连接使用更少的内存,而不会有明显的性能损失。节省的内存量取决于您当前的缓冲区大小和连接数,但在我们的测试中,它在一个拥有数千个连接的系统中节省了几百兆字节的内存。
值得指出的是,本段讨论的缓冲区是用户空间缓冲区,不应与 recbuf
/ sndbuf
缓冲区混淆,后者是内核缓冲区。这些缓冲区可以静态配置,如果未配置,则由 Linux 内核自动调整(在其他操作系统上的行为可能有所不同)。
tcp_listen_options.buffer
的值(以前用于控制现在自动调整的缓冲区的大小)将被忽略。