ack、nack、reject 三个动作和 requeue 这个开关,到底分别让消息去哪?拒绝的消息回到队首还是队尾?确认可以换个 channel 做吗?消费者崩溃时手动确认和自动确认差在哪?一个总是 requeue 的消费者会造成什么?这篇用 rabbitmqctl 实时读 ready / unacked 数,一项项量。
初始 (ready, unacked) = (5, 0) basic_get 取 3 条(m1 m2 m3),不 ack: ['m1', 'm2', 'm3'];(ready, unacked) = (2, 3) ack m1 之后: (ready, unacked) = (2, 2) 对 m3 的 tag 做 ack(multiple=True),m2 也一并确认: (ready, unacked) = (2, 0)
消息投递给消费者后进入 unacked,ready 和 unacked 之和不变。只有 ack 才让 broker 删除它;multiple=True 一次确认到这个 tag 为止的所有消息。
取到 m1、m2,redelivered=False,False
nack(m1, requeue=True) 之后继续取 4 条的顺序: [('m1', True), ('m3', False), ('m4', False), ('m5', False)](m2 还没确认,不在里面)
channel 关闭后全部未确认的消息回到队列: (ready, unacked) = (5, 0)
再取全部(顺序和 redelivered 标志): [('m1', True), ('m2', True), ('m3', True), ('m4', True), ('m5', True)]nack / reject 加 requeue=True 时消息放回队列原来的位置(这里是队首),redelivered 标志变成 True;channel 或连接关闭时所有未确认的消息自动回队列,顺序保持不变。
reject(m1, requeue=False): (ready, unacked) = (0, 5)
nack(m4, multiple=True, requeue=False) 把 m2~m4 一起丢: (ready, unacked) = (0, 2)
nack(m6, multiple=True, requeue=True) 把 m5、m6 放回: (ready, unacked) = (2, 0)
队列里剩下: [('m5', True), ('m6', True)]reject 一次一条;nack 是 RabbitMQ 支持的扩展,能加 multiple=True 一次处理一批。requeue=False 在没有配置死信交换机时就是丢弃。
channel A 收到 tag=1 的消息;channel B 用同一个 tag 去 ack → B 被关: ["(406, 'PRECONDITION_FAILED - unknown delivery tag 1')"] channel A 仍可确认: ok;(ready, unacked) = (1, 0)
delivery tag 是每个 channel 自己的递增编号。换一个 channel 用同一个 tag 去确认会得到 406 PRECONDITION_FAILED,并且那个 channel 被关闭。
auto_ack=True:取走 3 条后连接关闭 → (ready, unacked) = (1, 0) auto_ack=False:取走 3 条后连接关闭 → (ready, unacked) = (4, 0)
auto_ack(no_ack)时消息一投出去就算确认,消费者崩溃时在途的消息就丢了;手动确认时这些消息回到队列,代价是可能被重复投递(后面有一篇讲幂等)。
1 秒内同一条消息被投递了 11967 次;第 1 次 redelivered=False,之后全部 redelivered=True 经典队列只带一个 redelivered 布尔值,没有计数——数不出已经重试了几次(quorum 队列有 x-delivery-count,见后面的文章)
总是 requeue 的消费者会让同一条消息不停地循环。经典队列只有一个 redelivered 布尔值,无法限制次数。