对文章部分内容作了调整和说明,后续会基于seata-1.1.0版本写一篇更加完整的关于seata的AT、Tcc以及Saga模式的文章,大家互相学习,共同进步。

Seata 是什么?

Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。在 Seata 开源之前,Seata 对应的内部版本在阿里经济体内部一直扮演着分布式一致性中间件的角色,帮助经济体平稳的度过历年的双11,对各BU业务进行了有力的支撑。经过多年沉淀与积累,商业化产品先后在阿里云、金融云进行售卖。2019.1 为了打造更加完善的技术生态和普惠技术成果,Seata 正式宣布对外开源,未来 Seata 将以社区共建的形式帮助其技术更加可靠与完备。

seata的官方文档:http://seata.io/zh-cn/index.html

seata github地址:https://github.com/seata/seata

设计初衷

对业务无侵入:即减少技术架构上的微服务化所带来的分布式事务问题对业务的侵入

高性能:减少分布式事务解决方案所带来的性能消耗

发展远景

架构

TC - 事务协调者

维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM - 事务管理器

定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM - 资源管理器

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

微服务框架支持

目前已支持 Dubbo、Spring Cloud、Sofa-RPC、Motan 和 grpc 等RPC框架,其他框架持续集成中

AT 模式(业务入侵小)

提供无侵入自动补偿的事务模式,目前已支持 MySQL、 Oracle 的AT模式、PostgreSQL、H2 开发中

前提

基于支持本地 ACID 事务的关系型数据库。

Java 应用,通过 JDBC 访问数据库。

整体机制

两阶段提交协议的演变:

一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。

二阶段:

提交异步化,非常快速地完成。

回滚通过一阶段的回滚日志进行反向补偿

TCC 模式(高性能)

支持 TCC 模式并可与 AT 混用,灵活度更高

SAGA 模式

为长事务提供有效的解决方案

XA 模式(开发中)

支持已实现 XA 接口的数据库的 XA 模式

高可用

支持基于数据库存储的集群模式,水平扩展能力强

配置

2019.12.21,Seata 1.0.0 GA版本重磅发布,此次配置就是基于1.0.0版本进行集成

https://www.oschina.net/news/112269/seata-1-0-0-ga-released?tdsourcetag=s_pctim_aiomsg

依赖

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>  

数据库

为每个涉及数据库的微服务创建 UNDO_LOG 表,SEATA AT 模式需要 UNDO_LOG 表

-- 注意此处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-server

 https://github.com/seata/seata/releases,下载服务器软件包seata-server-1.0.0,将其解压缩

Usage: sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for windows) [options] 
Options: 
--host, -h 
The host to bind. 
Default: 0.0.0.0 
--port, -p 
The port to listen. 
Default: 8091 
--storeMode, -m 
log store mode : file、db 
Default: file 
--help 

e.g. 

sh seata-server.sh -p 8091 -h 127.0.0.1 -m file

配置seata-server

配置中心以nacos为例,配置文件在conf目录下

配置registry.conf

registry {

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

  nacos {
    serverAddr = "localhost"
    namespace = ""
    cluster = "default"
  }

}



config {

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

  nacos {
    serverAddr = "localhost"
    namespace = ""
  }

}

将registry下type修改为nacos

将config下type修改为nacos

配置nacos-config.txt

官网seata-server-0.9.0的conf目录下有该文件,seata-server-1.0.0的conf目录下没有nacos-config.txt文件,新增或者从seata-server-0.9.0的conf目录下复制一份即可(对应seata-1.0.0源码里的config.txt脚本,在script\config-center目录下,也可以下载源码,在源码里修改),内容如下:

transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.thread-factory.boss-thread-prefix=NettyBoss
transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker
transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler
transport.thread-factory.share-boss-worker=false
transport.thread-factory.client-selector-thread-prefix=NettyClientSelector
transport.thread-factory.client-selector-thread-size=1
transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread
transport.thread-factory.boss-thread-size=1
transport.thread-factory.worker-thread-size=8
transport.shutdown.wait=3
service.vgroup_mapping.my_test_tx_group=default
service.vgroup_mapping.my_test_tx_group1=default
service.vgroup_mapping.my_test_tx_group2=default
service.enableDegrade=false
service.disable=false
service.max.commit.retry.timeout=-1
service.max.rollback.retry.timeout=-1
client.async.commit.buffer.limit=10000
client.lock.retry.internal=10
client.lock.retry.times=30
client.lock.retry.policy.branch-rollback-on-conflict=true
client.table.meta.check.enable=true
client.report.retry.count=5
client.tm.commit.retry.count=1
client.tm.rollback.retry.count=1
store.mode=file
store.file.dir=file_store/data
store.file.max-branch-session-size=16384
store.file.max-global-session-size=512
store.file.file-write-buffer-cache-size=16384
store.file.flush-disk-mode=async
store.file.session.reload.read_size=100
store.db.datasource=dbcp
store.db.db-type=mysql
store.db.driver-class-name=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true
store.db.user=root
store.db.password=root
store.db.min-conn=1
store.db.max-conn=3
store.db.global.table=global_table
store.db.branch.table=branch_table
store.db.query-limit=100
store.db.lock-table=lock_table
recovery.committing-retry-period=1000
recovery.asyn-committing-retry-period=1000
recovery.rollbacking-retry-period=1000
recovery.timeout-retry-period=1000
transaction.undo.data.validation=true
transaction.undo.log.serialization=jackson
transaction.undo.log.save.days=7
transaction.undo.log.delete.period=86400000
transaction.undo.log.table=undo_log
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registry-type=compact
metrics.exporter-list=prometheus
metrics.exporter-prometheus-port=9898
support.spring.datasource.autoproxy=false

将下图处修改为自己的服务组名,各个微服务之间使用不同的服务组名

执行nacos-config.sh脚本

官网seata-server-0.9.0的conf目录下有该文件,但是seata-server-1.0.0的conf目录下没有nacos-config.sh文件,新增或者从seata-server-0.9.0的conf目录下复制一份即可(对应seata-1.0.0源码里的nacos-config.sh文件,在script\config-center\nacos目录下,也可以下载源码,在源码里执行),内容如下:

#!/usr/bin/env bash

if [ $# != 1 ]; then

echo "./nacos-config.sh nacosIp"

exit -1

fi



nacosIp=$1

echo "set nacosIp=$nacosIp"

error=0



for line in $(cat nacos-config.txt)



do



key=${line%%=*}

value=${line#*=}

echo "\r\n set "${key}" = "${value}



result=`curl -X POST "http://$nacosIp:8848/nacos/v1/cs/configs?dataId=$key&group=SEATA_GROUP&content=$value"`



if [ "$result"x == "true"x ]; then



  echo "\033[42;37m $result \033[0m"



else



  echo "\033[41;37 $result \033[0m"

  let error++



fi



done





if [ $error -eq 0 ]; then



echo  "\r\n\033[42;37m init nacos config finished, please start seata-server. \033[0m"



else



echo  "\r\n\033[41;33m init nacos config fail. \033[0m"



fi

使用git工具git bash执行nacos-config.sh脚本,结果如下图:

执行完成后nacos会新增seata配置,如下图:

微服务配置

配置文件

以yml文件为例,添加服务组名配置,不同微服务使用相同服务组名

spring:
    cloud:
        alibaba:
            seata:
                tx-service-group: my_test_tx_group

 

启动类配置

添加@EnableDiscoveryClient以及@EnableAutoConfiguration注解

@EnableAutoConfiguration:是否开启spring-boot自动装配,如果开启,则会自动配置seata与spring-boot的集成,包括数据源的自动代理以及GlobalTransactionScanner初始化。 注:1.0版本新特性,需依赖seata-spring-boot-starter。

registry.conf

将registry.conf添加到项目resources的根目录,registry以及config的type同样选择nacos

registry {

  # file nacos
  type = "nacos"

  nacos {
    serverAddr = "localhost"
    namespace = ""
    cluster = "default"
  }

}


config {

  # file、nacos 、apollo、zk、consul
  type = "nacos"

  nacos {
    serverAddr = "localhost"
    namespace = ""
  }

}

使用

只需要使用一个 @GlobalTransactional 注解在业务方法上

package com.test;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.test.domain.A;
import com.test.domain.B;
import com.test.service.AService;
import com.test.service.BService;

import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;


@Service(version = "1.0.0")
public class TestServiceImpl implements TestService{

    @Reference(check = false,version="1.0.0")
    private AService aService;

    @Reference(check = false,version="1.0.0")
    private BService bService;

    @GlobalTransactional
    @Override
    public void add() {

        A a = new A();
        a.setName("123456");
        aService.addA(a);

        B b = new B();
        b.setName("123456");
        bService.addB(b);

        throw new RuntimeException("测试回滚, xid:" + RootContext.getXID());

    }

}

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐