阿Han
阿Han

文字是留下記錄的一種媒介,將知識吸收轉化後輸出成文字進行保存。 ☕️ https://liker.land/willhanchen/civic

RabbitMQ — 如何保證消息可靠性?

訊息傳遞的過程中有三種可能遺失的情境:

Producer端送到RabbitMQ時丟失:

  1. 外界環境問題導致: 發生網路丟包、網路故障等造成訊息丟失。
  2. 程式碼層面、配置層面導致訊息丟失。

RabbitMQ儲存的訊息丟失:

  1. 訊息沒有持久化。
  2. 磁碟意外損壞導致訊息同步失敗。

RabbitMQ送到Consumer時丟失:

消費者接收訊息後還沒來得及處理就當機。

處理方式:

為了確保訊息正確的送達RabbitMQ及Consumer正確的收到訊息,RabbitMQ為我們提供了兩種方式:

  1. 透過AMQP Transaction機制實現。
  2. 將Channel設定為confirm模式。

AMQP Transaction機制

主要有三個方法分別為:

  • txSelect(): 將當前的channel設定為transaction模式。
  • txCommit(): 提交事務。
  • txRollback(): 回滾事務。

可以看到下面流程中多了四個步驟,如此一來當資料量大的時候處理起來會比較沒有效率,因此一般應用狀況下很少採用Transaction機制。

try {    channel.txSelect();    channel.basicPublish(...);    channel.txCommit();} catch (e) {    channel.txRollback();}

Confirm模式 — 生產端

首先我們一樣將通道設定為Confirm模式,Confirm模式與AMQP Transaction機制只能選一個使用。

channel.confirmSelect();

Confirm模式又分為以下三種方式:

1. 普通Confirm模式: 每發送一條消息就等待服務端回應一次。

這種方式較沒效率,每次丟一個訊息就得等待通知。
try {  // 發送一條訊息  channel.basicPublish(...);  // 等待確認訊號  if(channel.waitForConfirms()){     // 發送成功  } else {     // 重送或其他處置  }} catch(...) {    ...}

2. 批次Confirm模式: 發送一批消息後再等待服務端回應。

這種方式可以發送一批後再等待通知,乍看之下蠻有效率的,但如果訊息常常丟失,那麼我們也得批次重傳。
try {  // 發送多條訊息  for (i = 0; i < batchSize; i++) {     channel.basicPublish(...);  }  // 等待確認訊號  if(channel.waitForConfirms()){     // 發送成功  } else {     // 重送或其他處置  }} catch(...) {    ...}

3. 異步Confirm模式: 以Listener方式等待服務端回應。

這邊以Listener的方式來獲取通知訊息,RabbitMQ會發送以下兩種通知:

  • Ack: 成功將訊息送到Queue。
  • Nack: Queue達到上限、MQ異常、磁碟寫滿…等造成未正確將訊息送到Queue。

這邊會有一種狀況是Ack、Nack都沒收到,如網路瞬斷…等,這時候就得搭配其他機制去進行重送。

try {  // 開啟Confirm模式  channel.confirmSelect();  channel.addConfirmListener(new ConfirmListener() {  public void handleAck(long deliveryTag, boolean multiple) throws IOException {         // 成功將訊息送到Queue。  }  public void handleNack(long deliveryTag, boolean multiple) throws IOException {	       // Queue達到上限、MQ異常、磁碟寫滿...等。  }  });} catch(...) {    ...}

以上都不保證100%投送到MQ,只是盡量的保證能夠送達而已,如果對於投送訊息的部份有強烈需求則可以考慮搭配Redis…等DB來維持是否送達的狀態,但勢必會捨棄一些效能。

Confirm模式 — 消費端

消費端的部份就相對單純,處理完訊息後發送ack確認訊號給RabbitMQ即可,RabbitMQ收到後就認為已經消費完成會將該訊息刪除。

延伸閱讀:

Message Queue之基本概念

關於Message Queue的幾個常見傳輸協定

RabbitMQ — 消費者分發制度


CC BY-NC-ND 2.0 版权声明

喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。

加载中…
加载中…

发布评论