RabbitMQ 消息确认机制

生产者先把消息发到 exchange (很多个), exchange 决定把消息分发到哪些 queue (很多个), 再从 queue 发到消费者.

确认机制分为两部分, exchange 确认收到 publisher 的消息, consumer 确认收到 queue 的消息. 来自官方文档 Consumer Acknowledgements and Publisher Confirms — RabbitMQ

(Consumer) Delivery Acknowledgements

消费者向 RabbitMQ 发 ack 有两种时机

  • when a consumer is registered using the basic.consume method
  • when a message is fetched on demand with the basic.get method

Delivery Identifiers: Delivery Tags

The below explains how deliveries are identified (and acknowledgements indicate their respective deliveries). When a consumer is registered, messages will be delivered by RabbitMQ using the basic.deliver method. The method carries a delivery tag (单调递增的整数, 为 ack 的一个参数), which uniquely identifies the delivery on a channel. Delivery tags are therefore scoped per channel. 所以要在同一 channel 操作.

Consumer Acknowledgement Modes and Data Safety Considerations

Depending on the acknowledgement mode used, RabbitMQ can consider a message to be successfully delivered either

  • 自动模式: immediately after it is sent out (written to a TCP socket). 不安全; 而且不限制 prefetch 数量, 可能导致消费者过载. Automatic acknowledgement mode is therefore only recommended for consumers that can process deliveries efficiently and at a steady rate.
  • 手动模式: when an explicit (“manual”) client acknowledgement is received
    • basic.ack is used for positive ack, 告诉 MQ 消息已送达, 可以删除.
    • basic.nack is used for negative ack, 消息没送达, 但也应该删除. 还有个历史遗留的 basic.reject, 不用管.

Negative Acknowledgement and Requeuing of Deliveries

有时当前消费者没法立刻处理消息, 可以用 basic.nack

  • requeue 这个消息让别人处理
  • 或者丢弃消息 (如果配置了 Dead Letter Exchange 会转发到那里)
When a message is requeued, it will be placed to its original position in its queue, if possible. If not, the message will be requeued to a position closer to queue head.

手动模式下, 任何没有 ack 的消息在 channel 关闭后会自动 requeue. 因此消费者需要处理重新分发或者保证操作幂等性.

Channel 关闭的场景包括 TCP connection loss by clients, consumer application failures, and channel-level protocol exceptions.

Consumer Acknowledgement Modes, Prefetch and Throughput

Ack 模式和 prefetch count 影响消费者的吞吐量. 自动 ack + 提高 prefetch count 可以提高吞吐量, 但是导致消费者占用更多 RAM.

The “prefetch count” value in the basic.qos (qos stands for quality of service) method defines the max number of unacknowledged deliveries that are permitted on a channel.

Values in the 100 through 300 range usually offer optimal throughput and do not run significant risk of overwhelming consumers. Higher values often run into the law of diminishing returns.

Publisher Confirms

在标准的 AMQP 0-9-1 下, 确保消息可靠的唯一方式是用事务 (事务模式), 但这会让吞吐量锐减为 1/250. 因此引入确认机制 (确认模式), 和消费者确认机制类似.

To enable confirms, a client sends the `confirm.select` method. Depending on whether `no-wait` was set or not, the broker may respond with a `confirm.select-ok`. Once a channel is in confirm mode, both the broker and the client count messages (counting starts at 1 on the first `confirm.select`). The broker then confirms messages as it handles them by sending a `basic.ack` on the same channel. The `delivery-tag` field contains the sequence number of the confirmed message.

Negative Acknowledgments for Publishes

basic.nack will only be delivered if an internal error occurs. After a channel is put into confirm mode, all subsequently published messages will be confirmed or nack’d once. No guarantees are made as to how soon a message is confirmed. No message will be both confirmed and nack’d.

剩下的从 confirms.html#when-publishes-are-confirmed 开始看.

备考杂项