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

1、背景

隨着業務發展,單體系統逐漸沒法知足業務的需求,分佈式架構逐漸成爲大型互聯網平臺首選。伴隨而來的問題是,本地事務方案已經沒法知足,分佈式事務相關規範和框架應運而生。html

在這種狀況下,大型廠商根據分佈式事務實現規範,實現了不一樣的分佈式框架,以簡化業務開發者處理分佈式事務相關工做,讓開發者專一於核心業務開發。java

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

2、分佈式事務規範

1.分佈式事務相關概念

事務:一個程序執行單元,是用戶定義的一組操做序列,須要知足ACID屬性。github

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

分佈式事務:事務的操做位於不一樣的節點。數據庫

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

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

2. 分佈式事務實現規範

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

2.1 XA

XA是基於2階段提交協議設計的接口標準,實現了XA規範的資源管理器就能夠參與XA全局事務。應用承擔事務管理器TM工做,數據庫承擔資源管理器RM工做,TM生成全局事務id,控制RM的提交和回滾。異步

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

2.2 柔性事務的最終一致性

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

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

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

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

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

本地消息表:跟MQ事務消息相似,區別在於MQ不支持事務消息,須要藉助本地數據庫的事務管理能力。在步驟1中將須要發送的消息和本地事務一塊兒提交到DB,藉助DB的事務管理確保消息持久化。步驟2應用經過本地消息表掃描,重試發送,確保消息能夠發送成功。

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

3、Seata 架構

1. **系統組成**

Seata有三個核心組件:

  • Transaction Coordinator(TC,事務協調器)

    維護全局事務和分支事務的狀態,驅動全局事務提交或回滾。

  • Transaction Manager(TM,事務管理器)

    定義全局事務的範圍,開始事務、提交事務、回滾事務。

  • Resource Manager(RM,資源管理器):

    管理分支事務上的資源,向TC註冊分支事務,彙報分支事務狀態,驅動分支事務的提交或回滾。

三個組件相互協做,TC 以 Server 形式獨立部署,TM和RM集成在應用中啓動,其總體交互以下:

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

2.工做模式

Seata 支持四種工做模式:

2.1 AT(Auto Transaction)

AT模式是Seata默認的工做模式。須要基於支持本地 ACID 事務的關係型數據庫,Java 應用,經過 JDBC 訪問數據庫。

2.1.1 總體機制

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

  • 一階段:業務數據和回滾日誌記錄在同一個本地事務中提交,釋放本地鎖和鏈接資源。

  • 二階段:提交異步化,很是快速地完成;回滾經過一階段的回滾日誌進行反向補償。

下圖中,步驟1開啓全局事務;步驟2註冊分支事務,這裏對應着一階段;步驟3提交或者回滾分支事務,對應着二階段。

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

2.1.2 特色

  • 優勢:對代碼無侵入;併發度高,本地鎖在一階段就會釋放;不須要數據庫對XA協議的支持。

  • 缺點:只能用在支持ACID的關係型數據庫;SQL解析還不能支持所有語法。

2.2 TCC

該模式工做分爲三個階段:prepare/commit/cancel。

2.2.1 總體機制

  • TM向TC申請全局事務XID,傳播給各個子調用。

  • 子調用的所在TM向TC註冊分支事務,並執行本地prepare,並向TC報告執行結果。

  • TC根據各分支事務的執行結果肯定二階段是執行commit或rollback。

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

2.2.2 特色

  • 優勢:不依賴本地事務。

  • 缺點:回滾邏輯依賴手動編碼;業務侵入性較大。

2.3 Saga 模式

2.3.1 Saga 是什麼?

1987年普林斯頓大學的Hector Garcia-Molina和Kenneth Salem發表了一篇Paper Sagas,講述的是如何處理long lived transaction(長活事務)。Saga是一個長活事務可被分解成能夠交錯運行的子事務集合。論文見這裏。  

簡單來講,Saga將一個長事務(T)分解成一系列Sub事務(Ti),每一個Sub事務都有對應的補償動做(Ci),用於撤銷Ti事務產生的影響。Sub事務是直接提交到庫,在出現異常時,逆向進行補償。

所以Saga事務的組成有2種:  

  • T1, T2, T3, ..., Tn

  • T1, T2, ..., Tj, Cj,..., C2, C1,其中0 < j < n

第一種就是正常提交的狀況,第二種在提交Tj事務出現異常,開始逆向補償的狀況。

Saga模式是Seata提供的長事務解決方案。例如全局事務中涉及到外部系統,沒法管理它的資源管理器,讓它改形成TCC也很差實行,這時就能夠採用此類方案。

2.3.2 總體機制

在Saga模式中,業務流程中每一個參與者都提交本地事務,當出現某一個參與者失敗則補償前面已經成功的參與者,一階段正向服務和二階段補償服務都由業務開發實現。

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

上圖中對於多個分支事務,省略了屢次出現的 2.* 步驟。對於全局事務執行過程當中業務應用宕機狀況,業務應用集羣中對等節點會經過從TC獲取相關會話,從DB加載詳細信息來恢復狀態機。

2.3.3 特色

  • 優勢:一階段提交本地事務,無鎖,高性能;事件驅動架構,參與者可異步執行,高吞吐;補償服務易於實現。

  • 缺點:不保證隔離性。

2.4 XA模式

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。

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

2.4.2 **特色**

  • 優勢:繼承了XA協議的優點,事務具備強一致性。  

  • 缺點:一樣繼承了XA協議的劣勢,因爲分支事務長時間開啓,併發度低。

2.5  Seata 各模式對比

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

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

4、AT 模式核心實現

鑑於Seata支持的模式較多,而其默認的模式是AT,爲節省篇幅,如下圍繞AT模式分析其相關的核心模塊實現。

1. 事務協調器的啓動

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

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

2. **事務管理器的啓動**

TM(事務管理器)集成在應用中啓動,負責定義全局事務的範圍,開始事務、提交事務、回滾事務。
TM所在應用中須要配置GlobalTransactionScannerbean,在應用啓動時會進行以下初始化流程:

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

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 成功的全局事務處理流程

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

4.2 成功的全局事務處理流程

這裏設定BusinessService在成功調用StorageService後,本地出現異常。

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

5. 寫隔離實現

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

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

6. 讀隔離實現

在數據庫本地隔離級別爲讀已提交或以上的基礎上,Seata提供了讀未提交,這個很好理解,全局事務提交前分支事務本地已經提交。若是想要實現讀已提交,則須要在select語句上加for update。

5、總結

Seata是Java領域很強大的分佈式事務框架,其支持了多種模式。其中默認支持的AT模式,相比於傳統的2PC協議(基於數據庫的XA協議),很好地解決了2PC長期鎖資源的問題,提升了併發度。Seata支持的各個模式中,AT模式對業務零***實現分佈式事務,對於開發者更加友好。另外Seata的Server在選擇合適的存儲介質時能夠進行集羣模式,減小單點故障影響。

本文主要參考官網和部分博客,同時閱讀了AT模式實現源碼,若是有不對的地方,望指出,一塊兒討論交流。

6、參考

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

相關文章
相關標籤/搜索