本文基于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的執行過程。
- RM啟動時,讀取配置spring.cloud.alibaba.seat.tx-service-group,得到本RM所屬事務分組,下面假設事務分組為my_test_tx_group;
- 将my_test_tx_group與service.vgroupMapping組合成service.vgroupMapping.my_test_tx_group,使用該字元串查找配置資訊,找到以該字元串為key的配置,讀取對應的value值,假設該value值為“default”;
- 在“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叢集。