RabbitMQ 訊息確認機制 以及 原理解析
- 一、場景
- 當訊息的投送方把訊息投遞出去,卻不知道訊息是否投遞成功了。如果訊息投送方不管的話,勢必對系統的造成可靠性的影響。
- 可是如果要保證系統的可靠性,訊息投靠方,如何知道訊息是否投放成功了呢?
- 這個就需要訊息的確認機制,我們來看下rabbitMQ的訊息去人機制是如何做的。
- 二、原理:上圖
- 三、原理解析
- 訊息的確認分兩部分:rabbitMQ確認生產者投遞的訊息 和 消費者確認 rabbitMQ伺服器的訊息
- 首先說RabbitMQ對生產者的確認,總共分為兩種模式分別為 同步模式 與
非同步模式 。
(1) 同步模式分為 單條訊息確認 與 批量確認 。
① 單條訊息確認: channel.waitForConfirms() 普通傳送方確認模式; 訊息到達 交換器, 就會返回 true 。
② 批量訊息確認: channel.waitForConfirmsOrDie() 批量確認模式;使用同步方式等所有的訊息傳送之後才會執行後面程式碼,只要有一個訊息未 到達 交換器就會丟擲 IOException 異常。
(2) 非同步模式為生產者 非同步監聽訊息確認 。
非同步監聽訊息確認: channel.addConfirmListener() 非同步監聽傳送方確認模式; 如何使用,參見程式碼 no-spring 模組 包 cn.enjoyedu. producerconfirm 中 。
3. 其次說下消費者對RabbitMQ 訊息確認。總共分為兩種方式 分別為 手動確認 和 自動確認。
消費者收到的每一條訊息都必須進行確認。訊息確認後, RabbitMQ 才會從佇列刪除這條訊息, RabbitMQ 不會為未確認的訊息設定超時時間,它判斷此訊息是否需要重新投遞給消費者的唯一依據是消費該消的消費者連線是否已經斷開。
這麼設計的原因是RabbitMQ允許消費者消費一條訊息的時間可以很久很久。
(1)自動確認:
消費者在宣告佇列時,可以指定 autoAck 引數,當 autoAck=true 時,一旦消費者接收到了訊息,就視為自動確認了訊息。如果消費者在處理訊息的過程中,出了錯,就沒有什麼辦法重新處理這條訊息,所以我們很多時候,
需要在訊息處理成功後,再確認訊息,這就需要手動確認。
(2) 手動確認:
①當 autoAck=false 時, RabbitMQ 會等待消費者顯式發回 ack 訊號後才從記憶體 ( 和磁碟,如果是持久化訊息的話 ) 中移去訊息。否則, RabbitMQ 會在佇列中訊息被消費後立即刪除它。
②採用訊息確認機制後,只要令 autoAck=false ,消費者就有足夠的時間處理訊息 ( 任務 ) ,不用擔心處理訊息過程中消費者程序掛掉後訊息丟失的問題,因為 RabbitMQ 會一直持有訊息直到消費者顯式呼叫 basicAck 為止。
③當 autoAck=false 時,對於 RabbitMQ 伺服器端而言,佇列中的訊息分成了兩部分:一部分是等待投遞給消費者的訊息;一部分是已經投遞給消費者,但是還沒有收到消費者 ack 訊號的訊息。如果伺服器端一直沒有收到消費
者的 ack 訊號,並且消費此訊息的消費者已經斷開連線,則伺服器端會安排該訊息重新進入佇列,等待投遞給下一個消費者(也可能還是原來的那個消費者)。
④通過執行程式,啟動兩個消費者 A 、 B ,都可以收到訊息,但是其中有一個消費者 A 不會對訊息進行確認,當把這個消費者 A 關閉後,消費者 B 又會收到本來發送給消費者 A 的訊息。所以我們一般使用手動確認的方法是,將訊息的處理放在 try/catch 語句塊中,成功處理了,就給 RabbitMQ 一個確認應答,如果處理異常了,就在 catch 中,進行訊息的拒絕
- 如果有什麼不足歡迎討論!