一近零、背景
隨著業(yè)務(wù)發(fā)展诺核,單體系統(tǒng)逐漸無法滿足業(yè)務(wù)的需求,分布式架構(gòu)逐漸成為大型互聯(lián)網(wǎng)平臺首選久信。伴隨而來的問題是窖杀,本地事務(wù)方案已經(jīng)無法滿足,分布式事務(wù)相關(guān)規(guī)范和框架應(yīng)運而生裙士。
在這種情況下入客,大型廠商根據(jù)分布式事務(wù)實現(xiàn)規(guī)范,實現(xiàn)了不同的分布式框架腿椎,以簡化業(yè)務(wù)開發(fā)者處理分布式事務(wù)相關(guān)工作桌硫,讓開發(fā)者專注于核心業(yè)務(wù)開發(fā)。
Seata就是這么一個分布式事務(wù)處理框架啃炸,Seata是由阿里開源铆隘,前身為Fescar,經(jīng)過品牌升級變身Seata南用。
二膀钠、分布式事務(wù)規(guī)范
1.分布式事務(wù)相關(guān)概念
事務(wù):一個程序執(zhí)行單元,是用戶定義的一組操作序列裹虫,需要滿足ACID屬性肿嘲。
本地事務(wù):事務(wù)由本地資源管理器管理迹缀。
分布式事務(wù):事務(wù)的操作位于不同的節(jié)點磷雇。
分支事務(wù):在分布式事務(wù)中,由資源管理器管理的本地事務(wù)票腰。
全局事務(wù):一次性操作多個資源管理器完成的事務(wù)匣屡,由一組分支事務(wù)組成封救。
2. 分布式事務(wù)實現(xiàn)規(guī)范
對于本地事務(wù),可以借助DBMS系統(tǒng)來實現(xiàn)事務(wù)的管理捣作,但是對于分布式事務(wù)誉结,它就無能為力了。對于分布式事務(wù)虾宇,目前主要有2種思路:XA協(xié)議的強一致規(guī)范以及柔性事務(wù)的最終一致性規(guī)范。
2.1 XA
XA是基于2階段提交協(xié)議設(shè)計的接口標準如绸,實現(xiàn)了XA規(guī)范的資源管理器就可以參與XA全局事務(wù)嘱朽。應(yīng)用承擔事務(wù)管理器TM工作,數(shù)據(jù)庫承擔資源管理器RM工作怔接,TM生成全局事務(wù)id搪泳,控制RM的提交和回滾。
2.2 柔性事務(wù)的最終一致性
該規(guī)范主要有3種實現(xiàn)方式扼脐,TCC岸军、MQ事務(wù)消息奋刽、本地消息表。(還存在其他一些不常用實現(xiàn)方式如Saga)艰赞。
TCC:try/confirm/cancel佣谐,在try階段鎖定資源,confirm階段進行提交方妖,資源鎖定失敗執(zhí)行cancel階段釋放資源狭魂。
MQ事務(wù)消息:前提消息系統(tǒng)需要支持事務(wù)如RocketMQ,在本地事務(wù)執(zhí)行前党觅,發(fā)送事務(wù)消息prepare雌澄,本地事務(wù)執(zhí)行成功,發(fā)送事務(wù)消息commit杯瞻,實現(xiàn)分布式事務(wù)最終一致性镐牺。如果事務(wù)消息commit失敗,RocketMQ會回查消息發(fā)送者確保消息正常提交魁莉,如果步驟5執(zhí)行失敗睬涧,進行重試,達到最終一致性沛厨。
本地消息表:跟MQ事務(wù)消息類似宙地,區(qū)別在于MQ不支持事務(wù)消息,需要借助本地數(shù)據(jù)庫的事務(wù)管理能力逆皮。在步驟1中將需要發(fā)送的消息和本地事務(wù)一起提交到DB宅粥,借助DB的事務(wù)管理確保消息持久化。步驟2應(yīng)用通過本地消息表掃描电谣,重試發(fā)送秽梅,確保消息可以發(fā)送成功。
三剿牺、Seata 架構(gòu)
1. ****系統(tǒng)組成
Seata有三個核心組件:
-
Transaction Coordinator(TC企垦,事務(wù)協(xié)調(diào)器)
維護全局事務(wù)和分支事務(wù)的狀態(tài),驅(qū)動全局事務(wù)提交或回滾晒来。
-
Transaction Manager(TM钞诡,事務(wù)管理器)
定義全局事務(wù)的范圍,開始事務(wù)湃崩、提交事務(wù)荧降、回滾事務(wù)。
-
Resource Manager(RM攒读,資源管理器):
管理分支事務(wù)上的資源朵诫,向TC注冊分支事務(wù),匯報分支事務(wù)狀態(tài)薄扁,驅(qū)動分支事務(wù)的提交或回滾剪返。
三個組件相互協(xié)作废累,TC 以 Server 形式獨立部署,TM和RM集成在應(yīng)用中啟動脱盲,其整體交互如下:
2.工作模式
Seata 支持四種工作模式:
2.1 AT(Auto Transaction)
AT模式是Seata默認的工作模式邑滨。需要基于支持本地 ACID 事務(wù)的關(guān)系型數(shù)據(jù)庫,Java 應(yīng)用宾毒,通過 JDBC 訪問數(shù)據(jù)庫驼修。
2.1.1 整體機制
該模式是XA協(xié)議的演變,XA協(xié)議是基于資源管理器實現(xiàn)诈铛,而AT并不是如此乙各。AT的2個階段分別是:
一階段:業(yè)務(wù)數(shù)據(jù)和回滾日志記錄在同一個本地事務(wù)中提交,釋放本地鎖和連接資源幢竹。
二階段:提交異步化耳峦,非常快速地完成焕毫;回滾通過一階段的回滾日志進行反向補償蹲坷。
下圖中,步驟1開啟全局事務(wù)邑飒;步驟2注冊分支事務(wù)循签,這里對應(yīng)著一階段;步驟3提交或者回滾分支事務(wù)疙咸,對應(yīng)著二階段县匠。
2.1.2 特點
優(yōu)點:對代碼無侵入;并發(fā)度高撒轮,本地鎖在一階段就會釋放乞旦;不需要數(shù)據(jù)庫對XA協(xié)議的支持。
缺點:只能用在支持ACID的關(guān)系型數(shù)據(jù)庫题山;SQL解析還不能支持全部語法兰粉。
2.2 TCC
該模式工作分為三個階段:prepare/commit/cancel。
2.2.1 整體機制
TM向TC申請全局事務(wù)XID顶瞳,傳播給各個子調(diào)用玖姑。
子調(diào)用的所在TM向TC注冊分支事務(wù),并執(zhí)行本地prepare慨菱,并向TC報告執(zhí)行結(jié)果焰络。
TC根據(jù)各分支事務(wù)的執(zhí)行結(jié)果確定二階段是執(zhí)行commit或rollback。
2.2.2 特點
優(yōu)點:不依賴本地事務(wù)抡柿。
缺點:回滾邏輯依賴手動編碼舔琅;業(yè)務(wù)侵入性較大等恐。
2.3 Saga 模式
2.3.1 Saga 是什么洲劣?
1987年普林斯頓大學的Hector Garcia-Molina和Kenneth Salem發(fā)表了一篇Paper Sagas备蚓,講述的是如何處理long lived transaction(長活事務(wù))。Saga是一個長活事務(wù)可被分解成可以交錯運行的子事務(wù)集合囱稽。論文見這里郊尝。
簡單來說,Saga將一個長事務(wù)(T)分解成一系列Sub事務(wù)(Ti)战惊,每個Sub事務(wù)都有對應(yīng)的補償動作(Ci)流昏,用于撤銷Ti事務(wù)產(chǎn)生的影響。Sub事務(wù)是直接提交到庫吞获,在出現(xiàn)異常時况凉,逆向進行補償。
因此Saga事務(wù)的組成有2種:
T1, T2, T3, ..., Tn
T1, T2, ..., Tj, Cj,..., C2, C1各拷,其中0 < j < n
第一種就是正常提交的情況刁绒,第二種在提交Tj事務(wù)出現(xiàn)異常,開始逆向補償?shù)那闆r烤黍。
Saga模式是Seata提供的長事務(wù)解決方案知市。例如全局事務(wù)中涉及到外部系統(tǒng),無法管理它的資源管理器速蕊,讓它改造成TCC也不好實行嫂丙,這時就可以采用此類方案。
2.3.2 整體機制
在Saga模式中规哲,業(yè)務(wù)流程中每個參與者都提交本地事務(wù)跟啤,當出現(xiàn)某一個參與者失敗則補償前面已經(jīng)成功的參與者,一階段正向服務(wù)和二階段補償服務(wù)都由業(yè)務(wù)開發(fā)實現(xiàn)媳叨。
上圖中對于多個分支事務(wù)腥光,省略了多次出現(xiàn)的 2.* 步驟。對于全局事務(wù)執(zhí)行過程中業(yè)務(wù)應(yīng)用宕機情況糊秆,業(yè)務(wù)應(yīng)用集群中對等節(jié)點會通過從TC獲取相關(guān)會話武福,從DB加載詳細信息來恢復(fù)狀態(tài)機。
2.3.3 特點
優(yōu)點:一階段提交本地事務(wù)痘番,無鎖捉片,高性能;事件驅(qū)動架構(gòu)汞舱,參與者可異步執(zhí)行伍纫,高吞吐;補償服務(wù)易于實現(xiàn)昂芜。
缺點:不保證隔離性莹规。
2.4 XA模式
XA是基于二階段提交設(shè)計的接口標準。對于支持XA的資源管理器泌神,借助Seata框架的XA模式良漱,會使XA方案更簡單易用舞虱。使用前提:需要分支數(shù)據(jù)庫支持XA 事務(wù),應(yīng)用為 Java應(yīng)用母市,且使用JDBC訪問數(shù)據(jù)庫矾兜。
2.4.1 整體機制
在 Seata 定義的分布式事務(wù)框架內(nèi),利用事務(wù)資源(數(shù)據(jù)庫患久、消息服務(wù)等)對 XA 協(xié)議的支持椅寺,以 XA 協(xié)議的機制來管理分支事務(wù)的一種 事務(wù)模式。
執(zhí)行階段:業(yè)務(wù)sql在XA分支中執(zhí)行蒋失,由分支事務(wù)的RM管理器管理返帕,然后執(zhí)行XA prepare。
完成階段:TM根據(jù)各個分支執(zhí)行結(jié)果通過TC通知各個分支執(zhí)行XA commit或者XA rollback篙挽。
2.4.2 ****特點
優(yōu)點:繼承了XA協(xié)議的優(yōu)勢溉旋,事務(wù)具有強一致性。
缺點:同樣繼承了XA協(xié)議的劣勢嫉髓,由于分支事務(wù)長時間開啟观腊,并發(fā)度低。
2.5 Seata 各模式對比
分布式事務(wù)方案沒有銀彈算行,根據(jù)自己的業(yè)務(wù)特性選擇合適的模式梧油。例如追求強一致性,可以選擇AT和XA州邢,存在和外部系統(tǒng)對接儡陨,可以選擇Saga模式,不能依賴本地事務(wù)量淌,可以采用TCC等等骗村。結(jié)合各模式的優(yōu)缺點進行選擇。
四呀枢、AT 模式核心實現(xiàn)
鑒于Seata支持的模式較多胚股,而其默認的模式是AT,為節(jié)省篇幅裙秋,以下圍繞AT模式分析其相關(guān)的核心模塊實現(xiàn)琅拌。
1. 事務(wù)協(xié)調(diào)器的啟動
TC(事務(wù)協(xié)調(diào)器)以獨立的服務(wù)啟動,作為Server摘刑,維護全局事務(wù)和分支事務(wù)的狀態(tài)进宝,驅(qū)動全局事務(wù)提交或回滾。下面是TC的啟動流程:
[圖片上傳失敗...(image-b5010b-1607311250540)]
2. ****事務(wù)管理器的啟動
TM(事務(wù)管理器)集成在應(yīng)用中啟動枷恕,負責定義全局事務(wù)的范圍党晋,開始事務(wù)、提交事務(wù)、回滾事務(wù)未玻。
TM所在應(yīng)用中需要配置GlobalTransactionScannerbean漏益,在應(yīng)用啟動時會進行如下初始化流程:
3. 資源管理器的啟動
RM(資源管理器)集成在應(yīng)用中啟動,負責管理分支事務(wù)上的資源深胳,向TC注冊分支事務(wù),匯報分支事務(wù)狀態(tài)铜犬,驅(qū)動分支事務(wù)的提交或回滾舞终。
RM所在的應(yīng)用中除了需要跟TM一樣配置GlobalTransactionScanner以啟動RMClient,還需要配置DataSourceProxy癣猾,以實現(xiàn)對數(shù)據(jù)源訪問代理敛劝。該數(shù)據(jù)源代理實現(xiàn)了sql的解析 → 生成undo-log → 業(yè)務(wù)sql和undo-log一并本地提交等操作。
4. 全局事務(wù)的工作流程
下面以一個簡單的例子來說明全局事務(wù)的工作原理:
BusinessService:發(fā)起購買服務(wù)
StorageService:庫存管理服務(wù)
購買操作實現(xiàn)在businessService.purchase中纷宇,purchase方法實現(xiàn)上通過GlobalTransaction注解夸盟,通過Dubbo服務(wù),調(diào)用了庫存服務(wù)deduct方法方法像捶,樣例如下:
@GlobalTransactional(timeoutMills = 300000, name = "dubbo-demo-tx")
public void purchase(String userId, String commodityCode, int orderCount) {
storageService.deduct(commodityCode, orderCount);
// throw new RuntimeException("xxx");
}
4.1 成功的全局事務(wù)處理流程
4.2 成功的全局事務(wù)處理流程
這里設(shè)定BusinessService在成功調(diào)用StorageService后上陕,本地出現(xiàn)異常。
5. 寫隔離實現(xiàn)
全局事務(wù)未提交拓春,分支事務(wù)本地已經(jīng)提交的情況下(假設(shè)修改了資源A)释簿,如何避免其他事務(wù)在此時修改資源A?Seata采用全局鎖來實現(xiàn)硼莽,其流程如下:
6. 讀隔離實現(xiàn)
在數(shù)據(jù)庫本地隔離級別為讀已提交或以上的基礎(chǔ)上庶溶,Seata提供了讀未提交,這個很好理解懂鸵,全局事務(wù)提交前分支事務(wù)本地已經(jīng)提交偏螺。如果想要實現(xiàn)讀已提交,則需要在select語句上加for update匆光。
五套像、總結(jié)
Seata是Java領(lǐng)域很強大的分布式事務(wù)框架,其支持了多種模式终息。其中默認支持的AT模式凉夯,相比于傳統(tǒng)的2PC協(xié)議(基于數(shù)據(jù)庫的XA協(xié)議),很好地解決了2PC長期鎖資源的問題采幌,提高了并發(fā)度劲够。Seata支持的各個模式中,AT模式對業(yè)務(wù)零入侵實現(xiàn)分布式事務(wù)休傍,對于開發(fā)者更加友好征绎。另外Seata的Server在選擇合適的存儲介質(zhì)時可以進行集群模式,減少單點故障影響。
本文主要參考官網(wǎng)和部分博客人柿,同時閱讀了AT模式實現(xiàn)源碼柴墩,如果有不對的地方,望指出凫岖,一起討論交流江咳。
六、參考
作者:vivo官網(wǎng)商城開發(fā)團隊