简述分布式事务解决方案第三篇——Seata管理

207 阅读5分钟

前言

在前面的文章中,我们已经探讨了分布式事务的概念,以及如何通过XA协议和TCC三段提交来解决分布式服务中的事务问题。然而,这两种方法都有其局限性:XA协议较为古老,而TCC实现起来较为复杂。那么,是否存在一种第三方框架,能够轻松整合到现有项目中,将本地事务转换为全局分布式事务呢?本文将为您介绍这样一种解决方案——阿里巴巴提出的Seata。

Seata介绍及其原理

Seata是一款高性能、简单易用的开源分布式事务解决方案,旨在为用户提供一站式的分布式事务服务。Seata支持AT、TCC、SAGA和XA四种事务模式,以满足不同场景的需求。

在Seata分布式事务中,有两个核心角色:TC(Transaction Coordinator)TM(Transaction Manager)。TC负责维护全局和分支事务的状态,并驱动全局事务的提交或回滚。TM则负责定义全局事务的范围,包括开始、提交或回滚全局事务。

Seata的核心机制之一是二阶段提交。在第一阶段,Seata会开启一个全局事务,并生成一个全局唯一的XID。接着,Seata通过RPC框架(如Dubbo、Spring Cloud等)将XID传播到各个业务服务的参与者中,并开启相应的分支事务。参与者根据业务逻辑进行数据修改,并记录undo和redo日志。当所有参与者都执行完毕后,会向TC注册分支并上报状态。

在第二阶段,若所有分支均执行成功,TC会向所有参与者发送全局提交命令;若有任何一个分支执行失败,TC则会发送全局回滚命令。参与者根据第一阶段记录的日志进行数据恢复操作。

更多详细信息,请访问Seata官方网站:seata.io/zh-cn/docs/…

image.png

Seata实践

代码整合

需要注意的是,Seata 0.7.0以下版本不支持MyBatis批量插入。Seata适用于分布式微服务开发,特别是与Spring Cloud全家桶搭配使用。整合步骤如下:

  1. 每个微服务需创建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;

  1. 安装事务协调器:下载并解压Seata服务器软件包(seata-server)。

  2. 整合Spring Cloud,导入相关依赖,并修改配置文件,具体步骤如下: 导入依赖spring-cloud-starter-alibaba-seata  导入seata-all-0.7.1,在去找到服务器软件包为seata-all-0.7.1

<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

解压并启动seata-server,启动前需要修改Seata两个重要的配置文件

registry.conf:修改配置中心地址,注册中心配置 type = "nacos"

  type = "nacos"

  nacos {
    serverAddr = "120.24.79.44"
    namespace = "public"
    cluster = "default"
  }

file.conf 事务日志存储 

所有想要用到分布式事务的微服务使用seata  DataSourceProxy代理自己的数据源,并修改service指定,用注册nacos的微服务名称

store {
  ## store mode: file、db
  mode = "db"

  ## file store
  file {
    dir = "sessionStore"

    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    max-branch-session-size = 16384
    # globe session size , if exceeded throws exceptions
    max-global-session-size = 512
    # file buffer size , if exceeded allocate new buffer
    file-write-buffer-cache-size = 16384
    # when recover batch read size
    session.reload.read_size = 100
    # async, sync
    flush-disk-mode = async
  }

  ## database store
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "dbcp"
    ## mysql/oracle/h2/oceanbase etc.
    db-type = "mysql"
    url = "jdbc:mysql://127.0.0.1:3306/seata"
    user = "mysql"
    password = "mysql"
    min-conn = 1
    max-conn = 3
    global.table = "global_table"
    branch.table = "branch_table"
    lock-table = "lock_table"
    query-limit = 100
  }
}
service {
  #vgroup->rgroup
  vgroup_mapping.微服务名称-fescar-service-group = "default"
  #only support single node
  default.grouplist = "127.0.0.1:8091"
  #degrade current not support
  enableDegrade = false
  #disable
  disable = false
  #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
}

在原有项目的每个微服务,到拷贝这个两个配置文件到源文件目录中

registry.conf

file.conf 

启动测试分布式事务

给分布式大事务入口标注 @GlobalTransactional


    @GlobalTransactional
    public void purchase(String userId, String commodityCode, int orderCount) {
        ......
    }

启动测试分布式事务

在分布式大事务入口处添加@GlobalTransactional注解,每个服务小事务管理添加@Transactional注解。

Seata优缺点

优点

  • 简单易用:Seata提供了丰富的客户端API和文档,便于用户快速上手和管理分布式事务。
  • 高性能:基于两阶段提交协议,Seata具有较高的性能表现。
  • 可扩展性:支持多种数据源和数据库类型,易于与其他服务集成。
  • 安全性:提供数据加密和身份验证等安全机制,确保分布式事务的安全性。

缺点

  • 依赖数据库锁:Seata的分布式事务解决方案依赖于数据库锁,可能对数据库性能产生影响。
  • 难以管理:随着业务发展,分布式事务数量和管理难度可能增加,需要用户手动管理和维护。
  • 缺乏灵活性:基于两阶段提交协议,可能在某些场景下限制用户的灵活性和可扩展性。

总之,Seata作为一款优秀的分布式事务解决方案,在简化分布式事务管理的同时,也带来了一定的性能和管理挑战。在实际应用中,需要根据项目需求和场景进行权衡和选择。