在上一篇中通過閱讀Seata服務端的代碼,我們瞭解到TC是如何處理來自客戶端的請求的,今天這一篇一起來瞭解一下客戶端是如何處理TC發過來的請求的。要想搞清楚這一點,還得從GlobalTransactionScanner說起。 啟動的時候,會調用GlobalTransactionScanner#ini ...
在上一篇中通過閱讀Seata服務端的代碼,我們瞭解到TC是如何處理來自客戶端的請求的,今天這一篇一起來瞭解一下客戶端是如何處理TC發過來的請求的。要想搞清楚這一點,還得從GlobalTransactionScanner說起。
啟動的時候,會調用GlobalTransactionScanner#initClient()方法,在initClient()中初始化TM和RM
TM初始化,主要是註冊各種處理器,最終構造一個處理器映射表,不再多說
HashMap<Integer/*MessageType*/, Pair<RemotingProcessor, ExecutorService>> processorTable = new HashMap<>(32);
重點關註RM初始化
RM初始化過程中,設置了 resourceManager 和 transactionMessageHandler,然後也是註冊各種處理器,最終也是構造一個消息類型和對應的處理器的一個映射關係
可以看到,圖中上半部分是RM特有的,下半部分與TM初始化註冊處理器類似
然鵝,真正處理請求的還是靠調用各個處理器中的handler.onRequest()方法,於是問題的關鍵就很明顯了,就在於handler
1. ResourceManager
在瞭解ResourceManager之前,讓我們首先瞭解一下ResourceManagerInbound和ResourceManagerOutbound
ResourceManagerInbound是處理接收到TC的請求的,是TC向RM發請求
ResourceManagerOutbound是處理流出的消息的,是RM向TC發請求
ResourceManager繼承了二者,所以既負責向TC發請求,又負責接收從TC來的請求。
還記得剛纔在RMClient中是怎麼獲取ResourceManager的嗎?是調用DefaultResourceManager.get()獲取的
DefaultResourceManager.get()得到的是一個單例DefaultResourceManager,創建DefaultResourceManager的時候會構建一個分支類型與ResourceManager的一個Map
2. TransactionMessageHandler
TransactionMessageHandler負責處理接收到的RPC消息
前面在 RMClient 中通過 DefaultRMHandler.get() 獲取 TransactionMessageHandler
3. 消息處理
RMClient#init()的時候new了一個RmNettyRemotingClient
這裡要記住,rmNettyRemotingClient的兩個成員變數此時已經被賦值了:
- resourceManager是DefaultResourceManager,
- transactionMessageHandler是DefaultRMHandler
RmNettyRemotingClient構造方法中調用父類AbstractNettyRemotingClient的構造方法
可以看到,根據收到的RPC消息類型,從processorTable中獲取對應的Processor,最後調用對應RemotingProcessor的process()方法進行處理消息
RemotingProcessor的實現類很多,挑其中一個RmBranchCommitProcessor看一下
真相大白,最終還是調DefaultRMHandler#handle()
捋一下這個過程
最後,補充一個,this為什麼是DefaultRMHandler
補充二:AbstractTransactionRequestToRM
4. 分支事務提交(二階段)
交給AsyncWorker去執行
可以看到:
- 封裝成一個Phase2Context對象,並將其放入隊列中
- 如果放入成功,則立即返回提交成功,後續交由定時任務執行
- 如果放入失敗,則主動觸發定時任務先執行一次,以便騰出空間來,待執行完後,隊列裡面就有空間了,再將任務放入隊列,等待下一次定時任務執行
- 定時任務1秒執行一次,執行的時候將隊列中的任務取出,然後迴圈遍歷分段執行
- 執行的過程就是刪除對應事務的undo log
- 如果過程中拋異常,則將任務再放回隊列中
所以,RM收到TC發的提交指令後,僅僅只是刪除該事務的undo_log表記錄
5. 分支事務回滾(二階段)
與提交類似
所以,回滾就是根據事務的undo_log進行回滾
6. 總結
1、啟動時,自動代理數據源,應用GlobalTransactionalInterceptor,初始化TM和RM
2、進入@GlobalTransactional業務方法時,TM向TC發請求申請開啟全局事務,並獲得全局事務ID
3、業務方法調用遠程服務介面完成業務處理
4、RM執行本地邏輯,註冊分支事務,獲取全局鎖,成功後提交本地事務並寫入undo_log,本地事務提交成功後向TC報告分支事務
5、TM發起全局事務提交請求,TC向所有已註冊的RM發請求,讓RM進行分支提交,刪除本地undo_log
6、若執行失敗,TM發起全局事務回滾,TC向所有RM發請求,回滾分支事務,還原數據