Seata 1.5.2 原始碼學習(Client端)

2022-11-18 21:00:29

在上一篇中通過閱讀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去執行

可以看到:

  1. 封裝成一個Phase2Context物件,並將其放入佇列中
  2. 如果放入成功,則立即返回提交成功,後續交由定時任務執行
  3. 如果放入失敗,則主動觸發定時任務先執行一次,以便騰出空間來,待執行完後,佇列裡面就有空間了,再將任務放入佇列,等待下一次定時任務執行
  4. 定時任務1秒執行一次,執行的時候將佇列中的任務取出,然後迴圈遍歷分段執行
  5. 執行的過程就是刪除對應事務的undo log
  6. 如果過程中拋異常,則將任務再放回佇列中

所以,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發請求,回滾分支事務,還原資料