Consumer Acknowledgements and Publisher Confirms 消費者到RabbitMQ的投遞處理確認在AMQP 0-9-1中被稱之為“acknowledgements”;而RabbitMQ給生產者的確認是協議的擴展,這種協議擴展被叫做“publisher conf ...
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