确认
Consumer Acknowledgements and Publisher Confirms
消费者到RabbitMQ的投递处理确认在AMQP 0-9-1中被称之为“acknowledgements”;而RabbitMQ给生产者的确认是协议的扩展,这种协议扩展被叫做“publisher confirms”。
(Consumer) Delivery Acknowledgements
当RabbitMQ投递消息给一个消费者的时候,它需要知道这个消息到底投递成功了没有。
Delivery Identifiers: Delivery Tags
当一个消费者注册的时候,消息被RabbitMQ用basic.devliver方法投递(pushed)。这个方法携带一个投递标签,这个标签在一个channel中是一个唯一标示符。投递标签的作用域就是每个channel。投递标签单调地正向递增。
Acknowledgement Modes
根据确认模式的不同,RabbitMQ收到消息成功投递的时机也不一样,有可能在发送以后就立即收到成功确认了,也有可能客户端收到以后手动确认。手动确认分为积极的和消极的两种。
积极的确认只是简单的让RabbitMQ记录一下消息已经被投递过了。用basic.reject这种消极确认也是这样的,但是二者的语义不同:积极的确认假设消息已经被成功处理了,而消消极的确认是消息没有被处理但仍然应该被删除。
在自动确认模式下,消息被发送以后就立即确认投递成功。
Acknowledging Multiple Deliveries at Once
可以批量的手动确认以减少网络开销。这是通过设置mutiple的值为true来做的。
When Consumers Fail or Lose Connection: Automatic Requeueing
手动确认的时候,那些未被确认的投递会自动重新入队。重新排队发生在投递的那个channel被关闭的时候,这包括客户端断开连接,消费者应用程序处理失败,channel级别的协议异常等等。注意,有一个周期性是时间检测客户端是否不可用。(PS:默认60秒)
由于RabbitMQ的这种行为,消费者必须准备处理重新投递的消息,并且做好幂等性处理。重新投递的消息有一个特别是boolean类型的属性,redeliver,被设为true。第一次投递的时候这个属性值是false。注意,一个消费者可以收到之前投递给另一个消费者的消息。
Client Errors: Double Acking and Unknown Tags
客户端多次确认一个消息应该使用相同的投递标签,否则可能会报错。
Publisher Confirms
用标准的AMQP 0-9-1只有一种方式可以保证消息不丢失,那就是transaction(事务)—— 使channel开启事务,发布消息,提交。在这种情况下,事务是不必要的重量级,而且吞吐量也下降了250倍。为了补救这一点,一种确认机制被引入。这种机制模仿了协议中已经存在的消费者确认机制。
为了能够确认,客户端调用confirm.select方法。一旦confirm.select方法被应用在channel上,就表明已经是确认模式了。一个事务channel不能应用确认模式,同样,一个channel是确认模式,就不能是事务的。
一旦channel开启确认模式,客户端和服务器都会开始对消息进行计数(从1开始)。服务器通过在相同的channel发送basic.ack来确认它已经处理的消息。devlivery-tag字段包含确认消息的序列号。
When will messages be confirmed?
对于非路由消息,一旦exchange证实消息不需要路由到任何队列,则服务器立即发送确认。如果消息以强制方式发布,则在basic.ack之前会先发送basic.return。
对于路由消息,当消息被所有的队列接收以后才会发送确认。对于路由到永久队列的持久化消息来说,这意味着,持久化到磁盘。对于镜像队列而言,这意味着所有的镜像都接受了这个消息。
Ack Latency for Persistent Messages
对于一个路由到永久队列的持久化消息而言,在消息被持久化到磁盘以后才会发送basic.ack。RabbitMQ每隔一段时间(或者队列空闲的时候)就会批量持久化一批消息到磁盘,通常是几百毫秒,持久化到磁盘是通过调用fsync(2)来实现的。这就意味着,在负载恒定的情况下,basic.ack会持续达到几百毫秒。为了提高吞吐量,强烈建议应用程序用异步的方式确认,或者批量的发布消息然后等待确认。
回顾&小结:
1、生产者在发送消息和消费者在接收消息的时候都可以进行确认。
2、生产者的确认叫“Publisher Confirm”,其依靠的是协议扩展;消费者的确认叫“Delivery Acknowledgements”,它是AMQP 0-9-1协议自带的
接下来就分两部分了
Delivery Acknowledgements
1、投递标签的作用域是channel,它是一个正向递增的整数,用于在channel范围内的投递消息
2、确认模式有两种:自动和手动。手动确认模式又分积极和消极两种。
3、可以批量确认
4、自动确认,顾名思义就是,消息发出去,消费者收到了就立即发送确认
5、手动确认的时候,当消费者不可用了或者连接关闭了,这种情况下未被确认的消息会重新进入队列中
Publisher Confirms
1、用标准的AMQP 0-9-1协议,要想保证消息不丢失必须用事务。然而,事务会降低吞吐量,为了弥补这一点,需要引入一种确认机制。简单的来讲,要想保证消息不丢失,协议之内必须用事务来实现,协议之外可以用一种确认机制来实现。
2、确认的时机
2.1 对于路由到普通队列的消息,当所有的队列都接受了消息,则发送确认
2.2 对于路由到永久队列的持久化消息,当消息持久化到磁盘以后,则发送确认
2.3 对于路由到镜像队列的消息,当所有的镜像都接受了消息,则发送确认
3、服务器每隔一段时间(PS:大概几百毫秒)持久化一批消息到磁盘,这就意味着,如果是同步方式确认,那么basic.ack操作将会持续几百毫秒(PS:因为需要等消息持久化到磁盘以后才能发确认)。推荐用异步的方式确认。
参考 https://www.rabbitmq.com/confirms.html