基礎
事務
事務指的就是一個操作單元,在這個操作單元中的所有操作最終要保持一致的行為,要么所有操作都成功,要么所有的操作都被撤銷
本地事務
本地事物其實可以認為是數據庫提供的事務機制(ACID 原則)
分布式事務
分布式事務指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位于不同的分布式系統的不同節點之上,分布式事務就是為了保證不同數據庫的數據一致性
場景
- 單體系統訪問多個數據庫 :一個服務需要調用多個數據庫實例完成數據的增刪改操作
- 多個微服務調用同一個數據庫:多個服務需要調用一個數據庫實例完成數據的增刪改查
- 多個微服務訪問多個數據庫
方案
2PC
兩階段提交(2PC),對業務侵 ?很小,它最?的優勢就是對使??透明,用戶可以像使?本地事務?樣使?基于 XA 協議的分布式事務,能夠嚴格保障事務 ACID 特性
(2PC) 的缺點也是顯而易見,它是一個強一致性的同步阻塞協議,事務執?過程中需要將所需資源全部鎖定,也就是俗稱的 剛性事務。所以它比較適?于執?時間確定的短事務,整體性能比較差
3PC
三段提交(3PC)是二階段提交(2PC)的一種改進版本 ,為解決兩階段提交協議的阻塞問題,上邊提到兩段提交,當協調者崩潰時,參與者不能做出最后的選擇,就會一直保持阻塞鎖定資源
2PC 中只有協調者有超時機制,3PC 在協調者和參與者中都引入了超時機制,協調者出現故障后,參與者就不會一直阻塞
雖然 3PC 用超時機 制,解決了協調者故障后參與者的阻塞問題,但與此同時卻多了一次網絡通信,性能上反而變得更差,也不太推薦
TCC
兩階段提交的一個變種,不同的是 TCC 為在業務層編寫代碼實現的兩階段提交。TCC 分別指 Try、Confirm、Cancel ,一個業務操作要對應的寫這三個方法
TCC 不存在資源阻塞的問題,因為每個方法都直接進行事務的提交,一旦出現異常通過則 Cancel 來進行回滾補償,這也就是常說的補償性事務
原本一個方法,現在卻需要三個方法來支持,TCC 對業務的侵入性很強,而且這種模式并不能很好地被復用,會導致開發量激增。還要考慮到網絡波動等原因,為保證請求一定送達都會有重試機制,所以考慮到接口的冪等性
消息事務(最終一致性)
消息事務其實就是基于消息中間件的兩階段提交,將本地事務和發消息放在同一個事務里,保證本地操作和發送消息同時成功
- 訂單系統向
MQ發送一條預備扣減庫存消息,MQ保存預備消息并返回成功ACK - 接收到預備消息執行成功
ACK,訂單系統執行本地下單操作,為防止消息發送成功而本地事務失敗,訂單系統會實現MQ的回調接口,其內不斷的檢查本地事務是否執行成功,如果失敗則rollback回滾預備消息;成功則對消息進行最終commit提交。 - 庫存系統消費扣減庫存消息,執行本地事務,如果扣減失敗,消息會重新投,一旦超出重試次數,則本地表持久化失敗消息,并啟動定時任務做補償
基于消息中間件的兩階段提交方案,通常用在高并發場景下使用,犧牲數據的強一致性換取性能的大幅提升,不過實現這種方式的成本和復雜度是比較高的,還要看實際業務情況
Seata
也是從兩段提交演變而來的一種分布式事務解決方案,提供了 AT、TCC、SAGA 和 XA 等事務模式,這里重點介紹 AT模式
Transaction Coordinator(TC): 全局事務協調者,用來協調全局事務和各個分支事務(不同服務)的狀態, 驅動全局事務和各個分支事務的回滾或提交。Transaction Manager™: 事務管理者,業務層中用來開啟/提交/回滾一個整體事務(在調用服務的方法中用注解開啟事務)。Resource Manager(RM): 資源管理者,一般指業務數據庫代表了一個分支事務(Branch Transaction),管理分支事務與TC進行協調注冊分支事務并且匯報分支事務的狀態,驅動分支事務的提交或回滾
Seata 實現分布式事務,設計了一個關鍵角色 UNDO_LOG (回滾日志記錄表),我們在每個應用分布式事務的業務庫中創建這張表,這個表的核心作用就是,將業務數據在更新前后的數據鏡像組織成回滾日志,備份在 UNDO_LOG 表中,以便業務異常能隨時回滾
第一階段
把業務數據在更新前后的數據鏡像組織成回滾日志,將業務數據的更新和回滾日志在同一個本地事務中提交,分別插入到業務表和 UNDO_LOG 表中。在本地事務提交前,各分支事務需向全局事務協調者 TC 注冊分支 ( Branch Id) ,為要修改的記錄申請全局鎖 ,要為這條數據加鎖,利用 SELECT FOR UPDATE 語句。而如果一直拿不到鎖那就需要回滾本地事務。TM 開啟事務后會生成全局唯一的 XID,會在各個調用的服務間進行傳遞。
有了這樣的機制,本地事務分支(Branch Transaction)便可以在全局事務的第一階段提交,并馬上釋放本地事務鎖定的資源。相比于傳統的 XA 事務在第二階段釋放資源,Seata 降低了鎖范圍提高效率,即使第二階段發生異常需要回滾,也可以快速從UNDO_LOG 表中找到對應回滾數據并反解析成 SQL 來達到回滾補償
第二階段
根據各分支的決議做提交或回滾
- 如果決議是全局提交,此時各分支事務已提交并成功,這時
全局事務協調者(TC)會向分支發送第二階段的請求。收到 TC 的分支提交請求,該請求會被放入一個異步任務隊列中,并馬上返回提交成功結果給 TC。異步隊列中會異步和批量地根據Branch ID查找并刪除相應UNDO LOG回滾記錄 - 如果決議是全局回滾,過程比全局提交麻煩一點,
RM服務方收到TC全局協調者發來的回滾請求,通過XID和Branch ID找到相應的回滾日志記錄,通過回滾記錄生成反向的更新 SQL 并執行,以完成分支的回滾