1. 程式人生 > 實用技巧 >Seata是什麼?一文了解其實現原理

Seata是什麼?一文了解其實現原理

一、背景

隨著業務發展,單體系統逐漸無法滿足業務的需求,分散式架構逐漸成為大型網際網路平臺首選。伴隨而來的問題是,本地事務方案已經無法滿足,分散式事務相關規範和框架應運而生。

在這種情況下,大型廠商根據分散式事務實現規範,實現了不同的分散式框架,以簡化業務開發者處理分散式事務相關工作,讓開發者專注於核心業務開發。

Seata就是這麼一個分散式事務處理框架,Seata是由阿里開源,前身為Fescar,經過品牌升級變身Seata。

二、分散式事務規範

1.分散式事務相關概念

事務:一個程式執行單元,是使用者定義的一組操作序列,需要滿足ACID屬性。

本地事務:事務由本地資源管理器管理。

分散式事務:

事務的操作位於不同的節點。

分支事務:在分散式事務中,由資源管理器管理的本地事務。

全域性事務:一次性操作多個資源管理器完成的事務,由一組分支事務組成。

2. 分散式事務實現規範

對於本地事務,可以藉助DBMS系統來實現事務的管理,但是對於分散式事務,它就無能為力了。對於分散式事務,目前主要有2種思路:XA協議的強一致規範以及柔性事務的最終一致性規範。

2.1 XA

XA是基於2階段提交協議設計的介面標準,實現了XA規範的資源管理器就可以參與XA全域性事務。應用承擔事務管理器TM工作,資料庫承擔資源管理器RM工作,TM生成全域性事務id,控制RM的提交和回滾。

2.2 柔性事務的最終一致性

該規範主要有3種實現方式,TCC、MQ事務訊息、本地訊息表。(還存在其他一些不常用實現方式如Saga)。

TCC:try/confirm/cancel,在try階段鎖定資源,confirm階段進行提交,資源鎖定失敗執行cancel階段釋放資源。

MQ事務訊息:前提訊息系統需要支援事務如RocketMQ,在本地事務執行前,傳送事務訊息prepare,本地事務執行成功,傳送事務訊息commit,實現分散式事務最終一致性。如果事務訊息commit失敗,RocketMQ會回查訊息傳送者確保訊息正常提交,如果步驟5執行失敗,進行重試,達到最終一致性。

本地訊息表:跟MQ事務訊息類似,區別在於MQ不支援事務訊息,需要藉助本地資料庫的事務管理能力。在步驟1中將需要傳送的訊息和本地事務一起提交到DB,藉助DB的事務管理確保訊息持久化。步驟2應用通過本地訊息表掃描,重試傳送,確保訊息可以傳送成功。

三、Seata 架構

1.系統組成

Seata有三個核心元件:

  • Transaction Coordinator(TC,事務協調器)—— 維護全域性事務和分支事務的狀態,驅動全域性事務提交或回滾。
  • Transaction Manager(TM,事務管理器)—— 定義全域性事務的範圍,開始事務、提交事務、回滾事務。
  • Resource Manager(RM,資源管理器):—— 管理分支事務上的資源,向TC註冊分支事務,彙報分支事務狀態,驅動分支事務的提交或回滾。

三個元件相互協作,TC 以 Server 形式獨立部署,TM和RM整合在應用中啟動,其整體互動如下:

2.工作模式

Seata 支援四種工作模式:

2.1 AT(Auto Transaction)

AT模式是Seata預設的工作模式。需要基於支援本地 ACID 事務的關係型資料庫,Java 應用,通過 JDBC 訪問資料庫。

2.1.1 整體機制

該模式是XA協議的演變,XA協議是基於資源管理器實現,而AT並不是如此。AT的2個階段分別是:

  • 一階段:業務資料和回滾日誌記錄在同一個本地事務中提交,釋放本地鎖和連線資源。
  • 二階段:提交非同步化,非常快速地完成;回滾通過一階段的回滾日誌進行反向補償。

下圖中,步驟1開啟全域性事務;步驟2註冊分支事務,這裡對應著一階段;步驟3提交或者回滾分支事務,對應著二階段。

2.1.2 特點

  • 優點:對程式碼無侵入;併發度高,本地鎖在一階段就會釋放;不需要資料庫對XA協議的支援。
  • 缺點:只能用在支援ACID的關係型資料庫;SQL解析還不能支援全部語法。

2.2 TCC

該模式工作分為三個階段:

上圖中對於多個分支事務,省略了多次出現的 2.* 步驟。對於全域性事務執行過程中業務應用宕機情況,業務應用叢集中對等節點會通過從TC獲取相關會話,從DB載入詳細資訊來恢復狀態機。

2.3.3 特點

  • 優點:一階段提交本地事務,無鎖,高效能;事件驅動架構,參與者可非同步執行,高吞吐;補償服務易於實現。
  • 缺點:不保證隔離性。

2.4XA模式

XA是基於二階段提交設計的介面標準。對於支援XA的資源管理器,藉助Seata框架的XA模式,會使XA方案更簡單易用。使用前提:需要分支資料庫支援XA 事務,應用為 Java應用,且使用JDBC訪問資料庫。

2.4.1 整體機制

在 Seata 定義的分散式事務框架內,利用事務資源(資料庫、訊息服務等)對 XA 協議的支援,以 XA 協議的機制來管理分支事務的一種 事務模式。

  • 執行階段:業務sql在XA分支中執行,由分支事務的RM管理器管理,然後執行XA prepare。
  • 完成階段:TM根據各個分支執行結果通過TC通知各個分支執行XA commit或者XA rollback。

2.4.2特點

  • 優點:繼承了XA協議的優勢,事務具有強一致性。
  • 缺點:同樣繼承了XA協議的劣勢,由於分支事務長時間開啟,併發度低。

2.5 Seata 各模式對比

分散式事務方案沒有銀彈,根據自己的業務特性選擇合適的模式。例如追求強一致性,可以選擇AT和XA,存在和外部系統對接,可以選擇Saga模式,不能依賴本地事務,可以採用TCC等等。結合各模式的優缺點進行選擇。

四、AT 模式核心實現

鑑於Seata支援的模式較多,而其預設的模式是AT,為節省篇幅,以下圍繞AT模式分析其相關的核心模組實現。

1.事務協調器的啟動

TC(事務協調器)以獨立的服務啟動,作為Server,維護全域性事務和分支事務的狀態,驅動全域性事務提交或回滾。下面是TC的啟動流程:

2.事務管理器的啟動

TM(事務管理器)整合在應用中啟動,負責定義全域性事務的範圍,開始事務、提交事務、回滾事務。
TM所在應用中需要配置GlobalTransactionScannerbean,在應用啟動時會進行如下初始化流程:

3.資源管理器的啟動

RM(資源管理器)整合在應用中啟動,負責管理分支事務上的資源,向TC註冊分支事務,彙報分支事務狀態,驅動分支事務的提交或回滾。
RM所在的應用中除了需要跟TM一樣配置GlobalTransactionScanner以啟動RMClient,還需要配置DataSourceProxy,以實現對資料來源訪問代理。該資料來源代理實現了sql的解析 →生成undo-log →業務sql和undo-log一併本地提交等操作。

4. 全域性事務的工作流程

下面以一個簡單的例子來說明全域性事務的工作原理:

  • BusinessService:發起購買服務
  • StorageService:庫存管理服務

購買操作實現在businessService.purchase中,purchase方法實現上通過GlobalTransaction註解,通過Dubbo服務,呼叫了庫存服務deduct方法方法,樣例如下:

@GlobalTransactional(timeoutMills = 300000, name = "dubbo-demo-tx")
public void purchase(String userId, String commodityCode, int orderCount) {
    storageService.deduct(commodityCode, orderCount);
    // throw new RuntimeException("xxx");
}

4.1 成功的全域性事務處理流程

4.2 成功的全域性事務處理流程

這裡設定BusinessService在成功呼叫StorageService後,本地出現異常。

5.寫隔離實現

全域性事務未提交,分支事務本地已經提交的情況下(假設修改了資源A),如何避免其他事務在此時修改資源A?Seata採用全域性鎖來實現,其流程如下:

6.讀隔離實現

在資料庫本地隔離級別為讀已提交或以上的基礎上,Seata提供了讀未提交,這個很好理解,全域性事務提交前分支事務本地已經提交。如果想要實現讀已提交,則需要在select語句上加for update。

五、總結

Seata是Java領域很強大的分散式事務框架,其支援了多種模式。其中預設支援的AT模式,相比於傳統的2PC協議(基於資料庫的XA協議),很好地解決了2PC長期鎖資源的問題,提高了併發度。Seata支援的各個模式中,AT模式對業務零入侵實現分散式事務,對於開發者更加友好。另外Seata的Server在選擇合適的儲存介質時可以進行叢集模式,減少單點故障影響。

本文主要參考官網和部分部落格,同時閱讀了AT模式實現原始碼,如果有不對的地方,望指出,一起討論交流。

六、參考

作者:vivo官網商城開發團隊