首頁 > 軟體

Java分散式事務管理框架之Seata

2022-07-29 14:03:28

Seata介紹

Seata:Simple Extensible Autonomous Transaction Architecture,簡易可延伸的自治式分散式事務管理框架,其前身是fescar。是一種簡單分散式事務的解決方案。Seata 是一款開源的分散式事務解決方案,致力於提供高效能和簡單易用的分散式事務服務。Seata 將為使用者提供了 AT、TCC、SAGA 和 XA 事務模式,為使用者打造一站式的分散式解決方案。

官方檔案:https://seata.io/zh-cn/docs/overview/what-is-seata.html

三大元件

事務協調器(TC):維護全域性事務和分支事務的狀態,驅動全域性提交或回滾,相當於是協調者。

事務管理器(TM):定義全域性事務的範圍:開始全域性事務,提交或回滾全域性事務,相當於LCN中發起方。

資源管理器(RM):管理分支事務正在處理的資源,與TC進行對話以註冊分支事務並報告分支事務的狀態,並驅動分支事務的提交或回滾,相當於是LCN中的參與方

實現原理

  • 發起方™和我們的參與方(RM)專案啟動之後和協調者TC保持長連線;
  • 發起方™呼叫介面之前向TC獲取一個全域性的事務的id 為xid,註冊到 seata 中.Aop實現
  • 使用feign使用者端呼叫介面的時候,seata重寫了feign使用者端,在請求中傳遞該xid。
  • 參與方(RM)從請求頭中獲取到該xid,方法執行完後不會立馬提交而是等待協調者告訴提交狀態。

四種事務模式

第一種、AT

使用這種模式有個前提:

  • 基於支援本地 ACID 事務的關係型資料庫。
  • Java 應用,通過 JDBC 存取資料庫。

實現過程分為兩個階段:

一階段:

在一階段中,Seata會攔截“業務SQL“,首先解析SQL語意,找到要更新的業務資料,在資料被更新前,儲存下來"undo",然後執行”業務SQL“更新資料,更新之後再次儲存資料”redo“,最後生成行鎖,這些操作都在本地資料庫事務內完成,這樣保證了一階段的原子性。

  • 解析 SQL:得到 SQL 的型別(UPDATE),表(product),條件(where name = ‘TXC’)等相關的資訊。
  • 查詢前映象:根據解析得到的條件資訊,生成查詢語句,定位資料。
  • 執行業務 SQL:更新這條記錄的 name 為 ‘GTS’。
  • 查詢後映象:根據前映象的結果,通過 主鍵 定位資料。
  • 插入回滾紀錄檔:把前後映象資料以及業務 SQL 相關的資訊組成一條回滾紀錄檔記錄,插入到 UNDO_LOG 表中。
  • 提交前,向 TC 註冊分支:申請 product 表中,主鍵值等於 1 的記錄的 全域性鎖 。
  • 本地事務提交:業務資料的更新和前面步驟中生成的 UNDO LOG 一併提交。
  • 將本地事務提交的結果上報給 TC。

二階段:

相對一階段,二階段比較簡單,負責整體的回滾和提交,如果之前的一階段中有本地事務沒有通過,那麼就執行全域性回滾,否在執行全域性提交,回滾用到的就是一階段記錄的"undo Log",通過回滾記錄生成反向更新SQL並執行,以完成分支的回滾。當然事務完成後會釋放所有資源和刪除所有紀錄檔。

事務回滾的情況

  • 收到 TC 的分支回滾請求,開啟一個本地事務,執行如下操作。
  • 通過 XID 和 Branch ID 查詢到相應的 UNDO LOG 記錄。
  • 資料校驗:拿 UNDO LOG 中的後鏡與當前資料進行比較,如果有不同,說明資料被當前全域性事務之外的動作做了修改。這種情況,需要根據設定策略來做處理
  • 根據 UNDO LOG 中的前映象和業務 SQL 的相關資訊生成並執行回滾的語句
  • 提交本地事務。並把本地事務的執行結果(即分支事務回滾的結果)上報給 TC。

事務提交的情況

  • 收到 TC 的分支提交請求,把請求放入一個非同步任務的佇列中,馬上返回提交成功的結果給 TC。
  • 非同步任務階段的分支提交請求將非同步和批次地刪除相應 UNDO LOG 記錄。

**總結:**AT模式是一種無侵入的分散式事務解決方案,在 AT 模式下,使用者只需關注自己的“業務 SQL”,使用者的 “業務 SQL” 作為一階段,Seata 框架會自動生成事務的二階段提交和回滾操作。該模式會根據使用者執行的SQL生成對應的回滾資料的SQL語句,然後根據事務的提交還是回滾來執行回滾的SQL語句還是刪除對應的UNDO LOG 記錄(SQL語句)。

第二種、TCC

不依賴於底層資料資源的事務支援:是指支援把 自定義 的分支事務納入到全域性事務的管理中。

一階段 prepare 行為:呼叫 自定義 的 prepare 邏輯。
二階段 commit 行為:呼叫 自定義 的 commit 邏輯。
二階段 rollback 行為:呼叫 自定義 的 rollback 邏輯。

第三種、Saga

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

第四種、XA

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

使用前提:支援XA 事務的資料庫。Java 應用,通過 JDBC 存取資料庫。

這裡主要介紹使用AT模式,後續提供每種模式的實現方式、程式碼案例。

搭建seata伺服器端

單機版安裝

下載地址:https://github.com/seata/seata/releases

這裡使用的是1.4.2版本

學習和測試建議使用單機版,簡單搭建,生成環境不建議。

直接在github上下載對應的軟體包,一鍵啟動即可,預設是file模式,也就是資料以檔案的形式儲存本地。

解壓之後,進入bin目錄執行對應的啟動命令即可:windows環境執行 bat檔案,Linux環境執行 sh檔案。

啟動成功:

資料儲存在本地

叢集安裝

首先準備mysql、nacos環境,在準備至少兩臺伺服器,這裡資料存到MySQL中去。

多個 Seata TC Server 通過 db 資料庫,實現全域性事務對談資訊的共用。同時,每個 Seata TC Server 可以註冊自己到註冊中心上,方便應用從註冊中心獲得到他們。

初始化SQL語句(可以去github中找到,原始碼中也有),seata框架需要用的資料庫表

CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

每個seata服務節點的設定資訊修改:主要修改下面兩個檔案

file.conf檔案的修改:注意mysql 的版本,我這裡使用的是MySQL8

store {
  ## store mode: file、db、redis
  mode = "db"
  ## rsa decryption public key
  publicKey = ""
  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.cj.jdbc.Driver"
    ## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param
    url = "jdbc:mysql://www.kaicostudy.com:3306/transaction_seata?rewriteBatchedStatements=true"
    user = "root"
    password = "123456"
    minConn = 5
    maxConn = 100
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
}

registry.conf 檔案的修改:

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "www.kaicostudy.com:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = ""
    password = ""
  }
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "www.kaicostudy.com:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = ""
    password = ""
    dataId = "seataServer.properties"
  }
}

修改好每個seata服務節點的設定資訊後,正常一次啟動seata服務就可以了。之後可以在nacos看到seata服務的資訊。

到此這篇關於Java分散式事務管理框架之Seata的文章就介紹到這了,更多相關Java Seata內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com