负面确认
概述
AMQP 0-9-1 中的消费者可以选择使用手动确认来处理交付的消息。
AMQP 0-9-1 规范定义了 basic.reject 方法,该方法允许客户端拒绝单条已交付的消息,并指示代理将其丢弃或重新入队。遗憾的是,basic.reject 不支持批量拒绝消息。
为了解决这个问题,RabbitMQ 支持 basic.nack 方法,它提供了 basic.reject 的所有功能,同时还支持批量处理消息。
basic.reject 与 basic.nack
虽然这两种方法都可以将消息放入死信队列/丢弃或重新入队,但它们在“毒丸”消息处理(poison message handling)方面存在语义上的差异。
basic.reject表示消息处理失败。使用此方法会增加消息的 delivery-count 消息头。basic.nack表示消费者未处理该消息,但不将其计为失败。使用此方法不会增加 delivery-count 消息头。
这种区别对于仲裁队列(quorum queues)非常重要,因为仲裁队列支持“毒丸”消息处理:当消息的 delivery-count 超过队列配置的 delivery-limit(默认值为 20)时,该消息将被发送到死信队列或被丢弃。
用法
要批量拒绝消息,客户端需将 basic.nack 方法的 multiple 标志设置为 true。此时,代理将拒绝所有直到并包括 basic.nack 方法中 delivery_tag 字段所指定消息在内的所有未确认的已交付消息。在这方面,basic.nack 补充了 basic.ack 的批量确认语义。
否定确认适用于长时间运行的消费者以及基于轮询的消费者(使用 basic.get)。
当消息被重新入队时,如果可能,它将被放回队列中的原始位置。如果无法做到(例如由于多个消费者共享队列时,存在其他消费者的并发交付和确认操作),消息将被重新入队到更靠近队列头部的位置。
示例
Java
此 Java 客户端示例展示了如何拒绝通过轮询(basic.get)消费的单条消息,并要求代理将其重新入队
GetResponse gr = channel.basicGet("some.queue", false);
channel.basicNack(gr.getEnvelope().getDeliveryTag(), false, true);
此示例展示了通过单次调用代理来拒绝两条消息(basicNack 的第二个参数是 multiple 标志)
GetResponse gr1 = channel.basicGet("some.queue", false);
GetResponse gr2 = channel.basicGet("some.queue", false);
channel.basicNack(gr2.getEnvelope().getDeliveryTag(), true, true);