Seata(Simple Extensible Autonomous Transaction Architecture)是一个简单可扩展的自治事务框架,由阿里巴巴于2019年开源。它提供了高性能和简单易用的分布式事务服务,支持多种事务模式,包括AT、TCC、SAGA和XA,以满足不同的业务场景需求。

原理说明

Seata实现事务回滚的原理主要基于两阶段提交协议(2PC),并结合了本地事务的ACID特性。以下是Seata事务回滚的关键步骤和原理:

  • 全局事务的启动

    服务调用Seata客户端发起全局事务,获取全局唯一的事务ID(XID)。这个XID在跨服务调用过程中通过上下文传播,使得各个微服务都能识别到同一全局事务。

  • 分支事务注册

    每个涉及分布式事务的服务在进行数据库操作前,会将其本地事务注册到TC(Transaction Coordinator),并与XID关联起来。

  • 事务执行与数据暂存

    在AT模式下,Seata通过代理数据库连接层,在本地事务执行过程中记录SQL操作前后的数据变化,保存为Undo LogRedo Log,以便后续回滚或重试。

  • 第一阶段(准备阶段)

    所有参与全局事务的分支事务首先尝试执行本地事务,并将准备提交的结果报告给TC。

  • 第二阶段(提交或回滚阶段)

    如果所有分支事务的第一阶段都成功,则TC通知所有RM(Resource Manager)进行全局提交,RM根据Undo Log和Redo Log完成最终提交。
    若有任何分支事务失败,则TC通知所有RM进行全局回滚,RM利用Undo Log回滚已变更的数据。

一、 环境搭建

安装MySQL

用于存储Seata所需的数据表,如全局事务表、分支事务表等。

安装Seata Server

1. 拉取Seata Docker镜像
从Docker Hub拉取Seata的官方镜像。打开终端或命令行界面,执行以下命令:

docker pull seataio/seata-server:latest

下载最新的Seata Server镜像到你的本地Docker环境。

2. 运行Seata Server容器
拉取完镜像后,使用以下命令启动Seata Server容器:

docker run -d --name seata-server -p 8091:8091 seataio/seata-server:latest

3. 验证Seata Server是否运行
Seata Server启动后,你可以通过浏览器访问http://localhost:8091/来查看Seata Server的管理界面,默认用户名和密码是seata/seata。

4. 创建Docker Compose文件
如果使用Docker Compose管理的容器,docker-compose.yml内容如下:

version: '3'
services:
  seata-server:
    image: seataio/seata-server:latest
    container_name: seata-server
    ports:
      - "8091:8091"

然后,通过以下命令启动Seata Server:

docker-compose up -d

二、代码工程配置

在项目的pom.xml文件中添加Seata的依赖,如下所示:

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.5</version> <!-- 使用Seata版本1.5 -->
</dependency>

在Spring Boot的配置文件中(如application.yml或application.properties),配置Seata的相关信息,包括服务组、事务服务组等。配置示例如下:

seata:
  enabled: true
  data-source-proxy-mode: AT
  tx-service-group: group1
  enable-auto-data-source-proxy: true
  service:
    vgroup-mapping:
      group1: cluster1
    grouplist:
      cluster1: 127.0.0.1:8091

三、 服务接入

添加注解:在需要进行分布式事务管理的方法上添加@GlobalTransactional注解,这样Seata就会自动管理这些方法的事务,示例如下。
假设业务流程如下图所示
在这里插入图片描述

    @Override
    @GlobalTransactional
    public Result createOrder(OrderDTO order) {
        // 维护当前服务的订单
        orderService.insert(order);

        // 库存服务扣减库存
        storageFeign.handleStock(order.getId(),order.getNum());

        // 计费服务计算金额
        Float money = calculateFeign.handleBill(order.getId(),order.getNum());

        // 缴费服务扣减用户余额
        Result result = payFeign.handlePay(order.getOperatorId(),money);
        return result;
    }

数据库配置:在数据库中初始化Seata所需的undo_log表,用于记录事务的回滚日志,sql如下。

DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `branch_id` bigint(20) NOT NULL COMMENT '分支事务ID',
  `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '全局事务唯一标识',
  `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '上下文',
  `rollback_info` longblob NOT NULL COMMENT '回滚信息',
  `log_status` int(11) NOT NULL COMMENT '状态,0正常,1全局已完成(防悬挂)',
  `log_created` datetime NOT NULL COMMENT '创建时间',
  `log_modified` datetime NOT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'AT模式回滚日志表' ROW_FORMAT = DYNAMIC;

四、 配置Nacos

将Seata的配置文件上传到Nacos配置中心,以便Seata Server和各个微服务能够动态获取配置,示例如下。

service.vgroupMapping.group1=cluster1
#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
store.mode=db
store.lock.mode=db
store.session.mode=db

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/order?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

确保nacos已经挂上seata服务后就可以开始进行测试使用了
在这里插入图片描述

五、 结语

虽然分布式事务在系统解耦方面能保持事务的一致性,但是在整合了seata这一类的事务统一中间件之后,不管中间件的性能多好,都会增加系统的复杂度和性能开销,在高并发的使用场景下尤为明显。

Logo

更多推荐