Seata分布式事務(wù)之TM椅您、RM外冀、TC源碼分析

引言

本篇文章著重點(diǎn)在于調(diào)用流程分析,根據(jù)業(yè)務(wù)的發(fā)起到結(jié)束對(duì)Seata的TM掀泳、RM雪隧、TC模塊進(jìn)行源碼調(diào)用過程分析,選用Seata版本為0.7.1版本员舵,本篇文章分析均為Seata的AT事務(wù)脑沿,TM、RM模塊分析的比較單一马僻,只分析了邏輯調(diào)用庄拇,在分析TC模塊時(shí)候才具體的結(jié)合TM、RM模塊進(jìn)行邏輯調(diào)用的全過程交互分析

時(shí)序圖

筆者通過繪制時(shí)序圖韭邓,我們可以清晰的知道在集成Seata措近、ShardingSphere、Dubbo之后女淑,我們插入一條數(shù)據(jù)的整個(gè)內(nèi)部調(diào)用鏈邏輯

TM模塊分析

比較重要的類TransactionalTemplate瞭郑、DefaultGlobalTransaction、DefaultTransactionManager

查看TransactionalTemplate源碼可知

在全局事務(wù)攔截器GlobalTransactionalInterceptor中調(diào)用excute后鸭你,調(diào)用過程如上圖所示屈张,雖然注釋信息已經(jīng)解釋的很詳細(xì)了,首先獲取全局事務(wù)GlobalTransaction,默認(rèn)實(shí)現(xiàn)類為DefaultGlobalTransaction袱巨,然后開啟全局事務(wù)beginTransaction

TransactionManager是一個(gè)自定義SPI接口

默認(rèn)實(shí)現(xiàn)類為DefaultTransactionManager.繼續(xù)跟蹤begin過程

通過將消息發(fā)給TC阁谆,最終調(diào)用到AbstractRpcRemoting類下面的sendAsyncRequest消息發(fā)送接口,該方法中重要的地方,消息未發(fā)送就喚醒mergeLock同步的對(duì)象

然后就能找到AbstractRpcRemotingClient類下面的MergedSendRunnable消息發(fā)送線程愉老,因?yàn)樵摼€程是在初始化TMClient(TmRpcClient)和RMClient(RmRpcClient)的時(shí)候一并進(jìn)行初始化

知道了消息發(fā)送场绿,我們看看消息的返回結(jié)果是怎么得到的

消息的獲取運(yùn)用了Future模式,消息返回與賦值在哪俺夕?因?yàn)槲覀兿l(fā)送和接收肯定都是異步發(fā)送和接收裳凸,如果對(duì)Netty比較熟悉的同學(xué)可能會(huì)直接知道消息切入點(diǎn)贱鄙,消息接收位于AbstractRpcRemotingClient類channelRead接口劝贸,消息的返回和賦值都是在這里進(jìn)行,不熟悉Netty的同學(xué)也不必糾結(jié)逗宁,可以MessageFuture類查看哪里進(jìn)行setResultMessage的

根據(jù)消息ID從futures獲取MessageFuture并設(shè)置消息返回映九,因?yàn)槭荈uture模式,所以就拿到了消息的返回結(jié)果

我們已開啟全局事務(wù)為例分析了消息的收發(fā)瞎颗,在TC/Seata-server模塊中收發(fā)消息基本都一致件甥,所以不在進(jìn)一步分析TC模塊中的消息收發(fā)捌议。

我們著重分析TM模塊中的以下部分

我們通過時(shí)序圖可知,當(dāng)我們執(zhí)行業(yè)務(wù)時(shí)候引有,如果業(yè)務(wù)出現(xiàn)異常瓣颅,那么該異常會(huì)被捕獲,然后通知TC進(jìn)行全局回滾操作譬正,如果沒有異常宫补,那么就進(jìn)行全局二階段提交操作。但是可能會(huì)有同學(xué)比較好奇上圖中的rs = business.execute();這個(gè)是個(gè)回調(diào)接口曾我,回調(diào)實(shí)現(xiàn)類

這個(gè)簡單理解就是Spring AOP粉怕,會(huì)繼續(xù)調(diào)用增強(qiáng)鏈中的下一個(gè)(調(diào)用下一個(gè)攔截器),最后調(diào)用到我們的目標(biāo)執(zhí)行方法,如下圖所示

比如我們使用了Dubbo抒巢,那么當(dāng)我們執(zhí)行orderService.insertOrder(orderEntity);在這個(gè)方法體中贫贝,如果有異常,那么completeTransactionAfterThrowing會(huì)執(zhí)行蛉谜,這里簡單說明下稚晚,無論是當(dāng)前模塊的異常還是調(diào)用到下游出現(xiàn)異常,如使用Dubbo調(diào)用型诚,我們都可以理解成這些都是屬于同步調(diào)用蜈彼,上游模塊獲取到的異常信息可能會(huì)是rpc異常,也可能是反射異常俺驶,也可能是下游主動(dòng)拋出的異常幸逆,所以上游模塊只能獲取當(dāng)前模塊的完整異常信息,獲取到下游的異常不是完全正確的暮现。TM模塊分析完畢

RM模塊分析

比較重要的類DataSourceProxy还绘、ConnectionProxy、PreparedStatementProxy栖袋、ExecuteTemplate拍顷,大致調(diào)用關(guān)系為DataSourceProxy獲取連接ConnectionProxy,ConnectionProxy獲取預(yù)編譯PreparedStatementProxy塘幅,PreparedStatementProxy獲取SQL執(zhí)行器ExecuteTemplate昔案。我們已Insert舉例,查看ExecuteTemplate源碼

通過解析SQL得出不同的執(zhí)行器电媳,這里我們會(huì)執(zhí)行InsertExecutor踏揣,唯一可能需要注意的就是SelectForUpdateExecutor這個(gè)執(zhí)行器,簡單說下這個(gè)執(zhí)行器的業(yè)務(wù)場景匾乓,因?yàn)镽M是當(dāng)前模塊若沒有異常就會(huì)提交一階段數(shù)據(jù)入庫捞稿,但是,往往我們當(dāng)前模塊可能會(huì)有某些業(yè)務(wù)接口,這些業(yè)務(wù)接口需要的是二階段的最終數(shù)據(jù)娱局,所以這里我們就可以使用Seata的@GlobalLock全局鎖彰亥,這個(gè)會(huì)一直輪訓(xùn)直到獲取到二階段最終數(shù)據(jù).有興趣的同學(xué)可以仔細(xì)研究SelectForUpdateExecutor執(zhí)行器.返回來,我們還是繼續(xù)分析InsertExecutor衰齐,查看rs = executor.execute(args);源碼任斋,最終會(huì)調(diào)用到以下接口

判斷是否全局事務(wù),綁定XID耻涛,以及判斷是否有全局鎖注解仁卷,全局鎖注解使用上文已介紹

判斷是否自動(dòng)提交事務(wù),一般都是自動(dòng)犬第,若是自動(dòng)提交事務(wù)會(huì)進(jìn)行設(shè)置為false锦积,會(huì)調(diào)用到以下代碼

這個(gè)地方beforeImage主要是通過解析用戶執(zhí)行SQL,然后記錄執(zhí)行SQL前的快照歉嗓,然后執(zhí)行statementCallback.execute繼而調(diào)用到以下方法執(zhí)行SQL語句

afterImage同理類推丰介,記錄SQL執(zhí)行后的快照,prepareUndoLog準(zhǔn)備好undolog數(shù)據(jù),也就是回滾表undo_log中即將寫入的數(shù)據(jù)

connectionProxy.commit();調(diào)用到如下方法

首先判斷是否是全局事務(wù),若不是全局事務(wù)鉴分,也不是全局鎖哮幢,那么直接提交數(shù)據(jù),直接分析全局事務(wù)方法

首先注冊(cè)當(dāng)前分支事務(wù),然后判斷當(dāng)前上下文是否有undolog數(shù)據(jù),數(shù)據(jù)就是上文介紹的志珍,在執(zhí)行完SQL之后會(huì)執(zhí)行prepareUndoLog橙垢,內(nèi)部就會(huì)拼裝undo_log回滾表數(shù)據(jù)

最后執(zhí)行commit提交數(shù)據(jù),然后上報(bào)分支事務(wù)狀態(tài),至此整個(gè)RM分支本地事務(wù)一階段已完成伦糯,寫到這里柜某,可能還是會(huì)有同學(xué)有疑問,比如register注冊(cè)分支事務(wù)是如何和TC模塊交互的敛纲,TC模塊的調(diào)用流程又是什么喂击!這些我們?cè)诤笪闹vTC模塊一起分析下流程

TC模塊分析

比較重要的類AbstractTCInboundHandler、DefaultCoordinator淤翔、DefaultCore

我們看看Server類都做了什么事情.因?yàn)門C模塊基于Netty框架翰绊,所以在研究TC模塊的時(shí)候,若對(duì)Netty框架完全不了解的同學(xué)旁壮,可以先閱讀下Netty框架相關(guān)文檔监嗜,比如定義消息接收類,每個(gè)回調(diào)代表什么意思抡谐,發(fā)送消息給客戶端如何進(jìn)行裁奇。有了一定了解之后在閱讀TC模塊會(huì)更清晰。

言歸正傳童叠,通過Server類框喳,我們看到通過創(chuàng)建和啟動(dòng)RpcServer來進(jìn)行和TM和RM交互,繼續(xù)分析厦坛,設(shè)置RpcServer的handler-> DefaultCoordinator協(xié)調(diào)器.DefaultCoordinator繼承AbstractTCInboundHandler五垮。然后RpcServer繼承AbstractRpcRemotingServer,然后設(shè)置Netty框架所需eventLoopGroupWorker杜秸、eventLoopGroupBoss放仗,最后啟動(dòng)

所有消息入口為AbstractRpcRemoting類中channelRead方法,如果有同學(xué)說為什么是這個(gè)撬碟,Netty框架規(guī)則就是這樣诞挨!

下面我們通過RM模塊注冊(cè)一階段本地事務(wù)舉例,詳細(xì)分析整個(gè)RM和TC交互過程

通過查看源碼最終調(diào)用到以下方法

這個(gè)resourceManagers在哪里賦值的呢蛤?跟蹤發(fā)現(xiàn)是靜態(tài)初始化實(shí)例通過自定義SPI擴(kuò)展接口通過BranchType進(jìn)行賦值

我們上面獲取的是AT類型ResourceManager惶傻,所以實(shí)現(xiàn)類為DataSourceManager,最終調(diào)用到AbstractResourceManager類下branchRegister方法

消息發(fā)送sendMsgWithResponse在TM模塊已經(jīng)介紹過,忘了的同學(xué)可以閱讀上文中的分析其障。

我們著重講解消息發(fā)送到TC之后银室,TC模塊中的業(yè)務(wù)處理。

我們簡要查看下查看下TC模塊的UML類圖

我們通過類圖發(fā)現(xiàn),我們比較關(guān)心的就RpcServer、AbstractRpcRemotingServer二蓝、AbstractRpcRemoting這3個(gè)類奶陈,那我們查看下我們分支事務(wù)注冊(cè)是如何進(jìn)行的

RM模塊發(fā)送請(qǐng)求到TC最終執(zhí)行到以下方法

然后TC模塊接收消息入口為RpcServer類中以下方法

因?yàn)槲覀兪亲?cè)RM分支事務(wù)事件,所以直接會(huì)執(zhí)行super父類進(jìn)行消息解析和分發(fā)伦泥,查看父類如何處理的。

因?yàn)槲覀兊腞M分支事務(wù)注冊(cè)屬于請(qǐng)求事件,所以最終會(huì)執(zhí)行以下方法

messageExecutor為Server啟動(dòng)類中定義的線程池執(zhí)行器

最終調(diào)用到RpcServer中dispatch方法進(jìn)行消息的分發(fā)處理

查看RpcServer初始化接口可知

消息被派發(fā)到DefaultServerMessageListenerImpl類中進(jìn)行處理否过,繼續(xù)查看

我們的消息屬于MergedWarpMessage類型,繼續(xù)調(diào)用results[i] = transactionMessageHandler.onRequest(subMessage, rpcContext);這個(gè)transactionMessageHandler就是DefaultCoordinator(核心類之一惭蟋,事務(wù)協(xié)調(diào)器)叠纹。繼續(xù)分析

這個(gè)地方簡單解釋下,我們的請(qǐng)求BranchRegisterRequest繼承AbstractTransactionRequestToTC敞葛,然后就會(huì)調(diào)用到以下方法體

這個(gè)handler就是DefaultCoordinator本身實(shí)例誉察,因?yàn)镈efaultCoordinator繼承AbstractTCInboundHandler,所以會(huì)執(zhí)行到AbstractTCInboundHandler類中的以下方法

繼而調(diào)用到DefaultCoordinator類

最終調(diào)用到DefaultCore類方法

這個(gè)地方很關(guān)鍵,需要重點(diǎn)分析! 大致調(diào)用如下:

1:通過Xid獲取全局事務(wù)GlobalSession,GlobalSession全局事務(wù)加鎖調(diào)用邏輯

2:判斷GlobalSession狀態(tài)惹谐,判斷狀態(tài)是否可用或者有沒有發(fā)起全局事務(wù)(Begin狀態(tài))

3:創(chuàng)建BranchSession分支事務(wù)持偏,其中l(wèi)ockKeys簡單理解就是操作的哪些行數(shù)據(jù)字段

4:BranchSession分支事務(wù)加鎖,內(nèi)部加鎖大致為根據(jù)pk主鍵值+操作的行數(shù)據(jù)進(jìn)行加鎖(行鎖)氨肌,加鎖邏輯比較復(fù)雜鸿秆,可以在seata.io官網(wǎng)進(jìn)行查看原理圖,如果分支事務(wù)獲取鎖失敗了,那么代表有其他分支事務(wù)正在處理業(yè)務(wù)邏輯怎囚,拋出鎖沖突異常信息,該異常會(huì)被ConnectionProxy的以下代碼捕獲

然后拋出LockConflictException異常

最終AbstractDMLBaseExecutor.executeAutoCommitTrue捕獲這個(gè)LockConflictException鎖沖突異常.異常處理為:1->回滾數(shù)據(jù)卿叽。2->重試獲取分支事務(wù)鎖,默認(rèn)重試30次桥胞,每次sleep間隔時(shí)間10ms,直到成功執(zhí)行commit操作或者拋出鎖超時(shí),若拋出鎖超時(shí)則會(huì)一直上拋SQLException到TM發(fā)起全局事務(wù)的模塊,然后由TM模塊發(fā)起全局回滾消息到TC,由TC下發(fā)分支事務(wù)回滾消息

5:保存全局事務(wù)GlobalSession對(duì)應(yīng)的分支事務(wù)BranchSession數(shù)據(jù)到store考婴,根據(jù)SPI接口判斷采用file本地文件保存還是按照db數(shù)據(jù)庫進(jìn)行保存贩虾,以便于TC服務(wù)端自檢操作

6:返回BranchSession分支事務(wù)id

重點(diǎn):上文對(duì)分支事務(wù)BranchSession加鎖了,還沒有釋放鎖沥阱,下文將分析BranchSession分支事務(wù)鎖的釋放

我們?cè)谏衔闹械?步獲取到分支事務(wù)id后缎罢,我們繼續(xù)分析后續(xù)操作

1:注冊(cè)分支事務(wù)register()方法,獲取到分支事務(wù)id考杉,設(shè)置當(dāng)前ConnectionContext上下文的分支事務(wù)id

2:判斷當(dāng)前ConnectionContext上下文是否有保存的undo_log數(shù)據(jù)策精,若有數(shù)據(jù)則將數(shù)據(jù)寫入undo_log表

封裝BranchUndoLog分支事務(wù)數(shù)據(jù)

將數(shù)據(jù)插入undo_log表,狀態(tài)為Normal狀態(tài),該狀態(tài)有Normal崇棠、GlobalFinished 兩種狀態(tài),后文分支事務(wù)回滾時(shí)候著重講解這兩種狀態(tài)

3:提交當(dāng)前分支事務(wù)(本地事務(wù))

4:上報(bào)分支事務(wù)(本地事務(wù))一階段完成狀態(tài)PhaseOne_Done

5:清空上下文數(shù)據(jù)

假設(shè)各個(gè)分支事務(wù)均未出現(xiàn)異常咽袜,各個(gè)分支事務(wù)均已完成一階段并且上報(bào)PhaseOne_Done狀態(tài),那么發(fā)起全局事務(wù)TM模塊將執(zhí)行以下邏輯(TransactionalTemplate.commitTransaction)

然后調(diào)用到DefaultGlobalTransaction.commit,最終調(diào)用到DefaultTransactionManager.commit

和begin發(fā)起全局事務(wù)調(diào)用過程基本一致枕稀,不清楚流程的同學(xué)可以查看上文發(fā)起begin的調(diào)用過程酬蹋。調(diào)用順序:

1:DefaultTransactionManager.commit->發(fā)送commit消息

2:AbstractRpcRemoting.sendRequest->封裝/發(fā)送請(qǐng)求數(shù)據(jù)

3:RpcServer.channelRead->TC/seata-server獲取請(qǐng)求數(shù)據(jù)

4:AbstractRpcRemoting.channelRead->TC/seata-server獲取請(qǐng)求數(shù)據(jù)

5:RpcServer.dispatch->消息分發(fā)處理

6:DefaultServerMessageListenerImpl.onTrxMessage->消息監(jiān)聽實(shí)現(xiàn)類,如:對(duì)RpcMessage消息相關(guān)處理

7:DefaultCoordinator.onRequest設(shè)置消息Handler處理類

8:AbstractTCInboundHandler.handle消息映射處理,根據(jù)消息請(qǐng)求類型進(jìn)行映射處理抽莱,commit對(duì)應(yīng)的請(qǐng)求類型為GlobalCommitRequest

9:DefaultCoordinator.doGlobalCommit

10:DefaultCore.commit分析下

10-1:根據(jù)xid獲取全局事務(wù)范抓,注意這里是重點(diǎn),分支事務(wù)鎖釋放第一現(xiàn)場

此步驟會(huì)執(zhí)行g(shù)lobalSession.setActive(false);設(shè)置當(dāng)前全局事務(wù)為不可用狀態(tài)食铐,這樣就不會(huì)有分支事務(wù)繼續(xù)注冊(cè)進(jìn)globalSession匕垫。釋放當(dāng)前分支事務(wù)鎖,還記得上文講述過在分支事務(wù)提交commit時(shí)候需要先向TC注冊(cè)當(dāng)前分支事務(wù)嗎虐呻?這個(gè)注冊(cè)過程就涉及到分支事務(wù)鎖象泵,比如某個(gè)全局事務(wù)中的分支事務(wù)和另外一個(gè)全局事務(wù)中的分支事務(wù),都在操作某一行數(shù)據(jù)斟叼,那么就要等到這個(gè)分支事務(wù)鎖釋放后偶惠,其他分支事務(wù)才能進(jìn)行Commit操作,然后去獲取分支事務(wù)鎖.然后判斷當(dāng)前xid對(duì)應(yīng)的全局事務(wù)是否是發(fā)起狀態(tài)(begin)

10-2:判斷當(dāng)前全局事務(wù)是否可以異步執(zhí)行朗涩,判斷是否異步就是判斷是否是TCC或者是AT事務(wù)類型忽孽,是AT事務(wù)類型則可以異步執(zhí)行

將全局事務(wù)放入Map集合中

10-3:在啟動(dòng)TC/seata-server時(shí)初始化了以下方法

然后開啟各種類型的定時(shí)任務(wù)

異步提交全局事務(wù)就將在如下方法中執(zhí)行

10-4:遍歷全局事務(wù)sessionMap集合,循壞調(diào)用DefaultCore.doGlobalCommit,該過程相對(duì)復(fù)雜谢床,那就繼續(xù)分析分析

10-5:eventBus主要數(shù)據(jù)監(jiān)控統(tǒng)計(jì)作用

10-6:遍歷分支事務(wù),執(zhí)行resourceManagerInbound.branchCommit

10-7:調(diào)用DefaultCoordinator.branchCommit

10-8:RpcServer.sendSyncRequest發(fā)送消息給RM分支事務(wù)模塊

10-9:AbstractRpcRemotingClient.channelRead接收消息

10-10:AbstractRpcRemotingClient.dispatch消息分發(fā)處理

10-11:RmMessageListener.onMessage該消息監(jiān)聽兄一,該監(jiān)聽器在RMClient中進(jìn)行初始化設(shè)置

10-12:RmMessageListener.handleBranchCommit執(zhí)行以下方法

10-13:這個(gè)handler.onRequest,handler在初始化RMClient中進(jìn)行設(shè)置,所以該handler對(duì)象即DefaultRMHandler识腿,隨后調(diào)用過程為DefaultRMHandler父類AbstractRMHandler.onRequest->DefaultRMHandler.handle->RMHandlerAT父類AbstractRMHandler.handle->AbstractRMHandler.doBranchCommit最終調(diào)用如下方法

10-14:getResourceManager()為模版方法出革,實(shí)現(xiàn)類為RMHandlerAT類中,最終獲取到的ResourceManager實(shí)現(xiàn)類為DataSourceManager

10-15:DataSourceManager.branchCommit將分支事務(wù)加入asyncWorker定時(shí)任務(wù)中

asyncWorker在SPI接口加載DataSourceManager時(shí)初始化

10-16:最終調(diào)用asyncWorker.branchCommit

Offer操作加入隊(duì)列渡讼,然后直接返回分支狀態(tài)骂束,即PhaseTwo_Committed狀態(tài)

簡要分析下分支事務(wù)二階段提交做了哪些事情吧耳璧,便于更好理解流程

10-16-1:判斷隊(duì)列是否有任務(wù),若有任務(wù)展箱,則封裝mappedContexts集合數(shù)據(jù)

10-16-2:遍歷mappedContexts集合旨枯,獲取DataSourceProxy數(shù)據(jù)源代理對(duì)象,然后獲取Connection數(shù)據(jù)庫連接對(duì)象

10-16-3: 最終執(zhí)行UndoLogManager.batchDeleteUndoLog刪除undo_log表中xid和branch_id字段同時(shí)出現(xiàn)在xids集合和branchIds集合中的數(shù)據(jù)行,最終分支事務(wù)完成二階段提交

10-17:在10-16步驟中析藕,分支事務(wù)返回PhaseTwo_Committed狀態(tài)后,在10-12步驟中

RmMessageListener.handleBranchCommit方法中通過sender.sendResponse(request, serverAddress, resultMessage)將handler.onRequest結(jié)果發(fā)給TC/seata-server

10-18:TC/seata-server接收數(shù)據(jù)流程簡要概括,RpcServer.channelRead->消息賦值

10-19:最終我們10-6步驟就得到了BranchStatus分支事務(wù)狀態(tài),即PhaseTwo_Committed狀態(tài)

11:TC/seata-server獲取到PhaseTwo_Committed狀態(tài)之后或者其他狀態(tài)會(huì)按照不同策略進(jìn)行處理召廷,我們簡要分析PhaseTwo_Committed狀態(tài)

分析globalSession.removeBranch(branchSession)做了哪些事情

12:往sessionStore記錄當(dāng)前分支狀態(tài)凳厢,如file本地文件或者db數(shù)據(jù)庫账胧,釋放當(dāng)前分支事務(wù)鎖,最后分支事務(wù)集合中刪除當(dāng)前分支事務(wù),其實(shí)這個(gè)地方先紫,筆者也有一些疑慮治泥,就是上文中commit第一現(xiàn)場時(shí)候已經(jīng)釋放了分支事務(wù)鎖,為何這里還要進(jìn)行釋放遮精?筆者根據(jù)Rollback回滾初步判斷居夹,可能是為了處理Rollback回滾,因?yàn)榛貪L過程第一現(xiàn)場只是將globalSession設(shè)置為不可用狀態(tài)本冲,所以需要在removeBranch中進(jìn)行鎖釋放

至此准脂,整個(gè)Commit過程分析完畢,涵蓋分支事務(wù)一階段檬洞,分支事務(wù)二階段和TC服務(wù)端的一系列數(shù)據(jù)交互過程

上文分析了Commit過程狸膏,我們接著分析全局回滾Rollback過程,觸發(fā)全局回滾Rollback大致分為兩類:1:全局事務(wù)發(fā)起端內(nèi)部異常被捕獲添怔。2:發(fā)起端調(diào)用下游業(yè)務(wù)端湾戳,下游業(yè)務(wù)端主動(dòng)上拋各種異常信息被發(fā)起端捕獲.

最終在發(fā)起端TransactionalTemplate.completeTransactionAfterThrowing進(jìn)行異常捕獲

最終發(fā)起全局回滾請(qǐng)求

和上文講述的TransactionalTemplate.commitTransaction全局提交流程基本完全一致

大致調(diào)用過程為:

1:DefaultGlobalTransaction.rollback,最終調(diào)用到DefaultTransactionManager.rollback

2:AbstractRpcRemoting.sendRequest->封裝/發(fā)送請(qǐng)求數(shù)據(jù)

3:RpcServer.channelRead->TC/seata-server獲取請(qǐng)求數(shù)據(jù)

4:AbstractRpcRemoting.channelRead->TC/seata-server獲取請(qǐng)求數(shù)據(jù)

5:RpcServer.dispatch->消息分發(fā)處理

6:DefaultServerMessageListenerImpl.onTrxMessage->消息監(jiān)聽實(shí)現(xiàn)類,如:對(duì)RpcMessage消息相關(guān)處理

7:DefaultCoordinator.onRequest設(shè)置消息Handler處理類

8:AbstractTCInboundHandler.handle消息映射處理,根據(jù)消息請(qǐng)求類型進(jìn)行映射處理广料,rollback對(duì)應(yīng)的請(qǐng)求類型為GlobalRollbackRequest

9:DefaultCoordinator.doGlobalRollback

10:DefaultCore.rollback分析下

11:根據(jù)xid獲取全局事務(wù)砾脑,然后設(shè)置當(dāng)前globalSession不可用,然后判斷當(dāng)前xid對(duì)應(yīng)的全局事務(wù)是否是發(fā)起狀態(tài)(begin)

12:DefaultCore.doGlobalRollback

13:遍歷分支事務(wù),執(zhí)行resourceManagerInbound.branchRollback

14:調(diào)用DefaultCoordinator.branchRollback

15:RpcServer.sendSyncRequest發(fā)送消息給RM分支事務(wù)模塊

16:AbstractRpcRemotingClient.channelRead接收消息

17:AbstractRpcRemotingClient.dispatch消息分發(fā)處理

18:RmMessageListener.onMessage該消息監(jiān)聽艾杏,該監(jiān)聽器在RMClient中進(jìn)行初始化設(shè)置

19:RmMessageListener.handleBranchRollback執(zhí)行以下方法

20:這個(gè)handler.onRequest,handler在初始化RMClient中進(jìn)行設(shè)置韧衣,所以該handler對(duì)象即DefaultRMHandler,隨后調(diào)用過程為DefaultRMHandler父類

AbstractRMHandler.onRequest->DefaultRMHandler.handle->RMHandlerAT父類AbstractRMHandler.handle->AbstractRMHandler.doBranchRollback最終調(diào)用如下方法

21:getResourceManager()為模版方法购桑,實(shí)現(xiàn)類為RMHandlerAT類中汹族,最終獲取到的ResourceManager實(shí)現(xiàn)類為DataSourceManager

22:DataSourceManager.branchRollback

23:UndoLogManager.undo回滾步驟著重分析

24:查詢undo_log表是否存在branchId、xid對(duì)應(yīng)的數(shù)據(jù)

25:canUndo判斷當(dāng)前數(shù)據(jù)狀態(tài)是否是Normal正常狀態(tài)其兴,如不是Normal狀態(tài)則跳出while循壞顶瞒,Normal狀態(tài)是分支事務(wù)插入,是正常執(zhí)行流程元旬、GlobalFinished狀態(tài)為異常狀態(tài)榴徐,是全局事務(wù)發(fā)起的防御性插入,比如全局回滾時(shí)守问,分支事務(wù)還沒執(zhí)行,此時(shí)就需要插入防御性數(shù)據(jù),用主鍵沖突來防止異常分支事務(wù)的插入坑资,起了一個(gè)占位作用

26:解析undo_log數(shù)據(jù)行耗帕,獲取TableMeta表數(shù)據(jù),主要封裝數(shù)據(jù)為表的所有列名字段信息allColumns袱贮,表的所有索引信息allIndexes

27:根據(jù)執(zhí)行器進(jìn)行執(zhí)行仿便,如:Insert操作會(huì)使用afterImage數(shù)據(jù)進(jìn)行刪除當(dāng)前數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行數(shù)據(jù)回滾操作

28:如果undo_log表中存在branchId、xid對(duì)應(yīng)的數(shù)據(jù)則刪除分支事務(wù)undo_log表中branchId攒巍、xid對(duì)應(yīng)的數(shù)據(jù)嗽仪,如果undo_log中不存在branchId、xid對(duì)應(yīng)的數(shù)據(jù)則防御性插入一條branchId柒莉、xid數(shù)據(jù)

注釋信息已經(jīng)解釋的很清晰insertUndoLogWithGlobalFinished的作用闻坚,主要起防御性的作用,因?yàn)榉种聞?wù)和全局事務(wù)都是異步RPC調(diào)用兢孝,所以為了防止一些異常情況進(jìn)行的占位操作

至此對(duì)Seata AT模式整個(gè)TM,RM,TC調(diào)用流程分析完畢窿凤,若有不正確的地方歡迎指出!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末跨蟹,一起剝皮案震驚了整個(gè)濱河市雳殊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌窗轩,老刑警劉巖夯秃,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異品姓,居然都是意外死亡寝并,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門腹备,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衬潦,“玉大人,你說我怎么就攤上這事植酥《频海” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵友驮,是天一觀的道長漂羊。 經(jīng)常有香客問我,道長卸留,這世上最難降的妖魔是什么走越? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮耻瑟,結(jié)果婚禮上旨指,老公的妹妹穿的比我還像新娘赏酥。我一直安慰自己,他們只是感情好谆构,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布裸扶。 她就那樣靜靜地躺著,像睡著了一般搬素。 火紅的嫁衣襯著肌膚如雪呵晨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天熬尺,我揣著相機(jī)與錄音摸屠,去河邊找鬼。 笑死猪杭,一個(gè)胖子當(dāng)著我的面吹牛餐塘,可吹牛的內(nèi)容都是我干的妥衣。 我是一名探鬼主播皂吮,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼税手!你這毒婦竟也來了蜂筹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤芦倒,失蹤者是張志新(化名)和其女友劉穎艺挪,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兵扬,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡麻裳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了器钟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片津坑。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖傲霸,靈堂內(nèi)的尸體忽然破棺而出疆瑰,到底是詐尸還是另有隱情,我是刑警寧澤昙啄,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布穆役,位于F島的核電站,受9級(jí)特大地震影響梳凛,放射性物質(zhì)發(fā)生泄漏耿币。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一韧拒、第九天 我趴在偏房一處隱蔽的房頂上張望淹接。 院中可真熱鬧秘狞,春花似錦、人聲如沸蹈集。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拢肆。三九已至减响,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郭怪,已是汗流浹背支示。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鄙才,地道東北人颂鸿。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像攒庵,于是被迫代替她去往敵國和親嘴纺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容