前言
在前面的文章中,我们已经探讨了分布式事务的概念,以及如何通过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/…
Seata实践
代码整合
需要注意的是,Seata 0.7.0以下版本不支持MyBatis批量插入。Seata适用于分布式微服务开发,特别是与Spring Cloud全家桶搭配使用。整合步骤如下:
- 每个微服务需创建
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服务器软件包(seata-server)。
-
整合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作为一款优秀的分布式事务解决方案,在简化分布式事务管理的同时,也带来了一定的性能和管理挑战。在实际应用中,需要根据项目需求和场景进行权衡和选择。