1 常用事務(wù)解決方案模型
維基百科:https://zh.wikipedia.org/wiki/X/Open_XA
分布式事務(wù)的實(shí)現(xiàn)有許多種,其中較經(jīng)典是由Tuxedo提出的XA分布式事務(wù)協(xié)議,XA協(xié)議包含二階段提交(2PC)和三階段提交(3PC)兩種實(shí)現(xiàn)。其他還有 TCC、MQ 等最終一致性解決方案。
1.1 DTP模型
https://www.ibm.com/docs/zh/db2/10.5?topic=managers-designing-xa-compliant-transaction
X/Open DTP(X/Open Distributed Transaction Processing Reference Model) 是X/Open 這個(gè)組織定義的一套分布式事務(wù)的標(biāo)準(zhǔn),也就是了定義了規(guī)范和API接口,由廠商進(jìn)行具體的實(shí)現(xiàn)
X/Open DTP中的角色
- AP(Application Program):應(yīng)用程序,主要是定義事務(wù)邊界以及那些組成事務(wù)的特定于應(yīng)用程序的操作。
- RM(Resouces Manager):資源管理器,管理一些共享資源的自治域,如提供對(duì)諸如數(shù)據(jù)庫之類的共享資源的訪問。譬如:數(shù)據(jù)庫、文件系統(tǒng)等,并且提供了這些資源的訪問方式。
-
TM(Transaction Manager):事務(wù)管理器,管理全局事務(wù),協(xié)調(diào)事務(wù)的提交或者回滾,并協(xié)調(diào)故障恢復(fù)。
DTP模型里面定義了XA協(xié)議接口,TM 和 RM 通過XA接口進(jìn)行雙向通信, 后面SpringCloud Seata中也有這樣的角色
1.2 2PC
2PC、3PC,都是基于 XA 協(xié)議的
-
方案簡(jiǎn)介
二階段提交協(xié)議(Two-phase Commit,即2PC)是常用的分布式事務(wù)解決方案,即將事務(wù)的提交過程分為兩個(gè)階段來進(jìn)行處理:準(zhǔn)備階段和提交階段。事務(wù)的發(fā)起者稱協(xié)調(diào)者,事務(wù)的執(zhí)行者稱參與者
在分布式系統(tǒng)里,每個(gè)節(jié)點(diǎn)都可以知曉自己操作的成功或者失敗,卻無法知道其他節(jié)點(diǎn)操作的成功或失敗。當(dāng)一個(gè)事務(wù)跨多個(gè)節(jié)點(diǎn)時(shí),為了保持事務(wù)的原子性與一致性,而引入一個(gè)協(xié)調(diào)者來統(tǒng)一掌控所有參與者的操作結(jié)果,并指示它們是否要把操作結(jié)果進(jìn)行真正的提交或者回滾(rollback)。
二階段提交的算法思路可以概括為:參與者將操作成敗通知協(xié)調(diào)者,再由協(xié)調(diào)者根據(jù)所有參與者的反饋情報(bào)決定各參與者是否要提交操作還是中止操作。
核心思想就是對(duì)每一個(gè)事務(wù)都采用先嘗試后提交的處理方式,處理后所有的讀操作都要能獲得最新的數(shù)據(jù),因此也可以將二階段提交看作是一個(gè)強(qiáng)一致性算法。
-
處理流程
簡(jiǎn)單一點(diǎn)理解,可以把協(xié)調(diào)者節(jié)點(diǎn)比喻為帶頭大哥,參與者理解比喻為跟班小弟,帶頭大哥統(tǒng)一協(xié)調(diào)跟班小弟的任務(wù)執(zhí)行。
-
階段1:準(zhǔn)備階段
1、協(xié)調(diào)者向所有參與者發(fā)送事務(wù)內(nèi)容,詢問是否可以提交事務(wù),并等待所有參與者答復(fù)。
2、各參與者執(zhí)行事務(wù)操作,將undo和redo信息記入事務(wù)日志中(但不提交事務(wù))。
3、如參與者執(zhí)行成功,給協(xié)調(diào)者反饋yes,即可以提交;如執(zhí)行失敗,給協(xié)調(diào)者反饋no,即不可提交。 -
階段2:提交階段
如果協(xié)調(diào)者收到了參與者的失敗消息或者超時(shí),直接給每個(gè)參與者發(fā)送回滾(rollback)消息;否則,發(fā)送提交(commit)消息;釋放所有事務(wù)處理過程中使用的鎖資源。(注意:必須在最后階段釋放鎖資源)
接下來分兩種情況分別討論提交階段的過程
— 情況1,當(dāng)所有參與者均反饋yes,提交事務(wù):
1、協(xié)調(diào)者向所有參與者發(fā)出正式提交事務(wù)的請(qǐng)求(即commit請(qǐng)求)。
2、參與者執(zhí)行commit請(qǐng)求,并釋放整個(gè)事務(wù)期間占用的資源。
3、各參與者向協(xié)調(diào)者反饋ack(應(yīng)答)完成的消息。
4、協(xié)調(diào)者收到所有參與者反饋的ack消息后,即完成事務(wù)提交。
— 情況2,當(dāng)任何階段1一個(gè)參與者反饋no,中斷事務(wù):
1、協(xié)調(diào)者向所有參與者發(fā)出回滾請(qǐng)求(即rollback請(qǐng)求)。
2、參與者使用階段1中的undo信息執(zhí)行回滾操作,并釋放整個(gè)事務(wù)期間占用的資源。
3、各參與者向協(xié)調(diào)者反饋ack完成的消息。
4、協(xié)調(diào)者收到所有參與者反饋的ack消息后,即完成事務(wù)中斷。
方案總結(jié)
2PC是一個(gè)強(qiáng)一致性的同步阻塞協(xié)議,事務(wù)執(zhí)?過程中需要將所需資源全部鎖定,也就是俗稱的 剛性事務(wù)
2PC方案實(shí)現(xiàn)起來簡(jiǎn)單,實(shí)際項(xiàng)目中使用比較少,主要因?yàn)橐韵聠栴}:
- 性能問題
– 所有參與者在事務(wù)提交階段處于同步阻塞狀態(tài),占用系統(tǒng)資源,容易導(dǎo)致性能瓶頸。 - 可靠性問題
– 如果協(xié)調(diào)者存在單點(diǎn)故障問題,如果協(xié)調(diào)者出現(xiàn)故障,參與者將一直處于鎖定狀態(tài)。 - 數(shù)據(jù)一致性問題
– 在階段2中,如果發(fā)生局部網(wǎng)絡(luò)問題,一部分事務(wù)參與者收到了提交消息,另一部分事務(wù)參與者沒收到提交消息,那么就導(dǎo)致了節(jié)點(diǎn)之間數(shù)據(jù)的不一致。
1.3 3PC
- 方案簡(jiǎn)介
三階段提交協(xié)議,是二階段提交協(xié)議的改進(jìn)版本,與二階段提交不同的是,引入超時(shí)機(jī)制。同時(shí)在協(xié)調(diào)者和參與者中都引入超時(shí)機(jī)制(2PC 中只有協(xié)調(diào)者有超時(shí)機(jī)制)。
三階段提交將二階段的準(zhǔn)備階段拆分為2個(gè)階段,插入了一個(gè)preCommit階段,使得原先在二階段提交中,參與者在準(zhǔn)備之后,由于協(xié)調(diào)者發(fā)生崩潰或錯(cuò)誤,而導(dǎo)致參與者處于無法知曉是否提交或者中止的“不確定狀態(tài)”所產(chǎn)生的可能相當(dāng)長(zhǎng)的延時(shí)的問題得以解決。
- 處理流程
-
階段1:canCommit
協(xié)調(diào)者向參與者發(fā)送canCommit請(qǐng)求,參與者如果可以提交就返回yes響應(yīng)(參與者不執(zhí)行事務(wù)操作),否則返回no響應(yīng):
1、協(xié)調(diào)者向所有參與者發(fā)出包含事務(wù)內(nèi)容的canCommit請(qǐng)求,詢問是否可以提交事務(wù),并等待所有參與者答復(fù)。
2、參與者收到canCommit請(qǐng)求后,如果認(rèn)為可以執(zhí)行事務(wù)操作,則反饋yes并進(jìn)入預(yù)備狀態(tài),否則反饋no。 -
階段2:preCommit
協(xié)調(diào)者根據(jù)階段1 canCommit參與者的反應(yīng)情況來決定是否可以基于事務(wù)的preCommit操作。根據(jù)響應(yīng)情況,有以下兩種可能。
情況1,階段1所有參與者均反饋yes,參與者預(yù)執(zhí)行事務(wù):
1、協(xié)調(diào)者向所有參與者發(fā)出preCommit請(qǐng)求,進(jìn)入準(zhǔn)備階段。
2、參與者收到preCommit請(qǐng)求后,執(zhí)行事務(wù)操作,將undo和redo信息記入事務(wù)日志中(但不提交事務(wù))。
3、各參與者向協(xié)調(diào)者反饋ack響應(yīng)或no響應(yīng),并等待最終指令。
情況2,階段1任何一個(gè)參與者反饋no,或者等待超時(shí)后協(xié)調(diào)者尚無法收到所有參與者的反饋,即中斷事務(wù):
1、協(xié)調(diào)者向所有參與者發(fā)出abort請(qǐng)求。
2、無論收到協(xié)調(diào)者發(fā)出的abort請(qǐng)求,或者在等待協(xié)調(diào)者請(qǐng)求過程中出現(xiàn)超時(shí),參與者均會(huì)中斷事務(wù)。
-
階段3:do Commit
該階段進(jìn)行真正的事務(wù)提交,也可以分為以下兩種情況:
情況1:階段2所有參與者均反饋ack響應(yīng),執(zhí)行真正的事務(wù)提交:
1、如果協(xié)調(diào)者處于工作狀態(tài),則向所有參與者發(fā)出do Commit請(qǐng)求。
2、參與者收到do Commit請(qǐng)求后,會(huì)正式執(zhí)行事務(wù)提交,并釋放整個(gè)事務(wù)期間占用的資源。
3、各參與者向協(xié)調(diào)者反饋ack完成的消息。
4、協(xié)調(diào)者收到所有參與者反饋的ack消息后,即完成事務(wù)提交。
階段2任何一個(gè)參與者反饋no,或者等待超時(shí)后協(xié)調(diào)者尚無法收到所有參與者的反饋,即中斷事務(wù):
1、如果協(xié)調(diào)者處于工作狀態(tài),向所有參與者發(fā)出abort請(qǐng)求。
2、參與者使用階段1中的undo信息執(zhí)行回滾操作,并釋放整個(gè)事務(wù)期間占用的資源。
3、各參與者向協(xié)調(diào)者反饋ack完成的消息。
4、協(xié)調(diào)者收到所有參與者反饋的ack消息后,即完成事務(wù)中斷
注意:進(jìn)入階段3后,如果協(xié)調(diào)者出現(xiàn)問題,或者協(xié)調(diào)者與參與者網(wǎng)絡(luò)出現(xiàn)問題,都會(huì)導(dǎo)致參與者無法接收到協(xié)調(diào)者發(fā)出的do Commit請(qǐng)求或rollback請(qǐng)求。此時(shí),參與者都會(huì)在等待超時(shí)之后,繼續(xù)執(zhí)行事務(wù)提交。
階段三 只允許成功不允許失敗,如果服務(wù)器宕機(jī)或者停電,因?yàn)橛涗浀碾A段二的數(shù)據(jù),重啟服務(wù)后在提交事務(wù),所以,到了階段三,失敗了也不進(jìn)行回滾。
方案總結(jié)
- 優(yōu)點(diǎn)
– 相比二階段提交,三階段提交降低了阻塞范圍,在等待超時(shí)后協(xié)調(diào)者或參與者會(huì)中斷事務(wù)。避免了協(xié)調(diào)者單點(diǎn)問題,階段3中協(xié)調(diào)者出現(xiàn)問題時(shí),參與者會(huì)繼續(xù)提交事務(wù)。 - 缺點(diǎn)
– 數(shù)據(jù)不一致問題依然存在,當(dāng)在參與者收到preCommit請(qǐng)求后等待do commite指令時(shí),此時(shí)如果協(xié)調(diào)者請(qǐng)求中斷事務(wù),而協(xié)調(diào)者無法與參與者正常通信,會(huì)導(dǎo)致參與者繼續(xù)提交事務(wù),造成數(shù)據(jù)不一致。
1.4 TCC
方案簡(jiǎn)介
TCC(Try-Confirm-Cancel)的概念,最早是由Pat Helland于2007年發(fā)表的一篇名為《Life beyond Distributed Transactions:an Apostate’s Opinion》的論文提出。
TCC是服務(wù)化的二階段編程模型,其Try、Confirm、Cancel 3個(gè)方法均由業(yè)務(wù)編碼實(shí)現(xiàn),基本類似兩階段提交
- Try操作作為一階段,負(fù)責(zé)資源的檢查和預(yù)留。
- Confirm操作作為二階段提交操作,執(zhí)行真正的業(yè)務(wù)。
- Cancel是預(yù)留資源的取消。
TCC事務(wù)的Try、Confirm、Cancel可以理解為SQL事務(wù)中的Lock、Commit、Rollback。
TCC 為在業(yè)務(wù)層編寫代碼實(shí)現(xiàn)的兩階段提交。TCC 分別指 Try、Confirm、Cancel ,一個(gè)業(yè)務(wù)操作要對(duì)應(yīng)的寫這三個(gè)方法
Github 上有具體的實(shí)現(xiàn),例如 點(diǎn)擊跳轉(zhuǎn)
處理流程
-
階段1:Try 階段
從執(zhí)行階段來看,與傳統(tǒng)事務(wù)機(jī)制中業(yè)務(wù)邏輯相同。但從業(yè)務(wù)角度來看,卻不一樣。TCC機(jī)制中的Try僅是一個(gè)初步操作,它和后續(xù)的確認(rèn)一起才能真正構(gòu)成一個(gè)完整的業(yè)務(wù)邏輯,這個(gè)階段主要完成:
- 完成所有業(yè)務(wù)檢查( 一致性 )
- 預(yù)留必須業(yè)務(wù)資源( 準(zhǔn)隔離性 )
TCC事務(wù)機(jī)制以初步操作(Try)為中心的,確認(rèn)操作(Confirm)和取消操作(Cancel)都是圍繞初步操作(Try)而展開。因此,Try階段中的操作,其保障性是最好的,即使失敗,仍然有取消操作(Cancel)可以將其執(zhí)行結(jié)果撤銷。
假設(shè)商品庫存為100,購買數(shù)量為2,這里檢查和更新庫存的同時(shí),凍結(jié)用戶購買數(shù)量的庫存,同時(shí)創(chuàng)建訂單,訂單狀態(tài)為待確認(rèn)。
- 階段2:Confirm / Cancel 階段
根據(jù)Try階段服務(wù)是否全部正常執(zhí)行,繼續(xù)執(zhí)行確認(rèn)操作(Confirm)或取消操作(Cancel)。
Confirm和Cancel操作滿足冪等性,如果Confirm或Cancel操作執(zhí)行失敗,將會(huì)不斷重試直到執(zhí)行完成。
- Confirm:確認(rèn)
當(dāng)Try階段服務(wù)全部正常執(zhí)行, 執(zhí)行確認(rèn)業(yè)務(wù)邏輯操作
這里使用的資源一定是Try階段預(yù)留的業(yè)務(wù)資源。在TCC事務(wù)機(jī)制中認(rèn)為,如果在Try階段能正常的預(yù)留資源,那Confirm一定能完整正確的提交。Confirm階段也可以看成是對(duì)Try階段的一個(gè)補(bǔ)充,Try+Confirm一起組成了一個(gè)完整的業(yè)務(wù)邏輯。 - Cancel:取消
當(dāng)Try階段存在服務(wù)執(zhí)行失敗, 進(jìn)入Cancel階段
Cancel取消執(zhí)行,釋放Try階段預(yù)留的業(yè)務(wù)資源,上面的例子中,Cancel操作會(huì)把凍結(jié)的庫存釋放,并更新訂單狀態(tài)為取消。
方案總結(jié)
TCC事務(wù)機(jī)制相對(duì)于傳統(tǒng)事務(wù)機(jī)制(X/Open XA),TCC事務(wù)機(jī)制相比于上面介紹的XA事務(wù)機(jī)制,有以下優(yōu)點(diǎn):
- 性能提升
– 具體業(yè)務(wù)來實(shí)現(xiàn)控制資源鎖的粒度變小,不會(huì)鎖定整個(gè)資源。 - 數(shù)據(jù)最終一致性
– 基于Confirm和Cancel的冪等性,保證事務(wù)最終完成確認(rèn)或者取消,保證數(shù)據(jù)的一致性。 - 可靠性
– 解決了XA協(xié)議的協(xié)調(diào)者單點(diǎn)故障問題,由主業(yè)務(wù)方發(fā)起并控制整個(gè)業(yè)務(wù)活動(dòng),業(yè)務(wù)活動(dòng)管理器也變成多點(diǎn),引入集群。
缺點(diǎn):
- TCC的Try、Confirm和Cancel操作功能要按具體業(yè)務(wù)來實(shí)現(xiàn),業(yè)務(wù)耦合度較高,提高了開發(fā)成本。
2 Seata
Seata 是一款開源的分布式事務(wù)解決方案,致力于在微服務(wù)架構(gòu)下提供高性能和簡(jiǎn)單易用的分布式事務(wù)服務(wù)。在 Seata 開源之前,Seata 對(duì)應(yīng)的內(nèi)部版本在阿里經(jīng)濟(jì)體內(nèi)部一直扮演著分布式一致性中間件的角色,幫助經(jīng)濟(jì)體平穩(wěn)的度過歷年的雙11,對(duì)各BU業(yè)務(wù)進(jìn)行了有力的支撐。經(jīng)過多年沉淀與積累,商業(yè)化產(chǎn)品先后在阿里云、金融云進(jìn)行售賣。2019.1 為了打造更加完善的技術(shù)生態(tài)和普惠技術(shù)成果,Seata 正式宣布對(duì)外開源,開放以來,廣受歡迎,不到一年已經(jīng)成為最受歡迎的分布式事務(wù)解決方案。
官方中文網(wǎng):https://seata.io/zh-cn
github項(xiàng)目地址:https://github.com/seata/seata
官方example:https://github.com/seata/seata-samples
2.1 Seata術(shù)語
- TC (Transaction Coordinator) - 事務(wù)協(xié)調(diào)者
– 維護(hù)全局和分支事務(wù)的狀態(tài),驅(qū)動(dòng)全局事務(wù)提交或回滾。 - TM (Transaction Manager) - 事務(wù)管理器
– 定義全局事務(wù)的范圍:開始全局事務(wù)、提交或回滾全局事務(wù)。 - RM (Resource Manager) - 資源管理器
– 管理分支事務(wù)處理的資源,與TC交談以注冊(cè)分支事務(wù)和報(bào)告分支事務(wù)的狀態(tài),并驅(qū)動(dòng)分支事務(wù)提交或回滾。
Seata 致力于提供高性能和簡(jiǎn)單易用的分布式事務(wù)服務(wù)。Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務(wù)模式,為用戶打造一站式的分布式解決方案。
2.1 Seata AT模式
Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務(wù)模式,為用戶打造一站式的分布式解決方案。其中AT模式最受歡迎
AT模式的相關(guān)資料請(qǐng)參考官方文檔說明:https://seata.io/zh-cn/docs/overview/what-is-seata.html
下圖是AT模式的執(zhí)行流程:
2.1.1 AT模式及工作流程
見官方文檔:https://seata.io/zh-cn/docs/overview/what-is-seata.html
2.1.2 Seata-Server安裝
在選擇用Seata版本的時(shí)候,可以先參考下官方給出的版本匹配(Seata版本也可以按自己的要求選擇):跳轉(zhuǎn)
直接基于docker啟動(dòng):
docker run --name seata-server -p 8091:8091 -d -e SEATA_IP=192.168.200.200 -e SEATA_PORT=8091 --restart=on-failure seataio/seata-server:1.3.0
2.1.3 集成springcloud-alibaba
官方示例, 可以 跳轉(zhuǎn)
各種集成模式自行的去看對(duì)應(yīng)的samples
集成可以按照如下步驟實(shí)現(xiàn):
1: 引入依賴包spring-cloud-starter-alibaba-seata
2: 配置Seata
3: 創(chuàng)建代理數(shù)據(jù)源
4: @GlobalTransactional全局事務(wù)控制
集成SpringCloud Alibaba需求:
- 創(chuàng)建undo_log表
在每個(gè)數(shù)據(jù)庫中都需要?jiǎng)?chuàng)建該表:
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
- 依賴引入
<!--seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
- 配置Seata
依賴引入后,需要在項(xiàng)目中配置SeataClient 端信息,關(guān)于SeataClient端配置信息, 可以參考官方項(xiàng)目:script,如下圖:
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: default_tx_group
enable-auto-data-source-proxy: true
use-jdk-proxy: false
excludes-for-auto-proxying: firstClassNameForExclude,secondClassNameForExclude
client:
rm:
async-commit-buffer-limit: 1000
report-retry-count: 5
table-meta-check-enable: false
report-success-enable: false
saga-branch-register-enable: false
lock:
retry-interval: 10
retry-times: 30
retry-policy-branch-rollback-on-conflict: true
tm:
degrade-check: false
degrade-check-period: 2000
degrade-check-allow-times: 10
commit-retry-count: 5
rollback-retry-count: 5
undo:
data-validation: true
log-serialization: jackson
log-table: undo_log
only-care-update-columns: true
log:
exceptionRate: 100
service:
vgroup-mapping:
default_tx_group: default
grouplist:
default: 192.168.200.200:8091
enable-degrade: false
disable-global-transaction: false
transport:
shutdown:
wait: 3
thread-factory:
boss-thread-prefix: NettyBoss
worker-thread-prefix: NettyServerNIOWorker
server-executor-thread-prefix: NettyServerBizHandler
share-boss-worker: false
client-selector-thread-prefix: NettyClientSelector
client-selector-thread-size: 1
client-worker-thread-prefix: NettyClientWorkerThread
worker-thread-size: default
boss-thread-size: 1
type: TCP
server: NIO
heartbeat: true
serialization: seata
compressor: none
enable-client-batch-send-request: true
配置文件內(nèi)容參數(shù)比較多,注意部分:
- seata_transaction: default:事務(wù)分組,前面的seata_transaction可以自定義,通過事務(wù)分組很方便找到集群節(jié)點(diǎn)信息。
- tx-service-group: default_tx_group:指定應(yīng)用的事務(wù)分組,和上面定義的分組前部分保持一致。
- default: 192.168.200.200:8091:服務(wù)地址,seata-server服務(wù)地址。
- 代理數(shù)據(jù)源
通過代理數(shù)據(jù)源可以保障事務(wù)日志數(shù)據(jù)和業(yè)務(wù)數(shù)據(jù)能同步,關(guān)于代理數(shù)據(jù)源早期需要手動(dòng)創(chuàng)建,但是隨著Seata版本升級(jí),不同版本實(shí)現(xiàn)方案不一樣了,下面是官方的介紹:
1.1.0: seata-all取消屬性配置,改由注解@EnableAutoDataSourceProxy開啟,并可選擇jdk proxy或者cglib proxy
1.0.0: client.support.spring.datasource.autoproxy=true
0.9.0: support.spring.datasource.autoproxy=true
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.demo.driver.feign"})
@EnableAutoDataSourceProxy
public class OrderApplication {
}
- 全局事務(wù)控制
@Override
@GlobalTransactional
public OrderInfo addOrder(String id) {
...
}
關(guān)于使用feign降級(jí)功能導(dǎo)致seata事務(wù)無法回滾的問題請(qǐng)看:移步
4.2 Seata TCC模式
一個(gè)分布式的全局事務(wù),整體是 兩階段提交 的模型。全局事務(wù)是由若干分支事務(wù)組成的,分支事務(wù)要滿足 兩階段提交 的模型要求,即需要每個(gè)分支事務(wù)都具備自己的:
- 一階段 prepare 行為
- 二階段 commit 或 rollback 行為
根據(jù)兩階段行為模式的不同,將分支事務(wù)劃分為 Automatic Transaction Mode 和 Manual Transaction Mode.
AT 模式(參考鏈接 TBD)基于 支持本地 ACID事務(wù) 的 關(guān)系型數(shù)據(jù)庫:
- 一階段 prepare 行為:在本地事務(wù)中,一并提交業(yè)務(wù)數(shù)據(jù)更新和相應(yīng)回滾日志記錄。
- 二階段 commit 行為:馬上成功結(jié)束,自動(dòng) 異步批量清理回滾日志。
- 二階段 rollback 行為:通過回滾日志,自動(dòng) 生成補(bǔ)償操作,完成數(shù)據(jù)回滾。
相應(yīng)的,TCC 模式,不依賴于底層數(shù)據(jù)資源的事務(wù)支持:
- 一階段 prepare 行為:調(diào)用 自定義 的 prepare 邏輯。
- 二階段 commit 行為:調(diào)用 自定義 的 commit 邏輯。
- 二階段 rollback 行為:調(diào)用 自定義 的 rollback 邏輯。
所謂 TCC 模式,是指支持把 自定義 的分支事務(wù)納入到全局事務(wù)的管理中。
TCC實(shí)現(xiàn)原理:
有一個(gè) TCC 攔截器,它會(huì)封裝 Confirm 和 Cancel 方法作為資源(用于后面 TC 來 commit 或 rollback 操作)
封裝完,它會(huì)本地緩存到 RM (緩存的是方法的描述信息),可以簡(jiǎn)單認(rèn)為是放到一個(gè) Map 里面
當(dāng) TC 想調(diào)用的時(shí)候,就可以從 Map 里找到這個(gè)方法,用反射調(diào)用就可以了
另外,RM 不光是注冊(cè)分支事務(wù)(分支事務(wù)是注冊(cè)到 TC 里的 GlobalSession 中的)
它還會(huì)把剛才封裝的資源里的重要屬性(事務(wù)ID、歸屬的事務(wù)組等)以資源的形式注冊(cè)到 TC 中的 RpcContext
這樣,TC 就知道當(dāng)前全局事務(wù)都有哪些分支事務(wù)了(這都是分支事務(wù)初始化階段做的事情)
舉個(gè)例子:RpcContext里面有資源 123,但是 GlobalSession 里只有分支事務(wù) 12
于是 TC 就知道分支事務(wù) 3 的資源已經(jīng)注冊(cè)進(jìn)來了,但是分支事務(wù) 3 還沒注冊(cè)進(jìn)來
這時(shí)若 TM 告訴 TC 提交或回滾,那 GlobalSession 就會(huì)通過 RpcContext 找到 1 和 2 的分支事務(wù)的位置(比如該調(diào)用哪個(gè)方法)
當(dāng) RM 收到提交或回滾后,就會(huì)通過自己的本地緩存找到對(duì)應(yīng)方法,最后通過反射或其他機(jī)制去調(diào)用真正的 Confirm 或 Cancel
3 Seata注冊(cè)中心
參看:https://github.com/seata/seata/tree/1.3.0/script/config-center 可以看到seata支持多種注冊(cè)中心!
3.1 服務(wù)端注冊(cè)中心配置
服務(wù)端注冊(cè)中心(位于seata-server的registry.conf配置文件中的registry.type參數(shù)),為了實(shí)現(xiàn)seata-server集群高可用不會(huì)使用file類型,一般會(huì)采用第三方注冊(cè)中心,例如zookeeper、redis、eureka、nacos等。
以下使用nacos
seata-server的registry.conf配置如下:
由于是基于docker啟動(dòng)的seata,故可以直接進(jìn)入到容器內(nèi)部修改配置文件/resources/registry.conf
registry {
# file ...nacos ...eureka...redis...zk...consul...etcd3...sofa
type = "nacos"
nacos {
application = "seata-server"
serverAddr = "192.168.200.200:8848"
group = "SEATA_GROUP"
namespace = "1ebba5f6-49da-40cc-950b-f75c8f7d07b3"
cluster = "default"
username = "nacos"
password = "nacos"
}
}
此時(shí)再重新啟動(dòng)容器,訪問:http://192.168.200.200:8848/nacos 看seata是否已注冊(cè)到nacos中
3.2 客戶端注冊(cè)中心配置
項(xiàng)目中,我們需要使用注冊(cè)中心,添加如下配置即可:
參看:https://github.com/seata/seata/blob/1.3.0/script/client/spring/application.yml
registry:
type: nacos
nacos:
application: seata-server
server-addr: 192.168.200.200:8848
group : "SEATA_GROUP"
namespace: 52abf927-d578-45f2-ade5-144a59c93a29
username: "nacos"
password: "nacos"
此時(shí)就可以注釋掉配置中的default.grouplist=“192.168.200.200:8091”
4 Seata高可用
上面配置也只是將注冊(cè)中心換成了nacos,而且是單機(jī)版的,如果要想實(shí)現(xiàn)高可用,就得實(shí)現(xiàn)集群,集群就需要做一些動(dòng)作來保證集群節(jié)點(diǎn)間的數(shù)據(jù)同步(會(huì)話共享)等操作
需要準(zhǔn)備2個(gè)seata-server節(jié)點(diǎn),并且seata-server的事務(wù)日志存儲(chǔ)模式,共支持3種方式
- file【集群不可用】
- redis
- db
這里選擇redis存儲(chǔ)會(huì)話信息實(shí)現(xiàn)共享。
1、啟動(dòng)第二個(gè)seata-server節(jié)點(diǎn)
docker run --name seata-server-n2 -p 8092:8092 -d -e SEATA_IP=192.168.200.200 -e SEATA_PORT=8092 --restart=on-failure seataio/seata-server:1.3.0
2、進(jìn)入容器修改配置文件 registry.conf,添加注冊(cè)中心的配置
registry {
# file ...nacos ...eureka...redis...zk...consul...etcd3...sofa
type = "nacos"
nacos {
application = "seata-server"
serverAddr = "192.168.200.200:8848"
group = "SEATA_GROUP"
namespace = "1ebba5f6-49da-40cc-950b-f75c8f7d07b3"
cluster = "default"
username = "nacos"
password = "nacos"
}
}
3、修改seata-server 事務(wù)日志的存儲(chǔ)模式,resources/file.conf
基于redis來存儲(chǔ)集群每個(gè)節(jié)點(diǎn)的事務(wù)日志,通過docker運(yùn)行一個(gè)redis
docker run --name redis6.2 --restart=on-failure -p 6379:6379 -d redis:6.2
然后修改seata-server的file.conf,修改如下:文章來源:http://www.zghlxwxcb.cn/news/detail-493659.html
## transaction log store, only used in seata-server
store {
## store mode: file...db...redis
mode = "redis"
## file store property
file {
## store location dir
dir = "sessionStore"
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
maxBranchSessionSize = 16384
# globe session size , if exceeded throws exceptions
maxGlobalSessionSize = 512
# file buffer size , if exceeded allocate new buffer
fileWriteBufferCacheSize = 16384
# when recover batch read size
sessionReloadReadSize = 100
# async, sync
flushDiskMode = async
}
## database store property
db {
## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
datasource = "druid"
## mysql/oracle/postgresql/h2/oceanbase etc.
dbType = "mysql"
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://127.0.0.1:3306/seata"
user = "mysql"
password = "mysql"
minConn = 5
maxConn = 30
globalTable = "global_table"
branchTable = "branch_table"
lockTable = "lock_table"
queryLimit = 100
maxWait = 5000
}
## redis store property
redis {
host = "192.168.200.200"
port = "6379"
password = ""
database = "0"
minConn = 1
maxConn = 10
queryLimit = 100
}
}
如果基于DB來存儲(chǔ)seata-server的事務(wù)日志數(shù)據(jù),則需要?jiǎng)?chuàng)建數(shù)據(jù)庫seata,表信息如下:
https://github.com/seata/seata/blob/1.3.0/script/server/db/mysql.sql文章來源地址http://www.zghlxwxcb.cn/news/detail-493659.html
到了這里,關(guān)于SpringCloud Alibaba-Seata分布式事務(wù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!