分散式事務解決方案(二)【基於可靠訊息的最終一致性】

風靈使發表於2018-07-31

2. 最終一致性(基於可靠訊息)

2.1 訊息傳送的一致性

  • 指產生訊息的業務動作與訊息傳送的一致。(也就是說,如果業務操作成功,那麼由這個業務操作所產生的訊息一定要成功投遞出去,否則就丟訊息)

2.1.1 如何保障訊息傳送一致性

  • 處理方式1
    • 如果業務操作成功,執行訊息傳送前應用故障,訊息發不出去,導致訊息丟失(訂單系統與會計系統的資料不一致);
    • 如果業務操作成功,應用正常,但訊息系統故障或網路故障,也會導致訊息發不出去(訂單系統與會計系統的資料不一致);
/** 支付訂單處理 **/
public void completeOrder() {
    // 訂單處理(業務操作)
    orderBiz.process();
    // 傳送會記原始憑證訊息(傳送訊息)
    sendAccountingVoucherMsg ();
}
  • 處理方式2
    • 這種情況下,更不可控,訊息發出去了,但業務可能會失敗(訂單系統與會計系統的資料不一致)
/** 支付訂單處理 **/
public void completeOrder() {
    // 傳送會記原始憑證訊息(傳送訊息)
    sendAccountingVoucherMsg ();
    // 訂單處理(業務操作)
    orderBiz.process();
}

2.1.2 正向流程

image

  1. 主動方應用先把訊息發給訊息中介軟體,訊息狀態標記為“待確認”;
  2. 訊息中介軟體收到訊息後,把訊息持久化到訊息儲存中,但並不向被動方應用投遞訊息;
  3. 訊息中介軟體返回訊息持久化結果(成功/失敗),主動方應用根據返回結果進行判斷如何進行業務操作處理:
    • 失敗:放棄業務操作處理,結束(必要時向上層返回失敗結果);
    • 成功:執行業務操作處理;
  4. 業務操作完成後,把業務操作結果(成功/失敗)傳送給訊息中介軟體;
  5. 訊息中介軟體收到業務操作結果後,根據業務結果進行處理;
    • 失敗:刪除訊息儲存中的訊息,結束;
    • 成功:更新訊息儲存中的訊息狀態為“待傳送(可傳送)”,緊接著執行訊息投遞;
  6. 前面的正向流程都成功後,向被動方應用投遞訊息

2.1.3 異常流程

  • 異常點分析(任何一個環節都可能會出問題)

image

  • 從主動方應用的角度Fenix

image

異常狀況 可能的狀態 一致性
預傳送訊息失敗 訊息未進儲存,業務操作未執行(可能的原因:主動方應用、網路、訊息中介軟體、訊息儲存) 一致
預傳送訊息後,主動方應用沒有收到返回訊息儲存結果 (1)訊息未進儲存,業務操作未執行 一致
預傳送訊息後,主動方應用沒有收到返回訊息儲存結果 (2)訊息已進儲存(待確認),業務操作未執行 不一致
收到訊息儲存成功的返回結果,但未執行業務操作就失敗 訊息已進儲存(待確認),業務操作未執行 不一致

- 從訊息中介軟體的角度來分析

image

異常狀況 可能的狀態 一致性
訊息中介軟體沒有收到主動方應用的業務操作處理結果 (1)訊息已進儲存(待確認),業務操作未執行(或業務操作出錯回滾了) 不一致
訊息中介軟體沒有收到主動方應用的業務操作處理結果 (2)訊息已進儲存(待確認),業務操作成功 不一致
訊息中介軟體收到業務操作結果(成功/失敗),但處理訊息儲存中的訊息狀態失敗 (1)訊息已進儲存(待確認),業務操作未執行(或業務操作出錯回滾了) 不一致
訊息中介軟體收到業務操作結果(成功/失敗),但處理訊息儲存中的訊息狀態失敗 (2)訊息已進儲存(待確認),業務操作成功 不一致

- 總結

異常狀況 一致性 異常處理方法
訊息未進儲存,業務操作未執行 一致 無需處理
訊息已進儲存(狀態待確認),業務操作未執行 不一致 確認業務操作結果,處理訊息(刪除訊息)
訊息已進儲存(狀態待確認),業務操作成功,但未通知傳送 不一致 確認業務操作結果,處理訊息(更新訊息狀態,執行訊息投遞)

2.2 訊息消費一致性

  • 訊息消費流程

image

2.2.1 訊息消費流程的異常點

  • 訊息的消費確認流程中,任何一個環節都可能會出問題!

image

2.2.2 訊息消費流程異常處理

2.3 常規MQ處理流程

image

  1. Producer生成訊息併傳送給MQ(同步、非同步);
  2. MQ接收訊息並將訊息資料持久化到訊息儲存(持久化操作為可選配置);
  3. MQ向Producer返回訊息的接收結果(返回值、異常);
  4. Consumer監聽並消費MQ中的訊息;
  5. Consumer獲取到訊息後執行業務處理;
  6. Consumer對已成功消費的訊息向MQ進行ACK確認(確認後的訊息將從MQ中刪除)。

    • 佇列訊息模型的特點:

      1. 訊息生產者將訊息傳送到Queue中,然後訊息消費者監聽Queue並接收訊息;
      2. 訊息被確認消費以後,就會從Queue中刪除,所以訊息消費者不會消費到已經被消費的訊息;
      3. Queue支援存在多個消費者,但是對某一個訊息而言,只會有一個消費者成功消費。
    • 常規MQ佇列訊息的處理流程無法實現訊息傳送一致性;

    • 投遞訊息的流程其實就是訊息的消費流程,可細化。
    • 解決方案如下

image

常規MQ佇列訊息的處理流程無法實現訊息傳送一致性,因此直接使用現成的MQ中介軟體產品無法實現可靠訊息最終一致性的分散式事務解決方案。

2.3 訊息冪等性

2.3.2 訊息重複傳送的原因

  1. 被動方應用接收到訊息,業務處理完成後應用出問題,訊息中介軟體不知道訊息處理結果,會重新投遞訊息。
  2. 被動方應用接收到訊息,業務處理完成後網路出問題,訊息中介軟體收不到訊息處理結果,會重新投遞訊息。
  3. 被動方應用接收到訊息,業務處理時間過長,訊息中介軟體因訊息超時未確認,會再次投遞訊息。
  4. 被動方應用接收到訊息,業務處理完成,訊息中介軟體問題導致收不到訊息處理結果,訊息會重新投遞。
  5. 被動方應用接收到訊息,業務處理完成,訊息中介軟體收到了訊息處理結果,但由於訊息儲存故障導致訊息沒能成功確認,訊息會再次投遞。

2.3.3 業務介面的冪等性設計

約束:被動方應用對於訊息的業務處理要實現冪等

  • 對於存在同一請求資料會發生重複呼叫的業務介面,介面的業務邏輯要實現冪等性設計。
  • 在實際的業務應用場景中,業務介面的冪等性設計,常結合可查詢操作一起使用。
    • 支付訂單建立:商戶編號 + 商戶訂單號 + 訂單狀態
    • 訂單更新處理:平臺訂單號 + 訂單狀態
    • 會計系統記賬:系統來源 + 請求號

2.4 方案一:本地訊息服務的設計

2.4.1 面臨問題

  1. 現成MQ中介軟體不支援訊息傳送的一致性
  2. 直接改造MQ中介軟體難度很大
  3. 有什麼變通的實現方式?

2.4.2 主要流程

image

  1. 訊息儲存與業務儲存在同一個本地事務中進行,訊息儲存後設定為待確認狀態,並非同步將訊息傳送(注意需要非同步傳送訊息,不要影響主流程).
  2. 通過一定策略不斷將待確認的訊息重新傳送.
  3. 業務方回收到訊息,成功處理業務,並持久化完成後調主動方介面,通知主動方此訊息已經處理完成,主動方將資料庫中訊息狀態改為已傳送.
  4. 實現一個訊息管理系統,手動處理多次重發失敗已死亡的訊息.

2.4.3 優勢

  1. 訊息實時性較高
  2. 從應用設計開發的角度實現了訊息資料的可靠性,訊息資料的可靠性不依賴於MQ中介軟體,弱化了對MQ中介軟體的依賴
  3. 方案輕量容易實現

2.4.4 劣勢

  1. 業務繫結,耦合性強,不通用
  2. 訊息資料與業務資料同庫,佔用業務系統資源
  3. 業務系統在使用關係型資料庫的情況下,訊息服務效能會受到關係型資料庫併發效能的侷限

2.5 方案二:獨立訊息服務

2.5.1 面臨問題

  1. 現成MQ中介軟體不支援訊息傳送的一致性
  2. 直接改造MQ中介軟體難度很大
  3. 有什麼變通的實現方式?

2.5.2 主要流程

image

  1. 儲存預傳送訊息(主動方業務執行之前進行,預傳送的訊息儲存後狀態為待確認)
  2. 確認併傳送訊息(主動方業務完成之後,主動方或訊息狀態確認系統通過此介面將訊息變為取消或傳送中)
  3. 查詢狀態確認超時的訊息(訊息狀態確認系統使用)
  4. 確認訊息已被成功消費(被動方業務執行完成之後呼叫)
  5. 查詢消費確認超時的資訊

2.5.3 優勢

  1. 訊息服務獨立部署,獨立維護,獨立伸縮
  2. 訊息儲存可以按需選擇不同的資料庫來整合實現
  3. 訊息服務可以被相同的使用場景共用,降低訊息重複建設訊息服務的成本
  4. 從應用設計開發的角度實現了訊息資料的可靠性,訊息資料的可靠性不依賴於MQ中介軟體,弱化了MQ中介軟體特性的依賴
  5. 降低了業務系統與系統間的耦合,有利於系統的擴充套件維護

2.5.4 劣勢

  1. 一次訊息需要傳送兩次請求
  2. 主動方應用系統需要實現業務操作狀態校驗查詢介面

相關文章