認識Seata
Seata 是一款開源的分佈式事務解決方案,致力於提供高性能和簡單易用的分佈式事務服務。Seata 將爲用戶提供了 AT、TCC、SAGA 和 XA 事務模式,爲用戶打造一站式的分佈式解決方案。
Seata的TXC模型
根據上圖可知整個TXC模型有三個重要的組件
- TC 事務協調器,維護全局和分支事務的狀態,驅動全局事務提交或回滾。(單獨部署)
- TM 事務管理器 定義全局事務的範圍:開始全局事務、提交或回滾全局事務。
- RM 資源管理器 管理分支事務處理的資源,與TC交談以註冊分支事務和報告分支事務的狀態,並驅動分支事務提交或回滾。
簡單理解就是TM事務管理器通過RPC與TC通訊請求開啓一個全局事務
簡單理解過程就是: Business作爲服務起始方(此時它是TM)發起全局事務並註冊到TC。在調用協同服務時,協同服務的事務分支事務會先完成階段一的事務提交或回滾,並生成事務回滾的undo_log日誌,同時註冊當前服務到TC並上報其事務狀態,歸併到同一個業務的全局事務中。此時若沒有問題繼續下一個服務的調用,期間任何服務的分支事務回滾,都會通知到TC,TC在通知全局事務包含的所有已完成一階段提交的分支事務回滾。如果所有分支事務都正常,最後回到全局事務發起方時,也會通知到TC,TC在通知全局事務包含的所有分支刪除回滾日誌。在這個過程中爲了解決寫隔離和度隔離的問題會涉及到TC管理的全局鎖。
那麼全局事務是如何在服務中傳遞的呢?實際在TM向TC請求開啓一個全局事務的時候,TC會響應一個全局事務XID,只需要TM在調用其他協同服務時把XID傳遞給協同服務,這樣就可以實現全局事務在分佈式服務中傳播,以及分支事務屬於哪個全局事務。
Seata目前已經支持許多框架中的XID的自動傳遞了
-
dubbo
-
spring cloud
-
sofa-rpc
用戶在使用Seata的時候對於XID的傳遞完全是無感知。
上文提到Seata中三個重要的組件TC TM RM
.
其中TC作爲事務協調者, 它負責驅動全局事務的提交與回滾。根據它的職責可知。它的重要性不言而喻。
那麼作爲一個優秀的協調者它需要具備哪些功能呢?
- 高可用
- 高性能
- 支持擴展
那麼我們根據我們的猜測來看看TC的實現模塊Server是怎麼來實現這寫功能的。
Server模塊介紹
整個Server模塊可以分成7個主要模塊
- RPC模塊 負責與TM RM交互
- Coordinator Core模塊 TC實現事務協調的核心模塊
- Lock模塊 資源全局鎖的實現
- Config模塊 支持配置TC的配置模塊
- Store模塊 TC運行時全局事務以及分支事務的相關信息需要通過Store模塊持久化
- Discover模塊 Seata TC服務註冊發現模塊
- HA-Cluste模塊 TC Server實現高可用的模塊
就一個Server端而言, 它就有7個模塊。那麼我們改從何看起呢。
我們可以用Server啓動的main函數來理解清楚整個TC的運行流程
Server啓動流程
本文所有源碼基於Seata1.1.0
個人能力有限,如有不對歡迎指出。
整個Server端是一個java
應用,它是通過java -jar
啓動的,所以主入口是一個main函數。
入口地址是io.seata.server.Server#main()
public static void main(String[] args) throws IOException {
//1、 參數解析
ParameterParser parameterParser = new ParameterParser(args);
//2、 監控初始化
MetricsManager.get().init();
// 3、將存儲模式放到系統環境變量÷
System.setProperty(ConfigurationKeys.STORE_MODE, parameterParser.getStoreMode());
// 4、創建與RM TM通訊的rpc服務器
RpcServer rpcServer = new RpcServer(WORKING_THREADS);
//server port
rpcServer.setListenPort(parameterParser.getPort());
UUIDGenerator.init(parameterParser.getServerNode());
//log store mode : file, db
// 5、設置資源存儲模式
SessionHolder.init(parameterParser.getStoreMode());
// 6、核心事務協調器創建
DefaultCoordinator coordinator = new DefaultCoordinator(rpcServer);
coordinator.init();
// 7、把協調器作爲一個回調 傳給netty rpc模塊
rpcServer.setHandler(coordinator);
// 8、註冊JVM關閉構造函數
ShutdownHook.getInstance().addDisposable(coordinator);
ShutdownHook.getInstance().addDisposable(rpcServer);
//127.0.0.1 and 0.0.0.0 are not valid here.
if (NetUtil.isValidIp(parameterParser.getHost(), false)) {
XID.setIpAddress(parameterParser.getHost());
} else {
XID.setIpAddress(NetUtil.getLocalIp());
}
XID.setPort(rpcServer.getListenPort());
try {
// 9、啓動RPC模塊 監聽TM RM的請求
rpcServer.init();
} catch (Throwable e) {
LOGGER.error("rpcServer init error:{}", e.getMessage(), e);
System.exit(-1);
}
System.exit(0);
}
首先看看參數解析,其實參數解析很簡單主要是通過JCommander
解析main函數中的args數組,不過在需要注意的是,由於Seata Server已經支持容器部署, 所以在容器環境啓動參數的創建跟正常啓動的參數是不同的。容器部署的啓動參數需要通過System.getenv
獲取
io.seata.server.ParameterParser#init()
private void init(String[] args) {
try {
// 判斷啓動環境是否是容器
boolean inContainer = this.isRunningInContainer();
// 如果是容器啓動 則從系統環境變量讀取參數配置
if (inContainer) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("The server is running in container.");
}
this.seataEnv = StringUtils.trimToNull(System.getenv(ENV_SYSTEM_KEY));
this.host = StringUtils.trimToNull(System.getenv(ENV_SEATA_IP_KEY));
this.serverNode = NumberUtils.toInt(System.getenv(ENV_SERVER_NODE_KEY), SERVER_DEFAULT_NODE);
this.port = NumberUtils.toInt(System.getenv(ENV_SEATA_PORT_KEY), SERVER_DEFAULT_PORT);
this.storeMode = StringUtils.trimToNull(System.getenv(ENV_STORE_MODE_KEY));
} else {
// 否則使用JCommander 解析啓動參數
JCommander jCommander = JCommander.newBuilder().addObject(this).build();
jCommander.parse(args);
if (help) {
jCommander.setProgramName(PROGRAM_NAME);
jCommander.usage();
System.exit(0);
}
}
if (StringUtils.isNotBlank(seataEnv)) {
System.setProperty(ENV_PROPERTY_KEY, seataEnv);
}
if (StringUtils.isBlank(storeMode)) {
storeMode = ConfigurationFactory.getInstance().getConfig(ConfigurationKeys.STORE_MODE,
SERVER_DEFAULT_STORE_MODE);
}
} catch (ParameterException e) {
printError(e);
}
}
拿到啓動參數後我們就要根據啓動參數依次 啓動監控、設置存儲模型,創建協調核心對象、啓動Rpc服務器。
爲什麼Rpc服務器要在最後一個啓動呢? 下篇文章會解答。
由於監控對Seata的核心功能暫無影響所以本文已經後續文章暫不對監控進行分析。
總結
本文簡單的介紹了一下Seata Server
模塊啓動流程的一個分析,瞭解Seata的啓動流程,但是都是比較簡單沒有深入,後續會陸續深入分析Rpc模塊與核心協調模塊。