分散式事務解決方案

濤姐濤哥 發表於 2022-02-13

什麼是分散式系統?

部署在不同結點上的系統通過網路互動來完成協同工作的系統。
比如:充值加積分的業務,使用者在充值系統向自己的賬戶充錢,在積分系統中自己積分相應的增加。充值系統和積分系統是兩個不同的系統,一次充值加積分的業務就需要這兩個系統協同工作來完成。

什麼是事務?

事務是指由一組操作組成的一個工作單元,這個工作單元具有原子性(atomicity)、一致性(consistency)、 離性(isolation)和永續性(durability)。

  • 原子性:執行單元中的操作要麼全部執行成功,要麼全部失敗。如果有一部分成功一部分失敗那麼成功的操作要全部回滾到執行前的狀態。
  • 一致性:執行一次事務會使用資料從一個正確的狀態轉換到另一個正確的狀態,執行前後 資料都是完整的。
  • 隔離性:在該事務執行的過程中,任何資料的改變只存在於該事務之中,對外界沒有影響,事務與事務之間是完全的隔離的。只有事務提交後其它事務才可以查詢到最新的資料。 永續性:事務完成後對資料的改變會永久性的儲存起來,即使發生斷電當機資料依然在。

什麼是本地事務?

本地事務就是用關聯式資料庫來控制事務,關聯式資料庫通常都具有ACID特性,傳統的單體應用通常會將資料全部儲存在一個資料庫中,會藉助關聯式資料庫來完成事務控制。

什麼是分散式事務?

在分散式系統中一次操作由多個系統協同完成,這種一次事務操作涉及多個系統通過網路協同完成的過程稱為分式事務。這裡強調的是多個系統通過網路協同完成一個事務的過程,並不強調多個系統訪問了不同的資料庫,即使 多個系統訪問的是同一個資料庫也是分散式事務,如下圖:
在這裡插入圖片描述

CAP理論

如何進行分散式事務控制?CAP理論是分散式事務處理的理論基礎,瞭解了CAP理論有助於我們研究分散式事務的處理方案。

CAP理論是:分散式系統在設計時只能在一致性(Consistency)、可用性(Availability)、分割槽容忍性(Partition Tolerance)中滿足兩種,無法兼顧三種。

一致性(Consistency):服務A、B、C三個結點都儲存了使用者資料, 三個結點的資料需要保持同一時刻資料一致性。
可用性(Availability):服務A、B、C三個結點,其中一個結點當機不影響整個叢集對外提供服務,如果只有服務A結點,當服務A當機整個系統將無法提供服務,增加服務B、C是為了保證系統的可用性。
分割槽容忍性(Partition Tolerance):分割槽容忍性就是允許系統通過網路協同工作,分割槽容忍性要解決由於網路分割槽導致資料的不完整及無法訪問等問題。
分散式系統不可避免的出現了多個系統通過網路協同工作的場景,結點之間難免會出現網路中斷、網延延遲等現象,這種現象一旦出現就導致資料被分散在不同的結點上,這就是網路分割槽。

分散式系統能否兼顧C、A、P?
在保證分割槽容忍性的前提下一致性和可用性無法兼顧,如果要提高系統的可用性就要增加多個結點,如果要保證資料的一致性就要實現每個結點的資料一致,結點越多可用性越好,但是資料一致性越差。
所以,在進行分散式系統設計時,同時滿足“一致性”、“可用性”和“分割槽容忍性”三者是幾乎不可能的。 CAP有哪些組合方式?

  1. CA:放棄分割槽容忍性,加強一致性和可用性,關聯式資料庫按照CA進行設計。
  2. AP:放棄一致性,加強可用性和分割槽容忍性,追求最終一致性,很多NoSQL資料庫按照AP進行設計。
    說明:這裡放棄一致性是指放棄強一致性,強一致性就是寫入成功立刻要查詢出最新資料。追求最終一致性是指允許暫時的資料不一致,只要最終在使用者接受的時間內資料一致即可。
  3. CP:放棄可用性,加強一致性和分割槽容忍性,一些強一致性要求的系統按CP進行設計,比如跨行轉賬,一次轉賬請求要等待雙方銀行系統都完成整個事務才算完成。
    說明:由於網路問題的存在CP系統可能會出現待等待超時,如果沒有處理超時問題則整理系統會出現阻塞。

在分散式系統設計中AP的應用較多,即保證分割槽容忍性和可用性,犧牲資料的強一致性(寫操作後立刻讀取到最新資料),保證資料最終一致性。比如:訂單退款,今日退款成功,明日賬戶到賬,只要在預定的使用者可以接受的 時間內退款事務走完即可。

解決方案

兩階段提交協議(2PC)

為解決分散式系統的資料一致性問題出現了兩階段提交協議(2 Phase Commitment Protocol),兩階段提交由協調者和參與者組成,共經過兩個階段和三個操作,部分關聯式資料庫如Oracle、MySQL支援兩階段提交協議。

第一階段:準備階段(prepare)
協調者通知參與者準備提交訂單,參與者開始投票。
協調者完成準備工作向協調者回應Yes。

第二階段:提交(commit)/回滾(rollback)階段
協調者根據參與者的投票結果發起最終的提交指令。
如果有參與者沒有準備好則發起回滾指令。

一個下單減庫存的例子:

在這裡插入圖片描述

  1. 應用程式連線兩個資料來源。
  2. 應用程式通過事務協調器向兩個庫發起prepare,兩個資料庫收到訊息分別執行本地事務(記錄日誌),但不提交,如果執行成功則回覆yes,否則回覆no。
  3. 事務協調器收到回覆,只要有一方回覆no則分別向參與者發起回滾事務,參與者開始回滾事務。
  4. 事務協調器收到回覆,全部回覆yes,此時向參與者發起提交事務。如果參與者有一方提交事務失敗則由事務協調器發起回滾事務。

2PC的優點:實現強一致性,部分關聯式資料庫支援(Oracle、MySQL等)。
缺點:整個事務的執行需要由協調者在多個節點之間去協調,增加了事務的執行時間,效能低下。
事務補償(TCC)
TCC事務補償是基於2PC實現的業務層事務控制方案,它是Try、Confirm和Cancel三個單詞的首字母,含義如下:

  1. Try 檢查及預留業務資源
    完成提交事務前的檢查,並預留好資源。

  2. Confirm 確定執行業務操作
    對try階段預留的資源正式執行。

  3. Cancel 取消執行業務操作
    對try階段預留的資源釋放。

一個下單減庫存的業務為例
在這裡插入圖片描述

  1. Try
    下單業務由訂單服務和庫存服務協同完成,在try階段訂單服務和庫存服務完成檢查和預留資源。
    訂單服務檢查當前是否滿足提交訂單的條件(比如:當前存在未完成訂單的不允許提交新訂單)。
    庫存服務檢查當前是否有充足的庫存,並鎖定資源。
  2. Confirm 訂單服務和庫存服務成功完成Try後開始正式執行資源操作。
    訂單服務向訂單寫一條訂單資訊。
    庫存服務減去庫存。
  3. Cancel
    如果訂單服務和庫存服務有一方出現失敗則全部取消操作。
    訂單服務需要刪除新增的訂單資訊。
    庫存服務將減去的庫存再還原。

優點:最終保證資料的一致性,在業務層實現事務控制,靈活性好。
缺點:開發成本高,每個事務操作每個參與者都需要實現try/confirm/cancel三個介面。
注意:TCC的try/confirm/cancel介面都要實現冪等性,在為在try、confirm、cancel失敗後要不斷重試。
什麼是冪等性?
冪等性是指同一個操作無論請求多少次,其結果都相同。
冪等操作實現方式有:
1、操作之前在業務方法進行判斷如果執行過了就不再執行。
2、快取所有請求和處理的結果,已經處理的請求則直接返回結果。
3、在資料庫表中加一個狀態欄位(未處理,已處理),資料操作時判斷未處理時再處理。

訊息佇列實現最終一致
本方案是將分散式事務拆分成多個本地事務來完成,並且由訊息佇列非同步協調完成,如下圖:
下邊以下單減少庫存為例來說明:
在這裡插入圖片描述

  1. 訂單服務和庫存服務完成檢查和預留資源。
  2. 訂單服務在本地事務中完成新增訂單表記錄和新增“減少庫存任務訊息”。
  3. 由定時任務根據訊息表的記錄傳送給MQ通知庫存服務執行減庫存操作。
  4. 庫存服務執行減少庫存,並且記錄執行訊息狀態(為避免重複執行訊息,在執行減庫存之前查詢是否執行過此訊息)。
  5. 庫存服務向MQ傳送完成減少庫存的訊息。
  6. 訂單服務接收到完成庫存減少的訊息後刪除原來新增的“減少庫存任務訊息”。

實現最終事務一致要求:預留資源成功理論上要求正式執行成功,如果執行失敗會進行重試,要求業務執行方法實現冪等。

優點 :
由MQ按非同步的方式協調完成事務,效能較高。 不用實現try/confirm/cancel介面,開發成本比TCC低。
缺點:
此方式基於關聯式資料庫本地事務來實現,會出現頻繁讀寫資料庫記錄,浪費資料庫資源,另外對於高併發操作不是最佳方案。