前言
分散式系統中,不同服務之間的互動可能會出現各種問題,如網路、異常等,可能會導致服務間的資料產生不一致的情況,如何避免?本文將詳細講述分散式事務的原理和解決方案。
為什麼需要分散式事務
目前大多是網際網路公司都選擇的是分散式系統架構,隨之而來暴露本地事務出現的問題。所以瞭解分散式事務之前,需要了解什麼是本地事務。
那麼本地事務,在分散式系統中會出現哪些問題?這裡我們用訂單服務、庫存服務和優惠券服務來舉例說明。
第一種情況:儲存訂單成功,呼叫庫存服務時,庫存鎖定更改成功,但是由於伺服器卡頓等原因,導致呼叫超時,訂單服務報呼叫超時異常,並回滾資料,此時庫存已鎖定更改,但是訂單資料已全部回滾,導致資料不一致。
第二種情況:儲存訂單成功,呼叫庫存服務也成功,接著呼叫優惠券服務去鎖定優惠券,這時優惠券服務報了異常,訂單和優惠券服務進行了回滾,但是已經執行過事務的庫存服務無法回滾,導致資料不一致。
總的而言,本地事務在分散式系統,只能控制住自己的回滾,控制不了其他服務的回滾,出現異常很可能產生資料不一致的情況。所以需要分散式事務來解決此類問題。
瞭解分散式事務之前,我們還需要了解 CAP 原則和 BASE 理論。
CAP 原則
什麼是 CAP 原則
CAP 原則又稱 CAP 定律,指的是在一個分散式系統中,一致性、可用性、分割槽容錯性,三者不可兼得。
特性 | 說明 |
---|---|
一致性(Consistency) | 所有節點訪問的是同一份最新的資料副本,屬於強一致性。 |
可用性(Availability) | 服務一直可以訪問,且是正常訪問時間。 |
分割槽容錯性(Partition tolerance) | 分散式系統在遇到某節點或網路分割槽故障的時候,仍然能夠對外提供服務。 |
既然三者不可兼得,對待資料就有以下幾種不同的一致性策略。
一致性策略 | 說明 |
---|---|
強一致性 | 所有節點訪問的是同一份最新的資料副本。 |
弱一致性 | 資料更新後,能容忍後續的訪問只能訪問到部分或者全部訪問不到。 |
最終一致性 | 在一段時間後,節點間的資料會最終達到一致狀態。 |
為什麼 CAP 不可兼得
我們假設一個分散式網路中,有兩個節點Host1
和Host2
,分別對應資料庫Data0
和Data1
,我們將一個資料備份到這兩個資料中,假設這個資料值為age = 18
,此時**Data0**
更改資料值為**age = 28**
。
接下來,我們分析如何才能滿足 CAP 原則:
- 滿足一致性:如果
Data0
中更改age = 28
,則Data1
中必須同步更改; - 滿足可用性:使用者不管請求
Host1
或Host2
,都會在正常時間內響應結果。 - 滿足分割槽容錯性:
Host1
或Host2
故障的時候,仍然能夠對外提供服務。
最後,我們根據不同情況進行分析證明:
-
保證 C 和 P 的情況下:一致性要求
Data0
須將值複製給Data1
,分割槽容錯代表Data0
和Data1
可能會有一個出錯,這時Data1
並不能及時同步資料,為了保證資料一致性只能阻塞等待資料同步,此時則無法保證可用性了。 -
保證 A 和 P 的情況下:可用性要求
Host1
和Host2
在正常時間內響應,同樣由於網路問題**Data1**
還沒來得及同步資料,但為了保證可用性直接返回資料,返回的可能是舊的資料,此時則無法保證一致性了。 -
保證 C 和 A 的情況下:一致性和可用性,必須保證網路可靠不出故障的情況下才可能實現,此時只有不分割槽才能實現,這樣則無法保證分割槽容錯性,且此時將不再算是分散式系統了。
綜上所述,在一個分散式系統中,一致性、可用性、分割槽容錯性,三者不可兼得。
CAP 的取捨策略
CA 捨棄 P
捨棄分割槽容錯性,既不分割槽,違背了分散式系統的設計初衷。所以對於一個分散式系統來說,P 是一個基本要求,CAP 三者中,只能在 CA 兩者之間做權衡,並且要想盡辦法提升 P。
如關係型資料庫 Oracle、MySQL 就是 CA。
CP 捨棄 A
捨去可用性,要求資料強一致性,此時分割槽需要資料痛,而網路故障或訊息丟失可能導致同步時間無限延長,可能影響使用者體驗,等資料完全一致後,才能成功響應。
如非關係型資料看 Redis、HBASE等,分散式系統中常用的 Zookeeper 也是選擇優先保證 CP。
還有跨行轉賬場景中,一次轉賬請求要等待雙方銀行系統都完成整個事務才算完成。
AP 捨去 C
捨棄一致性,保證可用性和分割槽容。前提是使用者能夠接受在一定時間內,查詢到的資料不一定是最新的。這種通常會保證最終一致性,後面的 BASE 理論就是根據 AP 來擴充套件的。
如搶購場景,你看到的可購庫存數量是有的,你點進去就會顯示購買失敗,庫存已空,這種就是捨棄了一致性,這裡屬於強一致性,但是最後會保證資料最終一致性。
BASE 理論
什麼是 BASE 理論
BASE 是 Basically Available、Soft State 和 Eventually Consistent 的縮寫,含義分別是基本可用、軟狀態和最終一致性。
我們已瞭解分散式系統在保證 AP 性質的同時,無法做到強一致性。所以基本可用的核心思想是,即便無法保證強一致性,也可以根據應用特點採取適當措施,來達到最終一致性的效果。
Basically Available
基本可用,本質是一種妥協,就是說當出現節點故障或系統過載時,透過犧牲非核心功能的可用性,保證核心功能的穩定執行。
實現基本可用的策略:
策略 | 示例 |
---|---|
流量削峰 | 秒殺活動將熱門商品時間錯開,削弱請求峰值。 |
延遲響應、非同步處理 | 搶購商品,基於佇列收到下單請求,排隊非同步處理,延遲響應。 |
體驗降級 | 看到的非實時資料,採用快取資料提供服務。壓縮圖片質量,提高效能。 |
熔斷、限流 | 直接拒絕掉部分請求,或當請求佇列滿後移除部分請求,保證整體系統可用。 |
故障隔離 | 出現故障,做到故障隔離,避免影響其他服務。 |
Soft State
軟狀態,允許系統中的資料存在中間狀態,並認為該狀態不影響系統的整體可用性,即允許系統在多個不同節點的資料副本存在資料延遲。
與硬狀態對應,硬狀態要求多個節點的資料副本都是一致的。
Eventually Consistent
最終一致性,指系統中的所有資料副本,再經過一定時間的同步後,最終能達到一致的狀態。在沒有發生故障的前提下,這裡的“一定時間”取決於網路延遲,系統負載和資料複製方案設計等因素。
本質就是系統保證資料最終一致,而不需要實時保證資料強一致性。
總的來說,BASE 理論面向的是大型高可用可擴充套件的分散式系統,和傳統事務的 ACID 是相反的,它完全不同於 ACID 的強一致性模型,而是透過犧牲強一致性來獲得可用性,並允許資料在一段時間是不一致的。
什麼是分散式事務
分散式事務是指事務的參與者、支援事務的伺服器、資源伺服器以及事務管理器分別位於不同的分散式系統的不同節點之上。
簡單說就是這個事務需要多個系統透過網路協同完成,來保證分散式系統中的資料一致性。
分散式事務實現方案
2PC
2PC 和 3PC 都是基於XA
協議實現的分散式事務。XA
介面提供了事務管理器和本地資源管理器,其中本地資源管理器多由資料庫實現,如 Oracle、MySQL。
2PC 就是兩階段是提交,第一階段為準備階段,若所有事務參與者都預留資源成功,則第二階段進行提交,否則事務協調者回滾全部資源。
第一階段
如圖,由事務協調者詢問通知各個事務參與者,是否準備好了執行事務。
詳細流程:
- 協調者向所有參與者傳送事務內容,詢問是否可以提交事務,並等待答覆;
- 各參與者執行本地事務操作,將 undo 和 redo 資訊記入事務日誌中,但不提交;
- 如參與者執行成功,給協調者反饋同意,否則反饋中止,表示事務不可以執行;
第二階段
協調者收到各個參與者的準備訊息後,根據反饋情況通知各個參與者提交或回滾。
2.1 事務提交
如圖,當第一階段所有參與者都反饋同意時,協調者發起正式提交事務的請求,當所有參與者都回復同意時,則意味著完成事務,具體流程如下:
- 協調者節點向所有參與者節點發出正式提交的 commit 請求。
- 收到協調者的 commit 請求後,參與者正式執行事務提交操作,並釋放在整個事務期間內佔用的資源。
- 參與者完成事務提交後,向協調者節點傳送 ACK 訊息。
- 協調者節點收到所有參與者節點反饋的 ACK 訊息後,完成事務。
2.2 事務回滾
如果任意一個參與者節點在第一階段返回的訊息為中止,或者協調者節點在第一階段的詢問超時之前無法獲取所有參與者節點的響應訊息時,那麼這個事務將會被回滾,具體流程如下:
- 協調者向所有參與者發出 rollback 回滾操作的請求
- 參與者利用階段一寫入的 undo 資訊執行回滾,並釋放在整個事務期間內佔用的資源
- 參與者在完成事務回滾之後,向協調者傳送回滾完成的 ACK 訊息
- 協調者收到所有參與者反饋的 ACK 訊息後,取消事務
2PC 缺點
它是一個強一致性的同步阻塞協議,事務執⾏過程中需要將所需資源全部鎖定,也就是俗稱的剛性事務。所以它比較適⽤於執⾏時間確定的短事務,整體效能比較差。
一旦事務協調者當機或者發生網路抖動,會讓參與者一直處於鎖定資源的狀態或者只有一部分參與者提交成功,導致資料的不一致。因此,在⾼併發效能⾄上的場景中,基於 XA 協議的分散式事務並不是最佳選擇。
3PC
3PC,三階段提交協議,是二階段提交協議的改進版本,三階段提交有兩個改動點:
- 在協調者和參與者中都引入超時機制
- 在第一階段和第二階段中插入一個準備階段,保證了在最後提交階段之前各參與節點的狀態是一致的。
雖然 3PC 用超時機制,解決了協調者故障後參與者的阻塞問題,但與此同時卻多了一次網路通訊,效能上反而變得更差,也不太推薦。
2PC 和3PC 都無法保證資料絕對的一致性,一般為了預防這種問題,可以新增一個報警,比如監控到事務異常的時候,透過指令碼自動補償差異的資訊。
TCC
什麼是 TCC
兩階段提交的一個變種,不同的是 TCC 為在業務層編寫程式碼實現的兩階段提交。TCC 分別指 Try、Confirm、Cancel ,一個業務操作要對應的寫這三個方法。
TCC 不存在資源阻塞的問題,因為每個方法都直接進行事務的提交,一旦出現異常透過則 Cancel 來進行回滾補償,這也就是常說的補償性事務。
TCC 對業務的侵入性很強,原本一個方法,現在卻需要三個方法來支援 ,而且這種模式並不能很好地被複用,會導致開發量激增。
還要考慮到網路波動等原因,為保證請求一定送達都會有重試機制,所以考慮到介面的冪等性。
執行流程
如下圖,可將執行流程分為兩個階段:
- 第一階段:執行 Try,業務服務做檢測並鎖住資源;
- 第二階段:根據第一階段的結果決定是執行 Confirm 還是 Cancel,
- Confirm:執行真正的業務,並釋放鎖;
- Cancel:若出問題,則對 Try 階段預留資源的釋放;
以下單扣庫存為例,Try 階段去鎖庫存,不真正刪減,Confirm 階段則實際扣庫存,如果庫存扣減失敗 Cancel 階段進行回滾,釋放庫存。
TCC 優缺點:
TCC 事務相比於上面介紹的 XA 事務機制,有以下優點:
- 效能提升:具體業務來實現,控制資源鎖的粒度變小,不會鎖定整個資源。
- 資料最終一致性:基於 Confirm 和 Cancel 的冪等性,保證事務最終完成確認或者取消,保證資料的一致性。
- 可靠性:解決了 XA 協議的協調者單點故障問題,由主業務方發起並控制整個業務活動,業務活動管理器也變成多點,引入叢集。
缺點是 TCC 的 Try、Confirm 和 Cancel 操作功能要按具體業務來實現,業務耦合度較高,提高了開發成本。
Saga 事務
什麼是 Sage 事務
其核心思想是將長事務拆分為多個本地短事務並依次正常提交,如果所有短事務均執行成功,那麼分散式事務提交;如果出現某個參與者執行本地事務失敗,則由 Saga 事務協調器協調根據相反順序呼叫補償操作,回滾已提交的參與者,使分散式事務回到最初始的狀態。
與TCC事務補償機制相比,TCC有一個預留(Try)動作,相當於先報存一個草稿,然後才提交。Saga事務沒有預留動作,直接提交。
如圖, Sage 事務基本協議:
- 每個 Saga 事務由一系列冪等的有序子事務 Ti 組成;
- 每個 Ti 都有對應的冪等補償動作 Ci,補償動作用於撤銷 Ti 造成的結果。
Sage 的恢復策略
2.1 向後恢復
如圖,當執行事務失敗時,補償所有已完成的事務,撤銷掉之前所有成功的子事務。
2.2 向前恢復
對於執行不透過的事務,會嘗試重試事務直到成功,不需要補償,這種方式適用於必須要成功的場景。
Sage 優缺點
由於 Saga 模型沒有 Prepare 階段,因此事務間不能保證隔離性。當多個 Saga 事務操作同一資源時,就會產生更新丟失、髒資料讀取等問題。這時需要在業務層控制併發,在應用層面加鎖。
本地訊息表
什麼是本地事務表
核心思路就是將分散式事務拆分成本地事務進行處理,有事務主動方和事務被動方兩種角色。
事務主動發起方需要額外新建事務訊息表,用來在本地事務中和記錄事務訊息、完成業務處理,並輪詢事務訊息表的資料傳送事務訊息,事務被動方基於訊息中介軟體消費事務訊息表中的事務。
這樣可以避免以下兩種情況導致的資料不一致性:
- 業務處理成功、事務訊息傳送失敗;
- 業務處理失敗、事務訊息傳送成功。
本地訊息表的執行流程
一些必要的容錯處理如下:
- 當第 2 步出錯,事務主動方本地儲存了訊息,只需要輪詢訊息表重新透過訊息中介軟體傳送即可;
- 如果是事務被動方業務上處理失敗,可以發訊息給事務主動方回滾事務;
- 如果事務被動方已經消費了訊息,事務主動方需要回滾事務的話,需要再發訊息通知。
本地訊息表優缺點
優點:從應用設計開發的角度實現了訊息資料的可靠性,訊息資料的可靠性不依賴於訊息中介軟體,弱化了對 MQ 中介軟體特性的依賴。
缺點:
- 與具體的業務場景繫結,耦合性強,不可共用;
- 訊息資料與業務資料同庫,佔用業務系統資源;
- 訊息服務效能會受到關係型資料庫併發效能的侷限。
基於可靠訊息
什麼是基於可靠訊息
訊息的可靠性依賴於訊息中介軟體,本質上是對本地訊息表的封裝,整體流程與本地訊息表一致,唯一不同的就是將本地訊息表存在了MQ內部,而不是業務資料庫中,如下圖。
不同的 MQ 有不同的實現方式,詳細介紹放到對應的中介軟體介紹。
基於可靠訊息優缺點
相比本地訊息表方案,優點是:
- 訊息資料獨立儲存 ,降低業務系統與訊息系統之間的耦合
- 吞吐量大於使用本地訊息表方案
缺點:
- 一次訊息傳送需要兩次網路請求。
- 業務處理服務需要實現訊息狀態回查介面。
最大努力通知
最大努力通知也稱為定期校對,是對基於可靠訊息的進一步最佳化。它在事務主動方增加了訊息校對的介面,如果事務被動方沒有接收到主動方傳送的訊息,此時可以呼叫事務主動方提供的訊息校對的介面主動獲取。
在可靠訊息事務中,事務主動方需要將訊息傳送出去,並且讓接收方成功接收訊息,這種可靠性傳送是由事務主動方保證的。
而最大努力通知中,事務主動方僅是透過重試、輪詢,將事務傳送給事務接收方,所以存在事務被動方接收不到訊息的情況,此時需要事務被動方主動呼叫事務主動方的訊息校對介面查詢業務訊息並消費,這種通知的可靠性是由事務被動方保證的。
所以最大努力通知適用於業務通知型別,例如微信交易的結果,就是透過最大努力通知方式通知各個商戶,既有回撥通知,也有交易查詢介面。
實現方案場景總結
方案 | 特性 | 場景 |
---|---|---|
2PC/3PC | 剛性事務 | 適合傳統的單體應用,在同一個方法中存在跨庫操作的情況,不適合高併發和高效能要求的場景。 |
TCC | 柔性事務 | 只要能把 Try、Confirm、Cancel 各階段的邏輯捋清楚就可以使用TCC了, 但是存在業務耦合。 |
基於 MQ | 柔性事務 | 適用於事務中參與方支援操作冪等,業務上能容忍資料不一致。 |
Saga | 柔性事務 | 由於 Saga 事務不能保證隔離性,需要在業務層控制併發,適合於業務場景事務併發操作同一資源較少的情況。Saga 由於缺少預提交動作,導致補償動作的實現比較麻煩,例如業務是傳送簡訊,補償動作則得再傳送一次簡訊說明撤銷,使用者體驗比較差。所以,Saga 事務較適用於補償動作容易處理的場景 |
一些分散式事務中介軟體總結:
Seata
參考:
[1] 高階網際網路專家. 分散式事務理論.
[2] 還能在學一小時. 分散式常見解決方案.
[2] 程式設計師小富. 五種分散式方案,最終選擇了Seata.