分佈式事務理論與解決方案
作者:不是分針
鏈接:https://www.jianshu.com/p/daf012b994ea
一 與本地事務的區別
描述場景:支付訂單的時候需要完成兩步操作
-
修改訂單表訂單狀態爲已支付
-
修改庫存表減去訂單對應庫存數量
本地事務:
只有唯一的數據庫,訂單表和庫存表都位於同一個數據庫,直接使用 spring 進行事務管理
分佈式事務:跨庫事務
隨着系統用戶量增長,業務量龐大,一個數據庫無法支撐我們業務的訪問壓力,以及數據庫表的容量無法滿足我們的需求的時候。我們考慮將數據庫按照業務進行拆分,將訂單表單獨放到訂單庫,將庫存表單獨放到庫存庫…
這樣在一個支付方法中我們會操作兩個數據庫,這時候使用 spring 進行事務管理已經不會起作用了
跨庫事務如果出現問題一般都是第一步成功了,第二步失敗了(第一步如果就失敗了,直接退出了):
即訂單修改成功,庫存數量沒變(超賣),可能原因:庫存不夠減,庫存庫掛了等情況
二分佈式事務基礎理論
2.1 CAP 理論
2.1.1 CAP
對照如下的商品服務調用主庫寫入數據,調用存庫讀取數據,主庫需要向從庫同步數據的場景解釋下 CAP
image
C:Consistency 一致性
一致性指的是寫操作後的讀操作可以讀取到最新的數據狀態,上圖中,商品信息的寫入和讀取要滿足一致性就是要實現:商品服務寫入主庫成功,在從庫中也能查詢到這條最新寫入的數據
如何實現一致性:
-
寫入主庫後需要將寫入的數據同步到從庫
-
寫入主庫後,在向從庫同步期間要將從庫鎖定,等到同步完成後再釋放鎖,防止數據寫入後,沒同步完成從而在從庫查詢到舊數據
分佈式系統一致性的特點:
- 由於存在數據同步的延遲,因此寫操作的響應會有一定的延遲,因爲是同步的!!你寫不只是寫到主庫成功還要加上從主庫同步到從庫的時間
2 . 爲了保證數據一致性會對資源暫時鎖定,等待數據同步完成釋放鎖定資源,因此允許出現返回錯誤或者響應超時
A:aVailability 可用性
可用性指的是任何事務操作都可以得到響應結果,且不會出現響應超時或者響應錯誤,上圖中,商品信息讀取滿足可用性即需要實現:從庫接收到數據查詢的請求能夠立即響應數據查詢結果,且不會出現響應超時或者響應錯誤
如何實現可用性:
-
寫入數據哭後要將寫入的數據同步到從庫
-
由於要保證從庫的可用性,因此不可將從庫的資源鎖定
-
即使數據還沒有同步過來,從庫也要返回查詢到的數據,哪怕是舊數據,但不能返回錯誤或響應超時
分佈式系統可用性特點:
所有請求都有響應,不會出現響應超時或響應錯誤
P:partition tolerance 分區容錯性
分區容錯性是指分佈式系統的各個節點可能部署在不同的子網(不同機房等),這就是網絡分區,相互之前需要進行利用網絡進行通信,不可避免的會出現網絡問題導致的通信失敗,這時候仍然可以對外提供服務,這就是分區容忍性
上圖中,商品信息寫入和讀取滿足分區容忍性就是要實現:
-
主庫向從庫同步數據失敗不影響對從庫的讀和主庫的寫操作
-
其中一個節點掛了不影響另外一個節點對外提供服務
如何實現分區容忍性:
-
儘量使用異步而非同步操作,例如使用異步方式將數據從主庫同步到從庫
-
添加從庫節點,防止一個從節點掛了其他從節點還可以提供服務
分佈式系統分區容忍性特點:
分佈式系統具備的基本能力
2.1.2 CAP 組合方式
在所有分佈式事務場景中不會同時具備 CAP 三個特性,因爲在具備了 P 的前提下 C 和 A 是不能共存的
對於大多數互聯網應用場景,節點衆多,部署分散,集羣規模龐大,因此節點故障,網絡故障都是常態,而且要保證服務可用性達到 N 個 9(99.999999%),並能達到良好的響應性能來提高用戶體驗,因此一般會做出如下選擇:保證 P 和 A,捨棄 C 強一致性,保證最終一致性
-
AP:
放棄一致性,追求分區容忍性和可用性,這是很多分佈式系統設計時的選擇。通常 AP 都會保證最終一致性,BASE 理論基於 AP,一些業務場景比如訂單退款,今日顯示退款成功,明日賬戶才能到賬,只要用戶可以接受在一段時間內到賬即可
如上面的商品寫入,查詢,完全可以實現 AP,只要用戶能接受所查詢到的數據在一定時間內不是最新數據即可 -
CP
放棄可用性,追求分區容錯性和一致性,zookeeper 即是 CP,但是隻是理想達到,但是 zk 實際上實現的還是最終一致性。CP 要求一次轉賬請求必須要等待雙方銀行系統都完成整個事務纔算完成 -
CA
放棄分區容忍性,mysql 主從變成只有一個主 mysql,不考慮由於網絡不通或者節點掛掉的問題,則可以實現 CA,同時這樣的系統不再是一個標準的分佈式系統,我們最常用的關係型數據庫就滿足了 CA
2.1.3 BASE 理論
-
強一致性 VS 最終一致性
CAP 理論告訴我們一個分佈式系統最多隻能同時一致性,可用性,分區容忍性三項中的兩項。在實際應用各種,捨棄一致性,保證可用性和分區容忍性的 AP 使用最爲廣泛。
但是在實際生產中很多場景都要實現一致性,比如前邊舉例的主庫向從庫同步數據,即使不要一致性,但是最終也要將數據同步成功來保證數據一致性,這種一致性和 CAP 中的一致性不同,CAP 中的一致性是要求在任何時間點查詢每個節點數據都必須一致,它強調的是強一致性!但是最終一致性是允許在一段時間內每個節點上的數據不一樣,但是經過一段時間每個節點上的數據必須一致 -
BASE 理論
Eventually [ɪˈventʃuəli] 最終的
BASE 是 Basically Available(基本可用)、 Soft state(軟狀態) 、Eventually [ɪˈventʃuəli] consistent(最終一致性) 的縮寫。BASE 理論是對 CAP 中的 AP 的擴展,通過犧牲強一致性來獲得可用性,當出現故障允許部分不可用但是需要保證核心功能可用,允許數據在一段時間內是不一致的,但是最終達到一致狀態,滿足 BASE 理論的事務,我們稱之爲 "柔性事務"
-
基本可用:分佈式系統出現故障的時候,允許損失部分可用功能,保證核心功能可用,如電商網站交易付款出現問題了,商品仍然可以正常瀏覽
-
軟狀態:由於不要求強一致性,所以 BASE 允許系統中存在中間狀態 (也叫軟狀態),這個狀態不影響系統可用性,如訂單的支付中,數據同步中等狀態,等到數據最終一致後狀態更改爲‘成功’狀態
-
最終一致:最終一致性是指經過一段時間後,所有節點數據都會達到一致,如訂單的支付中狀態,最終會變爲支付成功或者支付失敗,使得訂單狀態與交易結果打成一致,但是需要一定時間的延遲、等待
三 分佈式事務解決方案之兩階段提交協議
以分佈式事務理論爲基礎,針對不同的分佈式場景業界常見的解決方案有 2PC,TCC, 可靠消息最終一致性,最大努力通知這幾種
3.1 什麼是 2PC
2PC 就是兩階段提交協議,是將整個事務流程分爲兩個階段:準備階段(prepare phase)、提交階段(commit phase),2 是指兩個階段,P 是指準備階段,C 是提交階段
在部分關係數據庫如 MySQL 和 Oracle 都支持兩階段提交協議
-
準備階段(prepare phase):事務管理器給每個參與者發送 Prepare 消息,每個數據庫參與者在本地執行事務,並寫本地的 Undo/Redo 日誌,此時事務沒有提交(Undo 日誌是記錄修改前的數據,用於數據庫回滾,Redo 日誌是記錄修改後的數據,用於提交事務後寫入數據文件)
-
提交階段(commit phase):如果事務管理器收到了參與者的執行失敗或者超市消息的時候,就給每個參與者發送回滾(rollback)消息,否則,發送提交(commit)消息。參與者根據事務管理器的指令進行提交或者回滾操作,並釋放事務處理過程中使用的鎖資源。注意:必須在最後階段釋放鎖資源
下圖展示了 2PC 的兩個階段,分成功和失敗兩個情況說明
成功情況:
失敗情況:
第一階段(預提交)
-
在訂單庫修改訂單狀態 sql 執行以後,不直接進行事務提交(訂單庫查該訂單狀態並沒有修改,即將要修改的訂單的那條記錄鎖住了),而是將 sql 執行結果即成功與否通知事務管理器
-
然後在庫存庫減庫存 sql 執行以後,同樣不直接進行事務提交,同樣將 sql 執行結果通知給事務管理器
第二階段(commit/rollback)
事務管理器如果收到每個庫的 sql 執行結果都是成功,則事務管理器將會正常通知訂單庫和庫存庫,讓這兩個庫提交事務
如果事務管理器收到第一個庫 sql 執行成功,第二個執行失敗,則會執行數據庫的 rollback 事務回滾操作
疑問:
如果事務管理器通知訂單庫提交事務成功,然而在通知庫存庫提交事務的時候因爲網絡問題失敗了怎麼處理?
答:這種情況事務管理器會進行重試提交操作,如果多次嘗試不成功,可能去採取記日誌,發送告警消息給人工進行數據補償的操作
3.2 解決方案
3.2.1 XA 方案
2PC 的傳統方案是在數據庫層面實現的,如 Mysql 支持 2PC 協議,爲了統一標準減少行業的對接成本,需要指定標準化的處理模型以及接口標準,國際開放組織 Open Group 定義了分佈式事務處理模型 DTP(Distributed Transaction Processing Refrerence Model)
以新用戶註冊送積分爲例
執行流程:
DTP 模型定義如下角色:
總結:
注意:
,只可能儘量提高成功概率最大 99.99%,2pc 即是提高成功概率,2pc 兩個階段之間的過程很短,可能在幾十 ms
使用 2pc 的分佈式事務有中間件 atomikos,有開源版本和商業版本
3.2.2 Seata 方案
Seata 是一個開源的分佈式事務框架。傳統的 2PC 的問題(需支持 XA 協議,資源鎖在兩個階段結束後才釋放,性能較差)在 Seata 中得到了解決,它通過在本地關係數據庫的分支事務的協調來驅動完成全局事務,是工作在應用層(這樣就不需要數據庫實現 XA 協議)的中間件,主要優點是性能較好,且不會長時間佔用連接資源,它以高效且對業務 0 侵入的方式解決微服務場景下面臨的分佈式事務問題,它目前提供 AT 模式 (2PC) 以及 TCC 模式的分佈式事務解決方案
下面講解的是 AT 模式的 Seata 原理
與傳統 2PC 的模型類似,Seata 定義了 3 個組件來協調分佈式事務的處理過程
-
Transaction Coordinator(TC):事務協調器,它是獨立的中間件,需要獨立部署運行,它維護全局事務的運行狀態,接收 TM 指令發起全局事務的提交和回滾,負責與 RM 通信協調各分支事務的提交或回滾
-
Transaction Manager(TM):事務管理器,TM 需要嵌入到應用程序中工作(就是一個 jar 包),它負責開啓一個全局事務,並最終向 TC 發起全局提交或全局回滾的指令
-
Resource Manager(RM):控制分支事務,負責分支註冊,狀態彙報,並接收事務協調器 TC 的指令,驅動分支(本地)事務的提交和回滾
用上面的新用戶註冊送積分舉例 Seata 的分佈式事務過程
具體的執行流程如下:(注意:區別於傳統的 xA 方案,這裏的下面的過程的第 2 步分支事務會直接提交!至於已經提交了怎麼回滾(反向操作,刪除))
Seata 實現 2PC 與傳統 2PC 的差別
四 分佈式事務解決方案之 TCC
4.1 什麼是 TCC 事務
TCC 是 Try,Confirm,Cancel 三個詞語的縮寫,TCC 要求每個分支事務實現三個操作:預處理 try,確認 Confirm,撤銷 Cancel。Try 操作做業務檢查以及資源預留,Confirm 做業務確認操作,Cancel 實現一個與 Try 相反的操作即回滾操作。TM 首先發起所有的分支事務的 try 操作,任何一個分支事務的 try 操作執行失敗,TM 就會發起所有分支事務的 cancel 操作。若 Try 操作全部成功(則認爲 confirm 一定會成功),TM 將會發起所有分支事務的 Confirm 操作,其中 Confirm/Cancel 操作若執行失敗,TM 會進行重試,甚至人工介入
分支事務成功的情況:
分支事務失敗的情況:
TCC 分爲三個階段
目前市面上的 TCC 框架有 Seata,tcc-transaction,Hmily,ByteTCC,EasyTransaction
TCC 模式
TCC(Try-Confirm-Cancel)兩階段補償型方案
第一階段,調用每個服務的 try api,並沒有真正的去執行相關操作,而是有一個字段來記錄被凍結的記錄,實際庫存字段並沒有修改
第二階段,調用每個服務的 confirm api,這時候上一步記錄被凍結記錄的字段將會清零,然後實際庫存字段進行 - 1 操作
如果第一階段訂單服務調用庫存服務的凍結庫存操作成功,調用積分服務的預加積分操作失敗,則第二階段會執行 cancel 操作,即調用每個服務的 cancel(回滾資源接口)api,即上一步記錄被凍結記錄的字段直接清零,實際庫存字段不進行操作
如果在第一階段成功,在第二階段某個環節失敗,如果因爲網絡問題,直接進行重試,多次不成功採用定時任務等記錄事務日誌 + 人工處理補償
TCC 方式事務管理器中間件:
tcc-transaction,byteTcc,seata
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/SV2eWH52S_fQh5XXPKPd0g