rabbitmq
版本:3.8.3
amqp-client
版本:5.7.1
由于在RabbitMQ
中,发送出去的消息不能完全保证能够被消费者接收到,因此需要一种消费者消息确认机制,来为消息从RabbitMQ
节点到消费者的可靠传递提供支持。
1 消息投递唯一标识码:Delivery Tags
当消费者向RabbitMQ
注册之后,RabbitMQ
将通过basic.deliver
方法投递消息给消费者。在每一次投递的消息体上都会携带一个delivery tag
,这个值在每隔通道上是唯一的,用来标识本次投递。
delivery tag
值是单调递增的正整数,64
位长度,值从1
开始,每发送一次消息值递增1
,最大值为9223372036854775807
。
消费者在收到消息后,向RabbitMQ
发送应答消息时,带上这个delivery tag
,告诉RabbitMQ
某次消息投递已经成功接收。
2 两种确认方式
对于消费者消息确认机制,RabbitMQ
提供了两种确认方式:
- 自动确认方式
- 手动确认方式
2.1 自动确认方式
RabbitMQ
成功将消息发送出去(将消息成功写入TCP Socket
)之后立即认为本次消息投递已经成功,不管消费者端是否成功接收到消息并处理了本次消息投递。
这种消息被发送出去立刻被认为是成功投递的,又被称作fire-and-forget
。
优点:
- 吞吐量非常高。
缺点:
- 有可能出现消息丢失的情况。如果消费者的
TCP
连接或者通道在消息成功被接收之前就关闭了,那么这个消息会丢失。 - 消费者端过载问题。因为消费者端不能设置一次处理消息的阈值,可能出现消费者无法及时处理过多的消息,导致消息在内存中堆积,内存最终被耗尽。
- 应用有限。自动确认方式只推荐在消费者可以快速且稳定处理投递消息的场景中。
2.2 手动确认方式
消费者受到消息之后,手动调用basic.ack
、basic.nack
、basic.reject
方法,发送应答消息,当RabbitMQ
受到应答消息之后,才认为本次投递成功。
三个函数的含义:
basic.ack
:用于肯定确认basic.nack
:用于否定确认basic.reject
:用于否定确认
注意:
basic.reject
和basic.nack
都是用于否定确认,但是多了一个限制:一次只能拒绝单条消息。以上三个方法都表示消息已经被正确投递。但是
basic.ack
表示消息已经被正确处理,basic.nack
、basic.reject
表示消息没有被正确处理,RabbitMQ
中仍然需要删除这条消息。
手动确认方式的消息投递效率低于自动确认方式,但是能够弥补自动确认方式的不足。
例子:
// 下面的代码片段演示了在消费者端如何手动确认消息投递
boolean autoAck = false;
channel.basicConsume(queueName, autoAck, "a-consumer-tag",
new DefaultConsumer(channel) {