概述
在RabbitMQ中,即使将queue,exchange, message等都设置了持久化之后,还是不能保证100%保证数据不丢失了。为了实现消息不丢失,我们需要从Consumer端和Productor端同时进行处理。本篇文章先介绍Consumer端,在AMPQ-0-9-1中有定义从消费者到RabbitMQ的消息确认机制,通过此机制可以保证消息能够从RabbitMQ正确到达消费者端。本文介绍在RabbitMQ中如何实现消费者端的消息确认机制,包括如下内容
- 1 消费者的实现机制
- 2 消费者端的代码实现
- 3 使用wireshark对消息确认的关键包进行转包,并进行分析
- 4 在使用消息确认机制的注意点
消费者端投递确认机制
在消费者端确认的方式
RabbitMQ中的两种确认方式:
1 自动确认方式:RabbitMQ成功将消息发出(即将消息成功写入TCP Socket)中立即认为本次投递已经被正确处理,不管消费者端是否成功处理本次投递
在自动确认模式下,消息发送后即被认为成功投递,又称为”fire-and-forget”
优点:这种模式下吞吐量非常高。
缺点:A. 有可能出现投递丢失的情况,不同于手动确认模式,如果消费者的TCP连接或通道在消息成功交互之前关闭,则此消息会丢失 B. 消费者端过载的问题。在手动确认模式中,可以设置一次最多同时处理多少消息,而自动模式不能设置此值。因此,消费者有可能因为消息无法及时处理,堆积中内存中,内存耗尽而奔溃 C. 此种模式只推荐在消费者可以快速且稳定处理投递的消息的场景中使用2 手动处理方式:消费者收到消息后,手动调用basic.ack/basic.nack/basic.reject后,RabbitMQ收到这些消息后,才认为本次投递成功
手动消息确认方法有:
§ basic.ack用于肯定确认
§ basic.nack用于否定确认(注意:这是AMQP 0-9-1的RabbitMQ扩展)
§ basic.reject用于否定确认,但与basic.nack相比有一个限制:一次只能拒绝单条消息
消费者端以上的3个方法都表示消息已经被正确投递,但是basic.ack表示消息已经被正确处理,但是basic.nack,basic.reject表示没有被正确处理,但是RabbitMQ中仍然需要删除这条消息。
手动的确认模式的投递效率略低于自动,但是可以弥补自动确认模式的不足。
批量手动投递确认
消息手动除了一次确认一条,也可以一次确认多条。为了减少网络流量,可以批量手动确认。在应答时,设置basic.nack的multiple 字段为true,可以同时对delivery_tag和比delivery_tag值小的投递消息进行确认
例如,假设在通道上没有确认消息的delivery_tag是5,6,7和8,当basic.nack中delivery_tag被设置为8并且multiple 被设置为true时,方法执行成功后,从5到8的所有消息将被确认。 如果multiple 设置为false,那么交货5,6和7仍然是未确认的。
投递唯一码: Delivery Tags
当消费者向RabbitMQ注册后,RabbitMQ使用basic.deliver向消费者投递消息时,消息体上会带上delivery tag,这个值会唯一标识本次投递,在同一通道上,此值是唯一的。delivery tag值有64位长度,值从1开始,每发送一次消息值递增1,最大值为92233720368547