经典队列支持优先级
什么是优先级队列
RabbitMQ 支持向经典队列添加“优先级”。启用“优先级”功能的经典队列通常被称为“优先级队列”。支持 1 到 255 之间的优先级,但是,强烈建议使用 1 到 5 之间的值。重要的是要知道,较高的优先级值需要更多的 CPU 和内存资源,因为 RabbitMQ 需要在内部为每个优先级(从 1 到给定队列配置的最大值)维护一个子队列。
经典队列可以通过使用客户端提供的可选参数成为优先级队列。
通过策略将经典队列声明为优先级队列是设计上不支持的。有关原因,请参阅为什么策略定义不支持优先级队列。
使用客户端提供的可选参数
要声明优先级队列,请使用 x-max-priority
可选队列参数。此参数应为介于 1 到 255 之间的正整数,表示队列应支持的最大优先级。例如,使用 Java 客户端
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 个优先级。它没有定义如何处理没有优先级属性的消息。
默认情况下,RabbitMQ 经典队列不支持优先级。创建优先级队列时,您可以根据需要选择最大优先级。选择优先级值时,需要考虑以下因素
-
每个队列的每个优先级级别都有一些内存和磁盘成本。还有额外的 CPU 成本,尤其是在消费时,因此您可能不希望创建大量的级别。
-
消息
priority
字段定义为无符号字节,因此实际上优先级应介于 0 和 255 之间。 -
没有
priority
属性的消息被视为优先级为 0。优先级高于队列最大优先级的消息被视为以最大优先级发布。
最大优先级数和资源使用
如果优先级队列是您想要的,则先前声明的信息强烈建议使用 1 到 5 之间的值。如果您必须高于 5,则 1 到 10 之间的值就足够了(保持为个位数),因为当前使用更多优先级会通过使用更多 Erlang 进程来消耗更多 CPU 资源。运行时调度也会受到影响。
优先级队列如何与消费者一起工作
如果消费者连接到空优先级队列,随后消息发布到该队列,则消息可能不会在优先级队列中等待任何时间,消费者就会接受这些消息(所有消息都会立即被接受)。在这种情况下,优先级队列没有机会对消息进行优先级排序,不需要优先级。
但是,在大多数情况下,以前的情况不是常态,因此您应该在消费者的手动确认模式下使用 basic.qos
(prefetch)方法来限制任何时候可以交付的消息数量,并允许消息被优先处理。basic.qos
是消费者连接到队列时设置的值。它表示消费者一次可以处理多少消息。
以下示例试图更详细地解释消费者如何与优先级队列一起工作,并强调有时当优先级队列与消费者一起工作时,较高优先级的消息实际上可能需要等待较低优先级的消息先被处理。
示例
-
新的消费者连接到预取(
basic.qos
)为 10 的空经典(非优先级)队列。 -
一条消息被发布并立即发送给消费者进行处理。
-
然后快速发布另外 5 条消息并立即发送给消费者,因为消费者在声明为 qos(prefetch)的 10 条消息中只有 1 条正在传输(未确认)的消息。
-
接下来,快速发布另外 10 条消息并发送给消费者,只有 4 条消息被发送给消费者(因为原始
basic.qos
(消费者预取)值 10 现在已满),其余 6 条消息必须在队列中等待(就绪消息)。 -
消费者现在确认 5 条消息,因此上面等待的 6 条消息中的 5 条随后被发送给消费者。
现在添加优先级
-
与上面的示例一样,消费者连接到
basic.qos
(消费者预取)值为 10。 -
10 条低优先级消息被发布并立即发送给消费者(
basic.qos
(消费者预取)现在已达到其限制) -
发布了一条最高优先级消息,但现在预取已超出,因此最高优先级消息需要等待优先级较低的消息先被处理。
与其他功能的交互
一般来说,优先级队列具有标准 RabbitMQ 队列的所有功能。开发人员应该注意一些交互。
应该过期的消息仍然只从队列的头部过期。这意味着与普通队列不同,即使是每个队列的 TTL 也可能导致过期的低优先级消息被未过期的高优先级消息卡住。这些消息将永远不会被传递,但它们将出现在队列统计信息中。
设置了最大长度的队列像往常一样从队列头部删除消息以强制执行限制。这意味着高优先级消息可能会被删除,以便为低优先级消息腾出空间,这可能不是您所期望的。
为什么策略定义不支持优先级队列
为队列定义可选参数最方便的方法是使用策略。策略是配置 TTL、队列长度限制和其他可选队列参数的推荐方法。
但是,策略不能用于配置优先级,因为策略是动态的,可以在队列声明后更改。优先级队列在队列声明后永远无法更改它们支持的优先级数量,因此策略不是一个安全的选择。