经典队列支持优先级
什么是优先级队列
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
(预取)方法来限制在任何时间点可以送达的 消息数量,并允许对消息进行优先级排序。basic.qos
是消费者连接到队列时设置的值。它表示消费者一次可以处理的消息数量。
以下示例试图解释消费者如何与优先级队列更详细地协作,以及强调有时当优先级队列与消费者协作时,实际上高优先级消息可能需要先等待低优先级消息处理。
示例
-
一个新的消费者连接到一个空的经典(非优先级)队列,消费者的预取(
basic.qos
)为 10。 -
一条消息被发布,并立即发送到消费者进行处理。
-
然后,很快又发布了 5 条消息,并立即发送到消费者,因为消费者只有 1 条正在进行中(未确认)消息,而 qos(预取)声明了 10 条。
-
接下来,很快又发布了 10 条消息,只有 4 条消息被发送到消费者(因为原始的
basic.qos
(消费者预取)值 10 现在已满),剩余的 6 条消息必须在队列中等待(准备好的消息)。 -
消费者现在确认了 5 条消息,因此现在等待的 6 条消息中的 5 条被发送到消费者。
现在添加优先级
-
如上例所示,消费者以
basic.qos
(消费者预取)值 10 连接。 -
发布了 10 条低优先级消息,并立即发送到消费者(
basic.qos
(消费者预取)现在已达到其限制)。 -
发布了一条最高优先级消息,但现在预取已超过,因此最高优先级消息需要等待低优先级消息先处理。
与其他功能的交互
通常,优先级队列具有标准 RabbitMQ 队列的所有功能。开发人员应注意一些交互。
应该过期的消息 仍然只从队列的头部过期。这意味着与普通队列不同,即使每个队列的 TTL 也会导致过期的低优先级消息卡在未过期的更高优先级消息后面。这些消息永远不会被传递,但它们会出现在队列统计信息中。
设置了最大长度的队列 像往常一样从队列头部删除消息以执行限制。这意味着更高优先级的消息可能会被删除以腾出空间给低优先级的消息,这可能不是您所期望的。
为什么策略定义不支持优先级队列
为队列定义可选参数的最方便方式是使用 策略。策略是配置 TTL、队列长度限制 和其他 可选队列参数 的推荐方法。
但是,策略不能用于配置优先级,因为策略是动态的,可以在声明队列后更改。优先级队列永远不能在声明队列后更改它们支持的优先级数量,因此策略不是安全的选项。