在上一篇中通過閱讀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發請求,回滾分支事務,還原資料

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/536070.html
標籤:Java
