RabbitMQ 性能测量,第 1 部分
今天我想谈谈 RabbitMQ 性能的某些方面。影响 RabbitMQ 服务器整体性能水平的变量非常多,今天我们将尝试调整其中一些变量,看看我们能看到什么。
这篇文章的目的不是试图说服您 RabbitMQ 是世界上最快的消息代理——它通常不是(尽管我们认为我们仍然相当不错)——而是让您了解在不同情况下您可以期望获得什么样的性能。
所有图表和统计数据都是在配备双路 Xeon E5530 和 40GB 内存的 PowerEdge R610 上测量的。主要是因为它当时是我们手头最快的机器。一个主要的不足之处是我们让客户端和服务器在同一台机器上运行——仅仅是因为我们可用的硬件有限。我们使用了 RabbitMQ 2.8.1(在大多数情况下)和启用了 HiPE 编译的 Erlang R15B。
顺便说一句,生成所有这些统计数据的代码都可以在 rabbitmq-java-client 的 bug24527 分支中找到(尽管目前还很粗糙)。最终它将被合并到 default 分支,并且也变得更容易使用。我们希望如此。
RabbitMQ 2.8.0+ 中的流控制
但首先,我需要介绍 RabbitMQ 2.8.0+ 中的一个新功能——内部流控制。RabbitMQ 内部由许多 Erlang 进程组成,这些进程相互传递消息。每个进程都有一个邮箱,其中包含它已接收但尚未处理的消息。这些邮箱可能会增长到无限大小。
这意味着,除非从网络套接字接收数据的第一个进程是链中最慢的进程(事实并非如此),否则当您有一个负载很重的 RabbitMQ 服务器时,消息可能会永远积压在进程邮箱中。或者更确切地说,直到我们耗尽内存。或者更确切地说,直到内存警报响起。届时,服务器将停止接受新消息,同时进行自我整理。
问题是,这可能需要一些时间。下图(此帖中唯一一个针对 RabbitMQ 2.7.1 制作的图表)显示了一个简单的过程,该过程尽可能快地将小消息发布到代理中,并尽可能快地使用它们,关闭了确认、确认、持久性等所有功能。我们绘制了发送速率、接收速率和延迟(发送消息到接收消息所用的时间)随时间的变化。请注意,延迟是对数刻度。
简单 1 -> 1 autoack (2.7.1)
哎呀!这相当令人不快。有几件事应该很明显
- 发送速率和接收速率波动很大。
- 发送速率降至零两分钟(这是第一次内存警报响起)。事实上,内存警报在最后又响起了一次。
- 延迟稳步增加(看看刻度——我们显示的是微秒,但我们也可以很容易地以分钟为单位测量它)。
(延迟在 440 秒左右的小幅下降是由于 200 秒之前发布的所有消息都被消耗掉了,以及之后的长间隔。)
当然,这只是在将服务器压力测试到极限时才会出现的行为。但我们正在进行基准测试——我们想要这样做。而且无论如何,服务器在生产环境中也会受到压力。
现在让我们看看针对 RabbitMQ 2.8.1 服务器进行的相同实验
简单 1 -> 1 autoack (2.8.1)
这看起来是平静得多的体验!发送速率、接收速率和延迟都接近恒定。原因是内部流控制。延迟约为 400 毫秒(与负载较轻的服务器相比仍然相当高,原因我稍后会讨论)。
这些图表没有显示内存消耗,但情况相同——在这种情况下,2.7.1 会消耗大量内存并在内存警报阈值附近反弹,而 2.8.1 将使用相当恒定、相当低的内存量。
链中的每个进程都会向可以向其发送消息的进程发出信用。进程在发送消息时会消耗信用,并在接收消息时发出更多信用。当进程耗尽信用时,它将停止向上游进程发出更多信用。最终,我们到达从网络套接字读取字节的进程。当该进程耗尽信用时,它会停止读取,直到获得更多信用。这与 2.7.1 代理的内存警报响起时相同,只不过它每秒发生多次而不是几分钟,并且我们对内存的使用控制得更多。
那么 400 毫秒的延迟从何而来?好吧,管道的每个阶段仍然有消息排队,因此消息从开始到结束需要一段时间。这解释了部分延迟。然而,大部分延迟来自整个服务器前面的一个看不见的“邮箱”
- 操作系统提供的 TCP 缓冲区。在 Linux 上,操作系统最多允许 8MB 的消息在 TCP 堆栈中备份。8MB 听起来当然不多,但我们处理的是微小的消息(并且每个消息都需要进行路由决策、权限检查等)。
但重要的是要记住,我们倾向于在达到我们能力极限时看到最糟糕的延迟。所以这是本周的最后一个图表
1 -> 1 尝试发送速率与延迟
请注意,水平轴不再是时间。我们现在展示的是像上面这样的多次运行的结果,每个点代表一次运行。
在上面的图表中,我们尽可能快地运行,但在这里我们将速率限制在不同的点,最高可达我们可以达到的最大速率。因此,黄线显示了尝试速率与实现速率——看到它大部分是纯粹的 1:1 线性关系(当我们有剩余容量时,如果我们尝试更快地发布,我们将成功),然后在我们达到我们可以做到的极限时停止增长。
但是看看延迟!在低发布速率下,我们的延迟远小于一毫秒。但随着服务器变得越来越繁忙,延迟会逐渐上升。当我们停止能够更快地发布时,我们遇到了延迟墙——TCP 缓冲区开始填满,很快消息就需要数百毫秒才能通过它们。
因此,希望我们已经展示了 RabbitMQ 2.8.1 在重负载下比以前的版本提供更可靠的性能,并展示了当您的消息代理过载时延迟如何飙升。请在下次收听,了解使用消息传递的不同方式如何影响性能!