天天看點

Seata--分布式事務1、Seata 分布式事務基礎2、分布式事務解決方案3、Seata介紹4、Seata實作分布式事務控制啟動seata服務

1、Seata 分布式事務基礎

1.1事務

事務指的就是一個操作單元,在這個操作單元中的所有操作最終要保持一緻的行為,要麼所有操作都成功,要麼所有的操作都被撤銷。簡單地說,事務提供一種“要麼什麼都不做,要麼做全套”機制。

1.2本地事務

本地事物其實可以認為是資料庫提供的事務機制。說到資料庫事務就不得不說,資料庫事務中的四大特性:

A:原子性(Atomicity),一個事務中的所有操作,要麼全部完成,要麼全部不完成C:一緻性(Consistency),在一個事務執行之前和執行之後資料庫都必須處于一緻性狀态I:隔離性(Isolation),在并發環境中,當不同的事務同時操作相同的資料時,事務之間互不影響D:持久性(Durability),指的是隻要事務成功結束,它對資料庫所做的更新就必須永久的儲存下來

資料庫事務在實作時會将一次事務涉及的所有操作全部納入到一個不可分割的執行單元,該執行單元中的所有操作要麼都成功,要麼都失敗,隻要其中任一操作執行失敗,都将導緻整個事務的復原

1.3分布式事務

分布式事務指事務的參與者、支援事務的伺服器、資源伺服器以及事務管理器分别位于不同的分布式系統的不同節點之上。

簡單的說,就是一次大的操作由不同的小操作組成,這些小的操作分布在不同的伺服器上,且屬于不同的應用,分布式事務需要保證這些小操作要麼全部成功,要麼全部失敗。

本質上來說,分布式事務就是為了保證不同資料庫的資料一緻性。

1.4分布式事務的場景

  • 單體系統通路多個資料庫

一個服務需要調用多個資料庫執行個體完成資料的增删改操作

  • 多個微服務通路同一個資料庫

多個服務需要調用一個資料庫執行個體完成資料的增删改操作

  • 多個微服務通路多個資料庫

多個服務需要調用一個資料庫執行個體完成資料的增删改操作

2、分布式事務解決方案

2.1全局事務

全局事務基于DTP模型實作。DTP是由X/Open組織提出的一種分布式事務模型——X/OpenDistributed Transaction Processing Reference Model。它規定了要實作分布式事務,需要三種角色:

  • AP: Application應用系統(微服務)
  • TM: Transaction Manager事務管理器(全局事務管理)
  • RM: Resource Manager資料總管(資料庫)

整個事務分成兩個階段:

階段一:表決階段,所有參與者都将本事務執行預送出,并将能否成功的資訊回報發給協調者。9階段二:執行階段,協調者根據所有參與者的回報,通知所有參與者,步調一緻地執行送出或者復原。

優點

  • 提高了資料一緻性的機率,實作成本較低

缺點

  • 單點問題:事務協調者當機
  • 同步阻塞:延遲了送出時間,加長了資源阻塞時間
  • 資料不一緻:送出第二階段,依然存在commit結果未知的情況,有可能導緻資料不一緻

2.2可靠消息服務

基于可靠消息服務的方案是通過消息中間件保證上、下遊應用資料操作的一緻性。假設有A和B兩個系統,分别可以處理任務A和任務B。此時存在一個業務流程,需要将任務A和任務B在同一個事務中處理。就可以使用消息中間件來實作這種分布式事務。

Seata--分布式事務1、Seata 分布式事務基礎2、分布式事務解決方案3、Seata介紹4、Seata實作分布式事務控制啟動seata服務

第一步:消息由系統A投遞到中間件

  1. .在系統A處理任務A前,首先向消息中間件發送一條消息
  2. .消息中間件收到後将該條消息持久化,但并不投遞。持久化成功後,向A回複一個确認應答
  3. .系統A收到确認應答後,則可以開始處理任務A
  4. .任務A處理完成後,向消息中間件發送Commit或者Rollback請求。該請求發送完成後,對系統A而言,該事務的處理過程就結束了
  5. .如果消息中間件收到Commit,則向B系統投遞消息;如果收到Rollback,則直接丢棄消息。但是如果消息中間件收不到Commit和Rollback指令,那麼就要依靠"逾時詢問機制"。

第二步:消息由中間件投遞到系統B

  • 消息中間件向下遊系統投遞完消息後便進入阻塞等待狀态,下遊系統便立即進行任務的處理,任務處理完成後便向消息中間件傳回應答。
  • 如果消息中間件收到确認應答後便認為該事務處理完畢
  • 如果消息中間件在等待确認應答逾時之後就會重新投遞,直到下遊消費者傳回消費成功響應為止。一般消息中間件可以設定消息重試的次數和時間間隔,如果最終還是不能成功投遞,則需要手工幹預。這裡之是以使用人工幹預,而不是使用讓A系統復原,主要是考慮到整個系統設計的複雜度問題。

基于可靠消息服務的分布式事務,前半部分使用異步,注重性能;後半部分使用同步,注重開發成本。

2.3最大努力通知

最大努力通知也被稱為定期校對,其實是對第二種解決方案的進一步優化。它引入了本地消息表來記錄錯誤消息,然後加入失敗消息的定期校對功能,來進一步保證消息會被下遊系統消費。

Seata--分布式事務1、Seata 分布式事務基礎2、分布式事務解決方案3、Seata介紹4、Seata實作分布式事務控制啟動seata服務

第一步:消息由系統A投遞到中間件

  • .處理業務的同一事務中,向本地消息表中寫入一條記錄
  • .準備專門的消息發送者不斷地發送本地消息表中的消息到消息中間件,如果發送失敗則重試

第二步:消息由中間件投遞到系統B

  • .消息中間件收到消息後負責将該消息同步投遞給相應的下遊系統,并觸發下遊系統的任務執行
  • .當下遊系統處理成功後,向消息中間件回報确認應答,消息中間件便可以将該條消息删除,進而該事務完成
  • .對于投遞失敗的消息,利用重試機制進行重試,對于重試失敗的,寫入錯誤消息表
  • .消息中間件需要提供失敗消息的查詢接口,下遊系統會定期查詢失敗消息,并将其消費

這種方式的優缺點:

優點:一種非常經典的實作,實作了最終一緻性。

缺點:消息表會耦合到業務系統中,如果沒有封裝好的解決方案,會有很多雜活需要處理。

2.4TCC事務

TCC即為Try Confirm Cancel,它屬于補償型分布式事務。TCC實作分布式事務一共有三個步驟:

  • Try:嘗試待執行的業務

這個過程并未執行業務,隻是完成所有業務的一緻性檢查,并預留好執行所需的全部資源

  • Confirm:确認執行業務

确認執行業務操作,不做任何業務檢查,隻使用Try階段預留的業務資源。通常情況下,采用TCC則認為Confirm階段是不會出錯的。即:隻要Try成功,Confirm一定成功。若Confirm階段真的出錯了,需引入重試機制或人工處理。

  • Cancel:取消待執行的業務

取消Try階段預留的業務資源。通常情況下,采用TCC則認為Cancel階段也是一定成功的。若Cancel階段真的出錯了,需引入重試機制或人工處理。

Seata--分布式事務1、Seata 分布式事務基礎2、分布式事務解決方案3、Seata介紹4、Seata實作分布式事務控制啟動seata服務

TCC兩階段送出與XA兩階段送出的差別是:

XA是資源層面的分布式事務,強一緻性,在兩階段送出的整個過程中,一直會持有資源的鎖。TCC是業務層面的分布式事務,最終一緻性,不會一直持有資源的鎖。

TCC事務的優缺點:

優點:把資料庫層的二階段送出上提到了應用層來實作,規避了資料庫層的2PC性能低下問題。

缺點:TCC的Try、Confirm和Cancel操作功能需業務提供,開發成本高。

3、Seata介紹

2019年1月,阿裡巴巴中間件團隊發起了開源項目Fescar(Fast & EaSy Commit AndRollback),其願景是讓分布式事務的使用像本地事務的使用一樣,簡單和高效,并逐漸解決開發者們遇到的分布式事務方面的所有難題。後來更名為Seata,意為:Simple Extensible AutonomousTransaction Architecture,是一套分布式事務解決方案。

Seata的設計目标是對業務無侵入,是以從業務無侵入的2PC方案着手,在傳統2PC的基礎上演進。它把一個分布式事務了解成一個包含了若幹分支事務的全局事務。全局事務的職責是協調其下管轄的分支事務達成一緻,要麼一起成功送出,要麼一起失敗復原。此外,通常分支事務本身就是一個關系資料庫的本地事務。

Seata--分布式事務1、Seata 分布式事務基礎2、分布式事務解決方案3、Seata介紹4、Seata實作分布式事務控制啟動seata服務

Seata主要由三個重要元件組成:

  • TC:Transaction Coordinator事務協調器,管理全局的分支事務的狀态,用于全局性事務的送出和復原。
  • TM:Transaction Manager事務管理器,用于開啟、送出或者復原全局事務。
  • RM:Resource Manager資料總管,用于分支事務上的資源管理,向TC注冊分支事務,上報分支事務的狀态,接受TC的指令來送出或者復原分支事務。
Seata--分布式事務1、Seata 分布式事務基礎2、分布式事務解決方案3、Seata介紹4、Seata實作分布式事務控制啟動seata服務

Seata的執行流程如下:

  1. .A服務的TM向TC申請開啟一個全局事務,TC就會建立一個全局事務并傳回一個唯一的XID
  2. .A服務的RM向TC注冊分支事務,并及其納入XID對應全局事務的管轄
  3. .A服務執行分支事務,向資料庫做操作
  4. .A服務開始遠端調用B服務,此時XID會在微服務的調用鍊上傳播
  5. .B服務的RM向TC注冊分支事務,并将其納入XID對應的全局事務的管轄
  6. .B服務執行分支事務,向資料庫做操作
  7. .全局事務調用鍊處理完畢,TM根據有無異常向TC發起全局事務的送出或者復原
  8. .TC協調其管轄之下的所有分支事務,決定是否復原

Seata實作2PC與傳統2PC的差别:

  1. .架構層次方面,傳統2PC方案的RM實際上是在資料庫層,RM本質上就是資料庫自身,通過XA協定實作,而Seata的RM是以jar包的形式作為中間件層部署在應用程式這一側的。
  2. .兩階段送出方面,傳統2PC無論第二階段的決議是commit還是rollback,事務性資源的鎖都要保持到Phase2完成才釋放。而Seata的做法是在Phase1就将本地事務送出,這樣就可以省去Phase2持鎖的時間,整體提高效率。

4、Seata實作分布式事務控制

4.1啟動Seata

4.1.1 下載下傳位址:下載下傳seata v0.9.0 https://github.com/seata/seata/releases/tag/v0.9.0

4.1.2修改配置檔案

将下載下傳得到的壓縮包進行解壓,進入conf目錄,調整下面的配置檔案:

registry.conf

registry{
        type="nacos"
        nacos{
                serverAddr="localhost"
                namespace="public"
                cluster="default"
        }
}


config{
        type="nacos"
        nacos{
                serverAddr="localhost"
                namespace="public"
                cluster="default"
        }
}

           

将配置導入到nacos 

vim nacos-config.txt
           
service.vgroup_mapping.springcloud-alibaba-impl-member=default
service.vgroup_mapping.springcloud-alibaba-impl-order=default
           
Seata--分布式事務1、Seata 分布式事務基礎2、分布式事務解決方案3、Seata介紹4、Seata實作分布式事務控制啟動seata服務

初始化:

sh nacos-config.sh 127.0.0.1
           

啟動seata服務

sh seata-server.sh -p 9000 -m file
           

啟動後在Nacos的服務清單下面可以看到一個名為serverAddr的服務。

Seata--分布式事務1、Seata 分布式事務基礎2、分布式事務解決方案3、Seata介紹4、Seata實作分布式事務控制啟動seata服務
 4.2使用Seata實作事務控制

4.2.1初始化資料表

在我們所使用的的資料庫中加入一張undo_log表,這是Seata記錄事務日志要用到的表

-- the table to store seata xid data
-- 0.7.0+ add context
-- you must to init this sql for you business databese. the seata server not need it.
-- 此腳本必須初始化在你目前的業務資料庫中,用于AT 模式XID記錄。與server端無關(注:業務資料庫)
-- 注意此處0.3.0+ 增加唯一索引 ux_undo_log
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
           
Seata--分布式事務1、Seata 分布式事務基礎2、分布式事務解決方案3、Seata介紹4、Seata實作分布式事務控制啟動seata服務

4.3添加配置

在需要進行分布式控制的微服務中進行下面幾項配置:

添加依賴

<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>
           

4.4添加配置類

DataSourceProxyConfig:

Seata是通過代理資料源實作事務分支的,是以需要配置io.seata.rm.datasource.DataSourceProxy的Bean,且是@Primary預設的資料源,否則事務不會復原,無法實作分布式事務

package application.config;

import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * @author: wtl
 * @License: (C) Copyright 2020, wtl Corporation Limited.
 * @Contact: [email protected]
 * @Date: 2021/1/4 6:57
 * @Version: 1.0
 * @Description:
 */
@Configuration
public class DataSourceProxyConfig {
    @Bean
    @ConfigurationProperties(prefix="spring.datasource")
    public DruidDataSource druidDataSource(){
        return new DruidDataSource();
    }

    @Primary
    @Bean
    public DataSourceProxy dataSource(DruidDataSource druidDataSource){
        return new DataSourceProxy(druidDataSource);
    }
}