1. 程式人生 > 實用技巧 >明瞭 | 看了這篇文章,多年不能理解的分散式事物,終於看懂了!

明瞭 | 看了這篇文章,多年不能理解的分散式事物,終於看懂了!

基礎知識

工欲善其事,必先利其器。所以需要先有一定的基礎知識。

事物

事物指的是對應用程式進行的嚴密的操作,添加了事物以後,所有的操作都必須完成,否則已經發生的事物進行撤銷,即,事物具有四個特點,原子性,一致性,隔離性,永續性,這是個屬性稱之為ACID

具體應用場景

在大型電商系統中,下單介面通常會扣減庫存,減去優惠,生成訂單id,訂單服務與庫存,優惠,訂單id都是不同的服務,下單介面的成功與否,不僅僅取決於本地的db操作,還依賴於第三方的結果,這些時候就需要使用強分散式事物,達到最終的一致性。

CAP

CAP原則稱之為CAP定理,指在一個分散式系統中,一致性,可用性,分割槽容錯性,三者不能同時顧及到。

一致性

在分散式系統的所有資料,在同一時刻是否有相同的值。

可用性

在叢集一部分節點故障以後,叢集是否還能響應客戶端的讀寫請求。

分割槽容錯性

在分散式系統中,各個叢集分為好幾區域,每個區域之間應該是互通的。

核心

對於CAP來說,只能滿足其中兩個,三個不可能全部滿足,即

BASE 理論

BASE理論為基本可用,軟狀態,最終一致性。解釋如下

基本可用

當系統出現不可預知的故障的時候,還需要能用,相對於正常的系統而言,需要有

  1. 相應時間上的損失,響應時間會相應的延長。

  2. 功能上的失去,對於電商網站來說,正常可以完成每一筆訂單,但是大促的時候,會引導到一個系統繁忙頁面。

軟狀態

允許系統存在於中間狀態,例如當用戶下單的時候,允許在同一時刻,該分散式系統,可以有中間狀態,即庫存還沒有扣減的狀態,但是要求最終都要達到一致性。只是資料同步出現了延遲。

最終一致性

相對於如軟狀態,不可能一直都是軟狀態,必須有一個時間期限,在這個期限過完以後,應當保證所有的資料副本都將會保證資料的一致性。

柔性事物

柔性事物是基於BASE理論的概念,通過柔性事物來達到最終的一致性。例如資料庫的讀寫分離,寫庫同步到讀庫,會有一個延時,該延時造成資料不一致,這種狀態稱之為亂狀態,在一定期限,達到同步,稱之為最終一致性。這個事物,稱之為柔性事物。

冪等操作

冪等性指的是,介面無論被呼叫多少次,其介面的返回值都應該是相同的,不會產生其他的變化。例如第三方支付用於回撥的地址,告知某個訂單支付成功,該回調地址,無論呼叫多少次,返回的結果都應該是一致的,

使用場景

轉賬

使用者A使用銀行app發起一筆跨行轉賬給使用者B,銀行系統會先扣掉使用者A的錢,在增加使用者B的餘額,此時需要使用分散式事物,達到這個操作具有原子性。

下單扣庫存

在電商系統中下單扣庫存分為兩個部分,分別為下單,扣庫存,這兩個步驟同樣需要原子性,需要分散式事物保證其原子性。

同步超時

以電商系統為例子,在微服務訂單裡,一個介面對應於多個介面,如下圖所示。多個介面也需要實現其原子性,在這裡也需要使用分散式事物。

解決方案

兩節點提交

第一階段,事物管理器會向所有本地資源管理器發起請求,詢問是否是ready狀態,所有參與者都將會把本事物能否成功的資訊反饋給協調者。第二階段:事物管理器根據所有的本地資源管理器的反饋,通知所有本地資源管理器,步調一致地在所有分支上提交和回滾。

存在問題

  1. 同步阻塞,當參與事物者存在佔用公共資源的情況,其中一個佔用了資源,其他事物參與者就只能阻塞等待資源釋放,處於阻塞狀態。

單點故障

當事物管理器出現故障的以後,怎個系統將會不可用

我這裡準備了一些

【Java核心技術資料】

【JAVA核心總結】

【524頁中高階XXXX】

【《JavaGuide面試突擊》v3.0肝出來了!】

【Java高階筆試寶典覆蓋近3年Java筆試中98%高頻知識點吊打100家大廠面試官】

【Java大廠面試題】

【阿里架構師花近十年時間整理出來的Java核心知識pdf(Java崗)】

【524頁《Java中高階程式設計師必備核心知識》總結,令人猶如醍醐灌頂】

等一系列的Java架構資料需要的話掃一掃免費獲取 無套路

TCC

TCC(Try Confirm Cancel) Try 階段:嘗試執行,完成所有業務檢查(一致性), 預留必須業務資源(準隔離性) Confirm 階段:確認執行真正執行業務,不作任何業務檢查,只使用 Try 階段預留的業務資源,Confirm 操作滿足冪等性。要求具備冪等設計,Confirm 失敗後需要進行重試。Cancel 階段:取消執行,釋放 Try 階段預留的業務資源 Cancel 操作滿足冪等性 Cancel 階段的異常和 Confirm 階段異常處理方案基本上一致。在 Try 階段,是對業務系統進行檢查及資源預覽,比如訂單和儲存操作,需要檢查庫存剩餘數量是否夠用,並進行預留,預留操作的話就是新建一個可用庫存數量欄位,Try 階段操作是對這個可用庫存數量進行操作。基於 TCC 實現分散式事務,會將原來只需要一個介面就可以實現的邏輯拆分為 Try、Confirm、Cancel 三個介面,所以程式碼實現複雜度相對較高。

本地訊息表

  1. 當系統 A 被其他系統呼叫發生資料庫表更操作,首先會更新資料庫的業務表,其次會往相同資料庫的訊息表中插入一條資料,兩個操作發生在同一個事務中

  2. 系統 A 的指令碼定期輪詢本地訊息往 mq 中寫入一條訊息,如果訊息傳送失敗會進行重試

  3. 系統 B 消費 mq 中的訊息,並處理業務邏輯。如果本地事務處理失敗,會在繼續消費 mq 中的訊息進行重試,如果業務上的失敗,可以通知系統 A 進行回滾操作

可靠訊息最終一致性

對於可靠訊息來說,需要實現最終的一致性

  1. A 系統先向 mq 傳送一條 prepare 訊息,如果 prepare 訊息傳送失敗,則直接取消操作

  2. 如果訊息傳送成功,則執行本地事務

  3. 如果本地事務執行成功,則想 mq 傳送一條 confirm 訊息,如果傳送失敗,則傳送回滾訊息

  4. B 系統定期消費 mq 中的 confirm 訊息,執行本地事務,併發送 ack 訊息。如果 B 系統中的本地事務失敗,會一直不斷重試,如果是業務失敗,會向 A 系統發起回滾請求

  5. mq 會定期輪詢所有 prepared 訊息呼叫系統 A 提供的介面查詢訊息的處理情況,如果該 prepare 訊息本地事務處理成功,則重新發送 confirm 訊息,否則直接回滾該訊息

盡最大努力通知

最大努力通知是最簡單的一種柔性事務,適用於一些最終一致性時間敏感度低的業務,且被動方處理結果 不影響主動方的處理結果。

這個方案的大致意思就是:

  1. 系統 A 本地事務執行完之後,傳送個訊息到 MQ;

  2. 這裡會有個專門消費 MQ 的服務,這個服務會消費 MQ 並呼叫系統 B 的介面;

  3. 要是系統 B 執行成功就 ok 了;要是系統 B 執行失敗了,那麼最大努力通知服務就定時嘗試重新呼叫系統 B, 反覆 N 次,最後還是不行就放棄。