什么是生產端的可靠性投遞?
- 保障消息的成功發出。
- 保障MQ節點的成功接收。
- 發送端收到MQ節點(Broker)確認應答。
- 完善的消息進行補償機制。
互聯網大廠的解決方案:
- 消息落庫,對消息狀態進行打標。
- 消息的延遲投遞,做二次確認,回調檢查。
1.生產端-可靠性投遞:消息落庫,對消息進行打標
- Step1:業務數據落庫(BIZ DB)(如訂單數據),消息落庫(MSG DB)。
- Step2:分布式定時任務查詢待發送消息發送至MQ Broker。
- Step3:MQ Broker confirm 機制回調Producer Listener。
- Step4:更新消息發送狀態。
- Step5:分布式定時任務查詢發送失敗(未被confirm)的消息。
- Step6:重新發送發送失敗的消息。
- Step7:重復發送次數達到指定次數,不進行再次投遞,人工接入處理。
該場景在高並發場景下是否合適?
2.生產端-可靠性投遞:消息的延遲投遞,做二次確認,回調檢查
- Step1:業務上游業務數據落庫成功后,發送一條消息M1。
- Step2:一定時間延遲后(延遲時間根據業務需求而定)發送一條延遲消息M2用於追溯M1(可在M1發送得同時發送至延遲隊列中)。
- Step3:業務下游接收M1消息之后,完成下游業務邏輯。
- Step4:發送消息M3至MQ Broker(新的得隊列)。
- Step5:CallBack端監聽M3消息,落入消息庫。
- Step6:同時CallBack監聽延時到達得M2消息,與MSG DB 中的M3比對。若對比結果M3不存在,則消息補償(重新發送M1消息)。此時下游業務端可能會消費重復消息(M3消息發送失敗),因此需要保證冪等性。
改方案對比上述方案上游業務端減少一次數據庫持久化,並發壓力提高,補償消息機制略差。
3.消費端冪等性保障
簡單來說就是用戶對於同一操作發起的一次請求或者多次請求的結果是一致的。
我們可以借鑒數據庫的樂觀鎖機制來舉個例子
- 首先為表添加一個版本字段version
- 在執行更新操作前呢,會先去數據庫查詢這個version
- 然后執行更新語句,以version作為條件,例如:
- UPDATE T_REPS SET COUNT = COUNT -1,VERSION = VERSION + 1 WHERE VERSION = 1
- 如果執行更新時有其他人先更新了這張表的數據,那么這個條件就不生效了,也就不會執行操作了,通過這種樂觀鎖的機制來保障冪等性。
3.1消費端-冪等性保障
什么情況下會出現重復消費?
當消費者消費完消息時,在給生產端返回ack時由於網絡中斷,導致生產端未收到確認信息,該條消息會重新發送並被消費者消費,但實際上該消費者已成功消費了該條消息,這就是重復消費問題。
業界主流的冪等性操作:
- 唯一ID + 指紋碼機制,利用數據庫主鍵去重
- 利用Redis的原子性去實現
唯一ID+指紋碼機制:
唯一ID + 指紋碼機制,利用數據庫主鍵去重
SELECT COUNT(1) FROM T_ORDER WHERE ID = 唯一ID +指紋碼
好處:實現簡單
壞處:高並發下有數據庫寫入的性能瓶頸
解決方案:跟進ID進行分庫分表進行算法路由
整個思路就是首先我們需要根據消息生成一個全局唯一的ID,然后還需要加上一個指紋碼。這個指紋碼它並不一定是系統去生成的,而是一些外部的規則或者內部的業務規則去拼接,它的目的就是為了保障這次操作是絕對唯一的。
將ID + 指紋碼拼接好的值作為數據庫主鍵,就可以進行去重了。即在消費消息前呢,先去數據庫查詢這條消息的指紋碼標識是否存在,沒有就執行insert操作,如果有就代表已經被消費了,就不需要管了。
對於高並發下的數據庫性能瓶頸,可以跟進ID進行分庫分表策略,采用一些路由算法去進行分壓分流。應該保證ID通過這種算法,消息即使投遞多次都落到同一個數據庫分片上,這樣就由單台數據庫冪等變成多庫的冪等。
利用Redis的原子性去實現:
我們都知道redis是單線程的,並且性能也非常好,提供了很多原子性的命令。比如可以使用 setnx 命令。
在接收到消息后將消息ID作為key執行 setnx 命令,如果執行成功就表示沒有處理過這條消息,可以進行消費了,執行失敗表示消息已經被消費了。
使用 redis 的原子性去實現主要需要考慮兩個點
第一:我們是否要進行數據落庫,如果落庫的話,關鍵解決的問題是數據庫和緩存如何做到原子性?
第二:如果不進行落庫,那么都存儲到緩存中,如何設置定時同步的策略(同步到關系型數據庫)?緩存又如何做到數據可靠性保障呢
關於不落庫,定時同步的策略,目前主流方案有兩種,第一種為雙緩存模式,異步寫入到緩存中,也可以異步寫到數據庫,但是最終會有一個回調函數檢查,這樣能保障最終一致性,不能保證100%的實時性。第二種是定時同步,比如databus同步
來源:若汐緣
鏈接:https://www.jianshu.com/p/d8042d7f62e1