EasyTransaction主要源碼分析

EasyTransaction是一個全功能的分佈式事務框架,如下特性摘抄自其首頁:https://github.com/QNJR-GROUP/EasyTransactionhtml

  • 一個框架包含多種事務形態,一個框架搞定全部類型的事務
  • 多種事務形態可混合使用
  • 高性能,大多數業務系統瓶頸在業務數據庫,若不啓用框架的冪等功能,對業務數據庫的額外消耗僅爲寫入25字節的一行
  • 可選的框架自帶冪等實現及調用錯亂次序處理,大幅減輕業務開發工做量,但啓用的同時會在業務數據庫增長一條冪等控制行
  • 業務代碼可實現徹底無入侵
  • 支持嵌套事務
  • 無需額外部署協調者,不一樣APP的服務協調自身發起的事務,也避免了單點故障
  • 分佈式事務ID可關聯業務ID,業務類型,APPID,便於監控各個業務的分佈式事務執行狀況

本文主要分享EasyTransaction core中各個package的做用其主要實現。git

請先閱讀 Seata架構的比對思考 http://www.javashuo.com/article/p-xetvolvp-u.html ,再結合 代碼以及demo調試過程看這篇,直接看的話這裏的點太零碎了github

1、context包

主要類數據庫

LogProcessContext

其用於存儲ET事務的上下文信息。在開啓ET事務(第一次ET遠程調用,或者主動調用startSoftTrans方法)時,將建立本類的實例並將其與Spring的本地事務上下文綁定,經過:架構

TransactionSynchronizationManager.bindResource()

執行綁定。當須要取得ET上下文時,經過併發

TransactionSynchronizationManager.getResource()

取得。app

ET上下文中包含的主要內容有:框架

  • 最終事務狀態
  • 所有的全局事務日誌
  • 未Flush到外部的全局事務日誌
  • 事務ID等內容

2、包core

本包主要類爲異步

EasyTransFacade
TransactionHook
ConsistentGuardian
ExecuteCacheManager

類EasyTransFacade

其定義了業務調用方的接口,只包含兩個:分佈式

public void startEasyTrans(String busCode,long trxId);

public <P extends EasyTransRequest<R,E>,E extends EasyTransExecutor, R extends Serializable> Future<R> execute(P params);

第一個用於開啓全局事務,主要的操做爲:

  • 掛載TransactionHook到當前的Spring本地事務中,使得能夠在關鍵節點(如本地事務提交前、本地事務回滾後等等)嵌入ET的代碼
  • 將 LogProcessContext 綁定到當前的Spring本地事務,使得ET能夠在當前Spring本地事務中隨時取得ET全局事務的狀態。
  • 在當前已開啓的本地事務中,寫入一條事務執行記錄到業務庫中,其對Crash恢復時識別全局事務的狀態起關鍵做用

第二個表示執行某個遠程事務方法。

  • 經過調用參數Object對應的Class獲取對應的處理器(如TCC處理器,可靠消息處理器等)並執行調用,具體調用的形態後續專門的章節再繼續

基於註解的接口調用也是經過這兩個方法封裝而成。

類TransactionHook

其爲ET框架代碼與Spring原生事務的主要交界點,ET經過TransactionSynchronization定義的方法,在Spring本地事務執行過程當中,擴展支持了全局事務。主要擴展瞭如下兩個方法

beforeCommit(boolean readOnly)
afterCompletion(int status)

beforeCommit方法將會

  • 在Spring本地事務提交前將全部未落盤的全局事務日誌落盤
  • 並執行全部未執行的遠程調用(ET會盡可能延後全局事務以此堆積並批量執行)
  • 如有不成功的全局事務,則拋出異常,回滾事務(包括本地以及全局)

afterCompletion方法將會

  • 獲取本地事務的最終結果(提交/回滾/未知)以及 ET父級事務的狀態(提交/回滾/未知)來決定本級ET事務的最終狀態(提交/回滾/未知)
  • 得到最終的本級ET事務狀態後,異步執行最終一致處理(調用consistentGuardian.process)

類ConsistentGuardian

本類用於處理ET全局事務的最終一致,例如TCC的Conifrim/Cancel,可靠消息的發送消息。

最終一致處理一般會在同步操做(TCC的TRY等)對應的本地事務執行完成後拋到線程池異步執行,但執行失敗的話,會有兜底的補償(recovery包),後續再詳細講述

該類的主要工做機制是根據以前寫入的全局事務日誌,獲取日誌對應的處理器(如從TCC的事務日誌獲取對應的TCC日誌處理器),以此

  • 判斷當前ET事務的最終狀態(若當前ET事務狀態仍未肯定的話)
  • 傳入最終ET事務狀態到日誌處理器,依次處理對應的事務日誌,處理的典型過程例子:
    • 若存在TRY方法對應的日誌
    • 而且找不到TRY對應的CONFRIM/CANCEL日誌
    • 則根據ET最終事務狀態,調用對應CONFIRM/CANCEL方法

類ExecuteCacheManager

本類主要服務於ET的如下指望

  • 批量寫入ET事務日誌(以減小IO)
  • 批量併發執行遠程業務調用(以減小串行等待遠程相應時間)

其主要實現的是,

  • 對每一個傳入的Calleble對象都返回一個通過改寫的Futrure對象
  • 當任意一個Futrue的get方法都沒有被調用前,全部以前傳入的Callable對象都不會執行。
  • 當任意一個Future的get被調用時,全部callable都會被批量執行,這裏包含了批量寫入日誌以及批量併發執行遠程調用

3、包datasource

主要包含如下兩個接口,其主要做用於業務數據源。

DataSourceSelector
TransStatusLogger

類DataSourceSelector

該類主要用於獲取當前事務/請求對應的數據源及其事務管理器,若應用有多個業務數據源,則須要自行實現對應的數據源選擇器,主要包含如下方法

DataSource selectDataSource(String appId,String busCode,long trxId);
DataSource selectDataSource(String appId,String busCode,EasyTransRequest<?, ?> request);

第一個方法是開啓ET事務時候選擇對應的數據源

第二個方法是被調用方接受到請求時選擇對應的數據源(用於冪等、防懸掛處理,若不須要可忽略)

該接口包含一個默認實現,當只有單數據源時,能夠直接用該實現

SingleDataSourceSelector

類TransStatusLogger

該類主要用來讀寫用於判斷ET事務狀態的記錄,該記錄會在ET事務開啓時,寫入當前的數據庫表中,隨着業務對應事務(Spring本地事務)提交而提交,回滾而回滾。

更具體請直接看實現

4、包executor

該包存儲的是事務發起方(遠程服務調用方)相關處理類的位置,不一樣的事務類型(TCC,可靠事務等)有不一樣的Executor,以TCC爲例講解,其餘的事務類型實現都相似。

TccMethodExecutor

該類實現了三個接口

  • EasyTransExecutor
  • LogProcessor
  • DemiLogEventHandler

EasyTransExecutor接口定義了方法

<P extends EasyTransRequest<R,E>,E extends EasyTransExecutor,R  extends Serializable> Future<R> execute(Integer sameBusinessCallSeq, P params);

該方法供類EasyTransFacade.execute使用,其對應的是執行TCC裏的TRY方法,具體的,它

  • 將TRY方法調用對應的RPC請求包裝成Runnable類
  • 構建本次調用對應的全局事務日誌(主要包含本次調用的具體參數、對應遠程方法等)
  • 而後傳入上面章節提到的類ExecuteCacheManager方法中

LogProcessor接口定義瞭如何處理事務日誌,其包含一個主要方法

boolean logProcess(LogProcessContext ctx, Content currentContent)

該方法將會判斷,若是傳入的日誌類型是PreTccCallContent(TCC TRY請求對應的日誌)的話,將會監聽該日誌最終的配對信息(類ConsistentGuardian會在處理當前ET事務的日誌後,發送消息,告知全部須要配對的日誌的配對結果),若是

  • 監聽到成功配對(找到CONFIRM或者CANCEL對應的日誌)的消息,則再也不作後續處理
  • 監聽到配對失敗(沒有存在對應的CONFIRM/CANCEL日誌)的消息,則根據當前的ET事務狀態執行對應的CONFIRM或者CANCEL操做,並記錄對應的日誌

其餘的事務形態的實現也相似,再也不贅述

5、包recovery

用於兜底恢復事務,實現最終一致。

代碼不復雜,能夠自行查看。

6、包Filter

該包主要用於實現ET對應的Filter,該Filter做用於被調用端。咱們能夠經過實現ET的Filter擴展被調用端的功能,如處理冪等、處理嵌套事務、增長調用上下文的處理等等。

7、包idempotent

實現冪等、方懸掛等處理對應的包

冪等及防懸掛處理的主要原理:

  • 當遠程調用過來時,寫入調用日誌到當前的開啓的業務日誌中,並記錄 調用對應的ID,調用參數對應的MD5
  • 有結果返回時就將結果更新存儲到日誌中
  • 當有重複請求過來時,就檢查ID對應的記錄是否存在,若存在則檢查參數的MD5是否一致,若一致則返回以前的存儲結果
  • 防懸掛也相似,在上述的日誌中,將會記錄調用的方法是什麼,如
    • 當找不到請求對應日誌時,但當前爲cancel操做的話,框架將直接返回成功
    • 上述cancel已經成功執行後,try方法再來到時,發現cancel已經執行,就直接將try報錯返回

8、包idgen

用於生成ET的分佈式事務ID,當自行制定ID時,本包對應的方法不會被調用。當不指定ID時,將會自動生成一個。

9、包log

定義ET事務日誌對應的Class,以及其讀寫接口。
事務日誌在以前TccExecutor等章節已提到,再也不贅述。

須要擴展事務日誌存儲實現的,直接實現如下接口便可

TransactionLogReader
TransactionLogWritter

(ET事務日誌的讀寫不須要與業務事務在同一個事務中,也不能在同一個事務中)

10、包master

用於在同一個appId中選擇一個做爲master進行兜底最終一致補償的包。

實際上選擇不須要太精確,任意一個appId下的實例都可,也能夠同時有多個master存在(但目前沒有意義,也會浪費性能)

11、包monitor

用於提供ET實例狀態的包,可供Dashboard,監控等擴展使用

12、包protocol

供客戶直接定義分佈式事務服務的包,其包含一些客戶直接使用的 父類、配置接口、配置註解等

十3、包provider.factory

從Spring中獲取並存儲對應的bean實現,以便於快速方便地經過ET對應的定義,取得對應bean

十4、包queue

若要擴展新增對應的消息隊列實現,則實現這個包對應的接口

十5、包rpc

同上

十6、包serialization

ET框架所使用的序列化形式,可自行擴展

十7、包stingcodec

用於壓縮字符串,將字符串替換爲數字id,以提升存儲效率

相關文章
相關標籤/搜索