保持队列尽量短
因为如果队列中消息会占用内存,如果消息很多,那么会写入磁盘,而这样会影响队列的速度,停止处理消息知道写完磁盘
大量消息的的集群重启也需要很长时间,因为需要重建索引
重启后集群节点的消息同步也需要很长时间
启用lazy 队列来获取可预见的性能
lazy 队列的消息收到会直接写入磁盘,消息只在需要的时候才会载入内存,内存使用最小,所以性能更可预见
如果你觉得消费速度跟不上生产速度,推荐启用
如果你需要高性能,那就禁用他
用ttl或者max-length来限制 队列 大小
对于经常受到消息峰值影响的应用程序,以及吞吐量比其他任何事情更重要的应用程序,可一给队列设置max-length
这样可以通过丢弃队列头部的消息来缩短队列,使其永远不会超过最大长度设置。
队列的数量
队列在RabbitMQ中是单线程的,一个队列最多可以处理大约每秒50k个消息。
如果你有多个队列和消费者,您将在多核系统上获得更好的吞吐量。
如果你具有与基础节点上的核心一样多的队列,您将获得最佳吞吐量
RabbitMQ管理接口收集并计算集群中每个队列的指标。
如果你有成千上万的活动队列和消费者,这可能会降低服务器的速度。
如果队列太多,CPU和RAM使用率也可能会受到负面影响。
把队列分到不同的cpu核心上
队列性能仅限于一个CPU核心。
因此,如果将队列分到不同的核心,你将获得更好的性能,
如果你拥有RabbitMQ集群,分到不同的节点也可以获得更好的性能。
RabbitMQ 队列 绑定到它们首次声明所在节点。
即使你创建了RabbitMQ代理集群,路由到特定队列的所有消息也将转到该队列所在的节点。
你可以在节点之间均匀地手动分配队列,但缺点是需要记住队列所在的位置。
如果你有多个节点或具有多个核心的单个节点集群,我们建议使用两个插件来帮助你
Consistent hash exchange plugin
Consistent hash exchange plugin允许你使用exchange来对队列之间的消息进行负载平衡。
发送到exchange的消息基于消息的路由密钥一致且均匀地分布在许多队列中。
该插件创建路由密钥的哈希值,并在具有绑定到该exchange的队列之间传播消息。
手动执行此操作很快就会出现问题,而无需添加太多有关队列数量及其绑定到发布者的信息。
如果你需要最大限度地使用集群中的许多核心,则可以使用Consistent hash exchange plugin。
请注意,从所有队列中消费是很重要的。
在此处阅读有关一致哈希交换插件的更多信息。
RabbitMQ sharding
RabbitMQ sharding插件为你自动分配队列,就是一旦您将exchange定义为分片,则在每个集群节点上自动创建支持队列,并在它们之间对消息进行分片。
RabbitMQ sharding向消费者显示一个队列,但它可能是在后台运行的许多队列。
RabbitMQ Sharding插件通过向集群中的其他节点添加队列,为您提供了集中发送消息的位置,以及跨多个节点的负载平衡。
不要在临时队列上设置自己的名称
如果要在生产者和使用者之间共享队列,则为队列命名很重要,但如果你使用临时队列则不重要。
相反,你应该让服务器选择随机队列名称而不是编写自己的名称 - 或者修改RabbitMQ策略。
自动删除你不在使用的队列
客户端连接可能会失败并可能留下未使用的资源(队列),而留在后面的许多队列可能会影响性能。
有三种方法可以自动删除队列。
你可以在队列上设置TTL策略.例如,28天的TTL策略删除28天未消费的队列.
当最后一个消费者取消或者通道/连接关闭时(或者当它与服务器的TCP连接丢失时),将删除自动删除队列.
独占队列只能通过其声明连接来使用(消耗,清除,删除等).当其声明连接关闭或消失时(例如,由于底层TCP连接丢失),将删除独占队列。
限制优先级队列的使用
每个优先级级别使用Erlang VM上的内部队列,占用一些资源。在大多数用例中,只要有不超过5个优先级就足够了。
有效负载 - RabbitMQ消息大小和类型
一个常见问题是如何处理发送到RabbitMQ的消息的有效负载(消息大小)。
当然,你不应该在消息中发送非常大的文件,但是每秒消息比消息大小本身是更大的瓶颈。
发送多条小消息可能是一个不好的选择。
一个更好的想法可能是将它们捆绑成一个更大的消息,让消费者将其拆分。
但是,如果捆绑多条消息,则需要记住这可能会影响处理时间。
如果其中一个捆绑消息失败 - 您是否需要重新处理它们?
如何设置它取决于带宽和架构
连接和通道
每个连接使用大约100 KB的RAM(如果使用TLS,甚至更多)。
成千上万的连接可能是RabbitMQ服务器的沉重负担。
在最坏的情况下,服务器可能会由于内存不足而崩溃。
AMQP协议具有称为“多路复用”单个TCP连接的信道的机制。
建议每个进程只创建一个TCP连接,并在该连接中为不同的线程使用多个通道。
连接也应该是长寿的。
AMQP连接的握手过程非常复杂,需要至少7个TCP数据包(如果使用TLS则更多)。
相反,如果需要,可以更频繁地打开和关闭通道。
如果可能,甚至通道也应该是长寿的,例如
每个发布线程重用相同的通道。
不要每次发布时打开通道。
最佳实践是重用连接并在线程与通道之间复用连接。
理想情况下,每个进程只能有一个连接,然后在应用程序中为每个线程使用一个通道。
不要在线程间共享通道
你还应该确保不在线程之间共享通道,因为大多数客户端不会使通道成为线程安全的(因为它会对性能影响产生严重的负面影响)。
发布者和消费者的单独连接
为发布者和消费者分开连接以获得高吞吐量。
当发布者向服务器发送过多消息来处理时,RabbitMQ可以对TCP连接施加反压。
如果您使用相同的TCP连接,则服务器可能无法从客户端收到消息确认。
因此,消费性能也会受到影响。
并且随着消耗速度的降低,服务器将不堪重负。
大量连接和通道可能会影响RabbitMQ管理接口性能
拥有大量连接和通道的另一个影响是RabbitMQ管理接口的性能。
对于每个连接和通道性能,必须收集,分析和显示指标。
Acknowledgements and Confirms
传输中的消息可能会在连接失败的情况下丢失,并且可能需要重新传输此类消息。
Ack让服务器和客户端知道何时重新传输消息。
客户端可以在收到消息时或者在客户端完全处理消息时触发消息。
Ack具有性能影响,因此为了尽可能快的吞吐量,应禁用手动确认。
接收重要消息的消费应用程序不应该确认消息,直到它完成它需要处理的任何消息,以便不丢失未处理的消息(工作程序崩溃,异常等)
发布Confirm,同样,只是对于发布而言。
服务器收到发布者发来的消息后会回答。
发布确认也会对性能产生影响。
但是,应该记住,如果发布者需要至少一次处理消息,则需要这样做。
未确认的消息
所有未确认的消息都必须驻留在服务器的RAM中。
如果你有太多未确认的消息,则内存不足。
限制未确认消息的有效方法是限制客户端预取的消息数量。
在预取部分中阅读有关预取的更多信息。
持久消息和持久队列
如果你不能丢失任何消息,请确保您的队列被声明为“持久”,并且您的消息将以“持久”的交付模式发送。
为了避免丢失代理中的消息,您需要为代理重新启动,代理硬件故障或代理崩溃做好准备。
为确保消息和代理定义在重新启动后仍然存在,我们需要确保它们位于磁盘上。
在代理重新启动期间,非持久性和持久性的消息,exchange和队列将丢失。
持久性消息更重,因为它们必须写入磁盘。
记住,即使你正在发送transient消息,lazy队列也会对性能产生相同的影响。
为了获得高性能 - 使用transient消息。
TLS and AMQPS
你可以通过AMQPS连接到RabbitMQ,这是包含在TLS中的AMQP协议。
由于所有流量都必须加密和解密,因此TLS会对性能产生影响。
为了获得最佳性能,我们建议使用VPC peering,然后在不涉及AMQP客户端/服务器的情况下加密流量。
预取
预取值用于指定同时向消费者发送的消息数。
它用于尽可能多地从你的消费者那里获得
RabbitMQ默认预取设置为客户端提供无限缓冲区,这意味着RabbitMQ默认情况下会向可以接受它们的任何消费者发送尽可能多的消息。
发送的消息由RabbitMQ客户端库(在消费者中)缓存,直到它被处理完毕。
预取限制了客户端在确认消息之前可以接收的消息数量。
所有预先获取的消息都将从队列中删除,并且对其他消费者不可见。
预取数量太小可能会影响性能,因为RabbitMQ大部分时间都在等待获得发送更多消息的权限。
另一方面,大的预取数量可能会占用队列中的大量消息并将其传递给单个消费者,并使其他消费者处于空闲状态。
如何设置正确的预取数量
如果你有有一个或少量消费者快速处理消息,我们建议您一次预取许多消息。
尽量让您的客户尽可能忙碌。
如果您具有大约相同的处理时间,并且网络行为保持不变 - 您可以简单地在客户端上为每条消息获取总往返时间/处理时间,以获得估计的预取值。
如果你有许多消费者,并且处理时间较短,我们建议使用比单个或少量消费者更低的预取值。
由于需要等待消息到达,因此值太低会使消费者空转很多。
过高的值可能会使一个消费者忙碌,而其他消费者则处于闲置状态
如果你有许多消费者,和/或处理时间过长,我们建议您将预取计数设置为1,以便消息在所有worker中均匀分配。
请注意,如果您的客户端自动确认消息,则预取值将不起作用。
一个典型的错误是拥有无限制的预取,其中一个客户端接收所有消息并耗尽内存并崩溃,然后再次重新传递所有消息。
hipe
HiPE将以增加启动时间为代价提高服务器吞吐量。
启用HiPE时,RabbitMQ在启动时编译。
根据我们的基准测试,吞吐量增加了20-80%。
HiPE的缺点是启动时间也增加了很多,大约1-3分钟。
如果您需要高可用性,请不要启用HiPE
Routing (exchanges setup)
直接exchange是最快的。
如果你有很多 绑定,RabbitMQ必须计算发送消息的位置。
禁用不使用的插件
有些插件可能非常好用,但它们可能消耗大量的CPU或RAM用量。
因此,不建议将它们用于生产服务器。
确保禁用您未使用的插件
生产中不要将RabbitMQ Management统计数据模式设置为详细
将RabbitMQ Management统计数据模式设置为详细会对性能产生严重影响,不应在生产中使用。
使用更新的RabbitMQ客户端库
确保您使用的是最新推荐版本的客户端库。
使用最新稳定的RabbitMQ和Erlang版本
尽量使用最新的RabbitMQ和Erlang稳定版本。
请谨慎使用TTL
死信和TTL是RabbitMQ中的两个流行功能,应谨慎使用。
TTL和死信可以产生您没有预见到的性能效果。
死信
使用x-dead-letter-exchange属性声明的队列将向指定的dead-letter-exchange发送被拒绝,nacked或过期(使用TTL)的消息。
如果指定x-dead-letter-routing-key,死信时将消息的路由键将被改变。
ttl
通过声明具有x-message-ttl属性的队列,如果消息未在指定的时间内消费,则将从队列中丢弃消息。
不要频繁打开和关闭连接或通道
如果可能的话,使用长期存在的连接,并为每个任务使用通道。
AMQP连接的握手过程非常复杂,需要至少7个TCP数据包(如果使用TLS,则需要更多)。
如果需要,可以更频繁地打开和关闭通道。
如果可能的话,甚至通道也应该是长期的,例如,每个线程重用相同的通道用于发布。
每次发布时都不要打开通道。
如果你不能拥有长期连接,那么请确保正常关闭连接最佳做法是重用连接并在线程之间通过通道复用连接。
AMQP connections: 7 TCP packages
AMQP channel: 2 TCP packages
AMQP publish: 1 TCP package (more for larger messages)
AMQP close channel: 2 TCP packages
AMQP close connection: 2 TCP packages
Total 14-19 packages (+ Acks)
不要使用太多的连接或通道
尽量保持连接/通道数低。
使用单独的连接来发布和使用。
理想情况下,每个进程只能有一个连接,然后在应用程序中为每个线程使用一个通道。
重用连接
1个发布连接
1个用于消费的连接
消耗(推送),不要轮询(拉)消息
Make sure that your consumer consumes messages from the queue, instead of using basic get.
确保你的消费者从队列消费消息而不会用basic get
当在集群上创建vhost时忘记高可用策略
当你在集群上创建vhost时,也别忘了为他启用高可用策略(即使你没有高可用设置,你可能需要他用于计划的改变)
如果没有高可用策略,那么消息不会在节点间同步