RabbitMQ 訊息的可靠投遞

chy_18883701161發表於2020-10-28


 

概述

可靠性投遞

  • 保障訊息能夠成功發出
  • 保 障rabbitmq(broker)能夠成功接收。接收指的是:broker接收到生產者傳送的訊息,放到exchange中,分發給對應的queue,交付給對應的消費者。
  • 傳送端要收到broker的確認應答,確認broker已收到|處理訊息
  • 完善的訊息補償機制。傳送端沒收到broker的確認應答,不知道訊息是否成功投遞成功,這時候就需要做一些補償處理,比如重新投遞。

rabbitmq的server又叫做broker,接收客戶端的連線,實現AMQP實體服務,包含exchange、queue等多種元件。

說白了,broker就是rabbitmq伺服器。
 

實現訊息可靠性投遞的、常見的2種解決方案

  • 訊息狀態入庫,對訊息狀態進行打標
  • 延時再次投遞訊息,回撥確認

 

方案一 訊息狀態打標

1、生產者將訊息入庫、訊息狀態入庫

比如使用者下單,產生一個Order物件,把這個Order物件資料持久化到資料庫中。

單獨用一張表來儲存訊息狀態:
用外來鍵關聯訊息(比如關聯訂單表的id),
設定一個status列記錄訊息投遞狀態,預設值為0,表示訊息未投遞到broker;
設定一個時間列,記錄訊息投遞時間;
設定一個重試次數列,記錄重新投遞的次數,預設值為0。
 

2、生產者傳送訊息到broker

把Order物件傳送到broker,因為訊息都要轉換為byte[ ]傳送,什麼型別都可以。
 

3、生產者接收到broker的確認應答,將資料庫中該條訊息的狀態修改為1,表示成功投遞
 

4、分散式系統的定時任務

如果訊息投遞一段時間後,未收到broker的確認應答,怎麼補償處理?

使用定時任務來做:

生產者每隔一段時間,比如5min,啟動一條執行緒來查詢資料庫中重試次數達到指定值(比如3)、且投遞時間已超過指定值(比如5min)的訊息,將其狀態修改為2,表示重試指定次數後仍未能成功投遞;

再查詢狀態為0、且傳送時間已超過指定時間的訊息,重新投遞,並更新投遞時間為當前時間、重試次數+1;
 

方案一存在的問題

生產者執行定時任務也有額外的開銷,生產者要進行2方面的資料庫IO操作(訊息本身+訊息狀態),IO是很花時間的,在高併發的情況下,資料庫效能很容易成為系統效能的瓶頸。

併發量大的情況下,第一種方案嚴重拉低生產者的效能。

相比之下,第二種方案用得更多,但稍微複雜一點。

 

方案二 延時再次投遞訊息

1、生產者將訊息入庫,並將訊息傳送給broker,broker將訊息放到對應的queue1中

2、消費者監聽queue1,處理訊息,處理一條訊息後產生一條新訊息作為確認(繫結queue2),比如以Order的id作為新訊息,總之要能唯一標識處理的訊息。

3、消費者將產生的訊息傳送給broker,broker將訊息放到queue2中(注意不是消費者監聽的queue1)

4、單獨寫一個callback service(回撥服務),來監聽queue2,把queue2中的訊息入庫,比如放在tb_msg_processed表中,一條記錄代表一條已被消費者處理的訊息

5、生產者傳送訊息後,延時再次傳送這條訊息(繫結queue3),比如3min|5min後再次傳送這條訊息。

6、回撥服務監聽queue3,把queue中訊息與資料庫中的記錄對比,比如把queue3獲取到的Order的id取出來,查詢tb_msg_processed中有沒有這個Order id,有就說明投遞成功;沒有就說說明未投妥,回撥服務rpc通知生產者(傳遞order id),生產者從資料庫查詢該條訊息的資料(order物件),重新投遞(queue1)——重新走一遍流程。
 

第一種方案消費者使用資料包來確認應答(ack),第二種由消費者自己產生一條訊息來確認應答。
在這裡插入圖片描述
整個流程中,生產者又叫做upstream service(上游服務),消費者又叫做downstream service(下游服務)。
 

方案二的優缺點

相較於第一種方案,第二種方案多寫一個服務,每對生產者——消費者都使用一個額外的queue來確認,回撥服務開發成本高些、略微複雜些;

部署回撥服務又要使用、維護額外的機器,成本變高了。

但生產者的資料庫IO操作減少了,提升了效能。只要效能上去,稍微增加點成本完全可以接受。

 

說明

(1)訊息入庫完成,然後傳送訊息(Order物件)到broker,注意順序

(2)分散式事務對效能的影響很大,併發量中小的可以加事務,如果併發量很大,事務會嚴重拉低效能,不建議加事務(能不加就不加)

(3)不管是第一種、還是第二種,都很難做到100%的投遞成功。優先考慮能夠扛得住高併發(效能),在保證效能的前提下儘可能提高訊息投遞的可靠性

相關文章