背景
RabbitMQ 自 V3.5.0 有优先级队列实现。使用客户端提供的可选参数可将任何队列转换为优先级(但与使用可选参数而不是策略的其他功能不同)。其实现支持有限数量的优先事项:255。但推荐值介于: 1 ~ 10。
使用客户端提供的可选参数
要声明优先级队列,使用 x-max-priority
参数。此参数应为介于 1 和 255 之间的正整数,指示队列应支持的最大优先级。例如
Channel ch = ...;
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-max-priority", 10);
ch.queueDeclare("my-priority-queue", true, false, false, args);
然后,发布者可以使用basic.properties
的priority
字段发布优先级消息。数字越大,优先级越高。
设计不支持使用策略的优先级声明。
行为
AMQP 0-9-1 规范
对于优先级预期如何工作有点模糊。它说,所有队列必须支持至少 2 个优先级,并且可能最多支持 10 个优先级。但它没定义如何处理没有优先级属性的消息。
与 AMQP 0-9-1 规范
不同,RabbitMQ 队列默认情况下不支持优先级。创建优先级队列时,开发人员可以选择认为合适的最大优先级。在选择值时,必须斟酌。
每个队列的优先级存在一些内存中和磁盘上的成本,还有额外的 CPU 成本,尤其是在使用时,因此可能不希望创建大量级别。
消息优先级字段定义为未签名的字节,因此实际上优先级应在 0 和 255 之间。
没有priority
属性的消息其优先级被视为 0。优先级高于队列最大值的消息将被视为以最大优先级发布。
优先级和资源使用的最大数量
如果需要优先级队列,推荐1 ~ 10。当前使用更多优先级将消耗更多的 CPU 资源,通过使用更多的 Erlang 进程。运行时调度也会受到影响。
与消费者的交互
了解使用者使用优先级队列时的工作方式非常重要。默认情况下,消费者在确认任何消息之前可能会收到大量消息,但仅受网络背压限制。
因此,如果这种饥饿的使用者连接到一个空队列,然后将消息发布到该队列中,则消息可能不会花费任何时间在队列中等待。在这种情况下,优先级队列将没有机会优先处理它们。
在大多数情况下,您需要在使用者的手动确认模式下使用 basic.qos 方法,以限制随时可以发送的消息数,从而允许对邮件进行优先级排序。
与其他功能的协作避坑
通常,优先级队列具有标准RabbitMQ队列的所有功能:支持持久性,分页,镜像等。开发人员应该注意几个交互。
应该过期的消息仍然只会从队列的开头过期。这意味着与普通队列不同,即使每个队列TTL也会导致过期的低优先级消息滞留在未过期的高优先级消息之后。这些消息将永远不会传递,但是将出现在队列统计信息中。
设置了最大长度的队列将照常从队列的开头丢弃消息以强制执行该限制。这意味着较高优先级的消息可能会被丢弃,以取代较低优先级的消息,这可能不是所期望的。
为什么不支持策略定义
为队列定义可选参数的最方便方法是通过策略。建议使用策略配置TTL,队列长度限制和其他可选队列参数。
但是,策略不能用于配置优先级,因为策略是动态的,可以在声明队列后进行更改。优先级队列在声明队列后永远无法更改其支持的优先级数量,因此使用策略不是一个安全的选择。
参考
- https://www.rabbitmq.com/priority.html
- https://www.rabbitmq.com/queues.html#optional-arguments