天天看點

Seata解析-TM、RM如何與TC叢集通訊一、RM與叢集通訊二、TM與叢集通訊三、叢集各機器間如何互動四、事務分組

本文基于seata 1.3.0版本

在AT模式下,服務端叢集部署很簡單,如果叢集是在一台機器上,複制一份程式,修改一下端口号,啟動即可。

因為叢集部署很簡單,本文不再對部署做介紹,本文向介紹一下TM、RM如何與叢集建立連接配接,以及叢集中各機器如何通訊。

文章目錄

  • 一、RM與叢集通訊
  • 二、TM與叢集通訊
  • 三、叢集各機器間如何互動
  • 四、事務分組

一、RM與叢集通訊

RM啟動的時候要向TC注冊,根據事務分組從注冊中心找到該分組對應的服務叢集,之後與叢集中的每台機器建立連接配接,并向每台機器注冊RM。

與叢集建立連接配接是在NettyClientChannelManager的reconnect方法中完成的,代碼如下:

//該方法的入參是事務分組
	void reconnect(String transactionServiceGroup) {
        List<String> availList = null;
        try {
            //從注冊中心獲得與事務分組對應的叢集中每台機器位址
            //transactionServiceGroup是事務分組,通過配置spring.cloud.alibaba.seat.tx-service-group指定
            availList = getAvailServerList(transactionServiceGroup);
        } catch (Exception e) {
            LOGGER.error("Failed to get available servers: {}", e.getMessage(), e);
            return;
        }
        //如果叢集中沒有機器提供服務,那麼列印出日志,seata啟動定時任務線程每過一段時間會重新檢視叢集中是否有機器
        if (CollectionUtils.isEmpty(availList)) {
            String serviceGroup = RegistryFactory.getInstance()
                                                 .getServiceGroup(transactionServiceGroup);
            LOGGER.error("no available service '{}' found, please make sure registry config correct", serviceGroup);
            return;
        }
        //周遊每台機器
        for (String serverAddress : availList) {
            try {
                //建立與TC的連接配接,并注冊RM
                acquireChannel(serverAddress);
            } catch (Exception e) {
                LOGGER.error("{} can not connect to {} cause:{}",FrameworkErrorCode.NetConnect.getErrCode(), serverAddress, e.getMessage(), e);
            }
        }
    }
           

注意RM是與叢集中的每台機器都建立連接配接,那麼之後RM與TC通訊時,比如注冊分支事務,RM是與叢集中的一條機器通訊還是與所有的機器通訊?

答案是一台機器。

RM與TC通訊時,首先也是根據事務分組從注冊中心找到叢集機器清單,之後使用負載均衡政策,從清單中選出一台機器,因為已經與每台TC建立了連接配接,是以這裡不用再建立連接配接而是直接使用。seata提供了兩種負載均衡政策:随機和輪詢。可以參見的代碼AbstractNettyRemotingClient的sendSyncRequest方法。

二、TM與叢集通訊

TM與叢集通訊和RM基本是一緻。

TM啟動時,也是根據事務分組從注冊中心找到叢集機器清單,然後與每台機器建立連接配接,并向其注冊TM資訊。

啟動後的通訊也是根據負載均衡政策與其中一台機器通訊。而且對于同一個全局事務,可能TM通路的機器前後是不同的。TM和RM與叢集通訊使用的代碼都是一樣的。

三、叢集各機器間如何互動

RM、TM在啟動後都是與叢集中一台機器通訊,而且就同一個全局事務前後互動的機器可能不同,那麼事務資料如何在叢集中共享?另外為什麼RM或者TM注冊必須向每台機器注冊,而之後的互動則不用?

先來看第一個問題。服務端收到TM或者RM的請求後,如果是事務注冊請求,則會将注冊的事務資料寫入檔案、redis或者資料庫,具體寫入哪個可以使用store.mode配置。之後事務的送出、復原或者查詢都是根據事務XID從檔案、redis或者資料庫查詢出事務資料,然後更新的。是以如果服務端叢集部署,事務資料存儲必須使用redis或者資料庫。

第二個問題,為什麼必須向每台機器都注冊。因為注冊資訊是記錄在記憶體中的,不寫入資料庫,而且各個機器之間也沒有通過網絡交換注冊資訊,注冊資訊記錄在ChannelManager的IDENTIFIED_CHANNELS屬性中。

四、事務分組

下面先詳細介紹一下RM如何查找TC機器清單,這也是上面代碼中方法getAvailServerList的執行過程。

  1. RM啟動時,讀取配置spring.cloud.alibaba.seat.tx-service-group,得到本RM所屬事務分組,下面假設事務分組為my_test_tx_group;
  2. 将my_test_tx_group與service.vgroupMapping組合成service.vgroupMapping.my_test_tx_group,使用該字元串查找配置資訊,找到以該字元串為key的配置,讀取對應的value值,假設該value值為“default”;
  3. 在“default”前添加強定内容形成一個字元串,然後通路注冊中心,從注冊中心查找該字元串對應的TC機器清單,比如注冊中心使用的是zk,TC啟動時會在zk上建立一個/registry/zk/default的節點(節點名通過register.conf的cluster配置),并将自己的ip注冊到該節點,之後RM啟動,并找到“default”值,在“default”前拼接“/registry/zk”,然後通路zk上該節點,便可以獲得TC機器清單。

通過上述流程可以看到,事務分組是一個與叢集相關的概念,可以将若幹個RM、TM、TC形成一個邏輯分組,相當于一個資源機關,可以做資源隔離。

事務分組并不是直接映射到TC清單,而是中間經過service.vgroupMapping配置中轉,這樣做的好處是,service.vgroupMapping配置可以放到配置中心,一旦TC叢集發生故障,通過修改配置中心值,在不停機的情況下切換到另一個TC叢集。