01 爲什麼要消息確認
在一些場合,如轉賬、付費時每一條消息都必須保證成功的被處理。AMQP是金融級的消息隊列協議,有很高的可靠性,這裏介紹在使用RabbitMQ時怎麼保證消息被成功處理的。
消息確認可以分爲兩種:一種是生產者發送消息到Broke時,Broker給生產者發送確認回執,用於告訴生產者消息已被成功發送到Broker;
一種是消費者接收到Broker發送的消息時,消費者給Broker發送確認回執,用於通知消息已成功被消費者接收。下邊分別介紹生產者端和消費者端的消息確認方法
02 生產者端消息確認
生產者端的消息確認:當生產者將消息發送給Broker,Broker接收到消息給生產者發送確認回執。生產者端的消息確認有兩種方式:tx機制和Confirm模式。
1. Tx機制模式
tx機制可以叫事務機制,RabbitMQ中有三個與tx機制的方法:txSelect,txcommit和txRollback。channe.txSelect用於將當前channel設置成一個transaction模式,channe.txCommit提交事務,channel.txRollback回滾事務。
使用tx機制,我們首先要通過txSelect方法開啓事務,然後發佈消息給broker服務器,如果txCommit提交成功了,則說明消息成功被broker接受了;
如果txCommit執行之前broker異常崩潰或者由於其他原因拋出異常,這個時候我們可以捕獲異常,通過txRollback回滾事務。
準備工作:如圖
看一個tx機制的簡單實現:
執行結果如下:
2. Confirm模式
C#的RabbitMQ API中,有三個與Confirm相關的方法:ConfirmSelect,WaitForCnofirms和WaitForCnofirmOrDie。channel.ConfirmSelect表示開啓Confirm模式。channel.WaitForConfirms等待所有消息確認,如果所有的消息都被服務端成功接收返回true,只要有一條沒有被成功接收就返回false。
channel.WaitForConfirmsOrDie和WaitForConfirms作用類型,也是等待所有消息確認,區別在於該方法沒有返回值(Void),如果有任意一條消息沒有被成功接收,該方法會立即拋出一個OperationInterrupedException類型異常.
下面看一個簡單的案例:
執行結果如下:
03 消費者端消息確認
生產者端的消息確認:從Broke發送到消費者時,RabbitMQ提供了兩種消息確認的方式:自動確認和顯示確認。
1、自動確認:
當RabbbitMQ將消息發送給消費者後,消費者端接收到消息後,不等待消息處理結束,立即自動回送一個確認回執。自動確認的用法十分簡單,設置消費方法的參數autoAck爲true即可;如下內容:channel.BasicConsume(queue:"myqueue",autoAck: true, consumer: consumer);
注意:Broker會在接收到確認回執時刪除消息,如果消費者接收到消息並返回了確認回執,然後這個消費者在處理消息時掛了,那麼這條消息就再也找不回來了。
2、顯示確認
我們知道自動確認可能會出現消息丟失的問題,我們不免會想到:Broker收到回執後才刪除消息,如果可以讓消費者在接收消息時不立即返回確認回執,等到消息處理完成後(或者完成一部分的邏輯)再返回確認回執,這樣就保證消費端不會丟失消息了!這正是顯式確認的思路。使用顯示確認也比較簡單,首先將Resume方法的參數autoAck設置爲false,在消費端使用代碼 channel.BasicAck/BasicReject等方法 來確認和拒絕消息。
生產者代碼:
消費者代碼如下:
介紹一下代碼中標紅的兩個方法:
channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); 方法用於確認消息,deliveryTag參數是分發的標記,multiple表示是否確認多條。
channel.BasicReject(deliveryTag: ea.DeliveryTag, requeue: false); 方法用於拒絕消息,deliveryTag也是指分發的標記,requeue表示消息被拒絕後是否重新放回queue中,true表示放回queue中,false表示直接丟棄
嘗試運行:如下圖
一些意外的情況:使用顯式確認時,如果消費者處理完消息不發送確認回執,那麼消息不會被刪除,消息的狀態一直是Unacked,這條消息也不會再發送給其他消費者。如果一個消費者在處理消息時尚未發送確認回執的情況下掛掉了,那麼消息會被重新放入隊列(狀態從Unacked變成Ready),有其他消費者存時,消息會發送給其他消費者。