使用阿里的分布式事务框架Seata 来解决分布式事务
Seata 1.Seata安装和部署 1.1下载 在官网下载压缩包:Seata-Server下载 | Apache Seata
这里因为我跟着教程,所以使用1.4.2
1.2修改配置 修改conf下的refistry.conf配置文件
改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 registry { type = "nacos" nacos { application = "seata-tc-server" serverAddr = "127.0.0.1:8848" group = "DEFAULT_GROUP" namespace = "" cluster = "SH" username = "nacos" password = "nacos" } } config { type = "nacos" nacos { serverAddr = "127.0.0.1:8848" namespace = "" group = "SEATA_GROUP" username = "nacos" password = "nacos" dataId = "seataServer.properties" } }
1.3在nacos中添加配置 特别注意,为了让tc服务的集群可以共享配置,我们选择了nacos作为统一配置中心。因此服务端配置文件seataServer.properties文件需要在nacos中配好。
格式如下:
内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 store.mode =db store.db.datasource =druid store.db.dbType =mysql store.db.driverClassName =com.mysql.cj.jdbc.Driver store.db.url =jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true &rewriteBatchedStatements =true &characterEncoding =utf-8 &zeroDateTimeBehavior =convertToNull&serverTimezone=Asia/Shanghai 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.queryLimit =100 store.db.lockTable =lock_table store.db.maxWait =5000 server.recovery.committingRetryPeriod =1000 server.recovery.asynCommittingRetryPeriod =1000 server.recovery.rollbackingRetryPeriod =1000 server.recovery.timeoutRetryPeriod =1000 server.maxCommitRetryTimeout =-1 server.maxRollbackRetryTimeout =-1 server.rollbackRetryTimeoutUnlockEnable =false server.undo.logSaveDays =7 server.undo.logDeletePeriod =86400000 transport.serialization =seata transport.compressor =none metrics.enabled =false metrics.registryType =compact metrics.exporterList =prometheus metrics.exporterPrometheusPort =9898
1.4创建数据库表 首先需要创建一个数据库 来作为seata的数据库,数据库名要和配置中url设置的一样,我这里是叫seata
然后需要在这个数据库中创建seata所需要的表 ,这些表主要记录全局事务、分支事务、全局锁信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0 ;DROP TABLE IF EXISTS `branch_table`;CREATE TABLE `branch_table` ( `branch_id` bigint (20 ) NOT NULL , `xid` varchar (128 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , `transaction_id` bigint (20 ) NULL DEFAULT NULL , `resource_group_id` varchar (32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `resource_id` varchar (256 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `branch_type` varchar (8 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `status` tinyint(4 ) NULL DEFAULT NULL , `client_id` varchar (64 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `application_data` varchar (2000 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `gmt_create` datetime(6 ) NULL DEFAULT NULL , `gmt_modified` datetime(6 ) NULL DEFAULT NULL , PRIMARY KEY (`branch_id`) USING BTREE, INDEX `idx_xid`(`xid`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; DROP TABLE IF EXISTS `global_table`;CREATE TABLE `global_table` ( `xid` varchar (128 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , `transaction_id` bigint (20 ) NULL DEFAULT NULL , `status` tinyint(4 ) NOT NULL , `application_id` varchar (32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `transaction_service_group` varchar (32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `transaction_name` varchar (128 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `timeout` int (11 ) NULL DEFAULT NULL , `begin_time` bigint (20 ) NULL DEFAULT NULL , `application_data` varchar (2000 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `gmt_create` datetime NULL DEFAULT NULL , `gmt_modified` datetime NULL DEFAULT NULL , PRIMARY KEY (`xid`) USING BTREE, INDEX `idx_gmt_modified_status`(`gmt_modified`, `status`) USING BTREE, INDEX `idx_transaction_id`(`transaction_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; SET FOREIGN_KEY_CHECKS = 1 ;
1.5启动TC服务 进入bin目录,运行其中的seata-server.bat即可:
启动成功后,seata-server应该已经注册到nacos注册中心了。
打开浏览器,访问nacos地址:http://localhost:8848,然后进入服务列表页面,可以看到seata-tc-server的信息:
补充 如果启动后,控制台无限报错 可能是之前使用seata时事务回滚失败导致的。
可以删除bin目录下的sessionStore\root.data ,并清空数据库的branch_table和global_table
2.微服务集成seata 2.1引入依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-starter-alibaba-seata</artifactId > <exclusions > <exclusion > <artifactId > seata-spring-boot-starter</artifactId > <groupId > io.seata</groupId > </exclusion > </exclusions > </dependency > <dependency > <groupId > io.seata</groupId > <artifactId > seata-spring-boot-starter</artifactId > <version > 1.4.2</version > </dependency >
2.2修改配置文件 对需要使用seata的微服务,需要修改application.yml文件,添加一些配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 seata: registry: type: nacos nacos: server-addr: 127.0 .0 .1 :8848 namespace: "" group: DEFAULT_GROUP application: seata-tc-server cluster: SH tx-service-group: seata-demo service: vgroup-mapping: seata-demo: SH
2.3启动微服务 启动后nacos可以看到,服务已经正常启动了
查看seata控制台,每一个微服务都完成了注册RM、TM,那么就是正常集成了seata
3.XA模式 3.1基本架构 如图:
RM一阶段的工作:
① 注册分支事务到TC
② 执行分支业务sql但不提交
③ 报告执行状态到TC
TC二阶段的工作:
TC检测各分支事务执行状态
a.如果都成功,通知所有RM提交事务
b.如果有失败,通知所有RM回滚事务
RM二阶段的工作:
3.2优缺点 优点
事务的强一致性,满足ACID原则。
常用数据库都支持,实现简单,并且没有代码侵入
缺点
因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
依赖关系型数据库实现事务
3.3使用 Seata的starter已经完成了XA模式的自动装配,实现非常简单,步骤如下:
1)修改application.yml文件(每个参与事务的微服务),开启XA模式:
1 2 seata: data-source-proxy-mode: XA
2)给发起全局事务的入口方法添加**@GlobalTransactional**注解:
本例中是OrderServiceImpl中的create方法.
3)重启服务并测试
在没有开启全局事务前,如果库存不足,会导致余额减少但库存不变,也就是无法正常回滚
重启order-service,再次测试,发现无论怎样,三个微服务都能成功回滚。
4.AT模式 4.1基本架构 基本流程图:
阶段一RM的工作:
注册分支事务
记录undo-log(数据快照)
执行业务sql并提交
报告事务状态
阶段二提交时RM的工作:
阶段二回滚时RM的工作:
4.2AT与XA的区别 简述AT模式与XA模式最大的区别是什么?
XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。
XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。
XA模式强一致;AT模式最终一致
4.3优缺点 优点:
一阶段完成直接提交事务,释放数据库资源,性能比较好
利用全局锁实现读写隔离
没有代码侵入,框架自动完成回滚和提交
缺点:
两阶段之间属于软状态,属于最终一致
框架的快照功能会影响性能,但比XA模式要好很多
4.4使用 AT模式中的快照生成、回滚等动作都是由框架自动完成,没有任何代码侵入,因此实现非常简单。
只不过,AT模式需要一个表来记录全局锁 、另一张表来记录数据快照undo_log 。
1)导入数据库表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0 ;DROP TABLE IF EXISTS `undo_log`;CREATE TABLE `undo_log` ( `branch_id` bigint (20 ) NOT NULL COMMENT 'branch transaction id' , `xid` varchar (100 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'global transaction id' , `context` varchar (128 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'undo_log context,such as serialization' , `rollback_info` longblob NOT NULL COMMENT 'rollback info' , `log_status` int (11 ) NOT NULL COMMENT '0:normal status,1:defense status' , `log_created` datetime(6 ) NOT NULL COMMENT 'create datetime' , `log_modified` datetime(6 ) NOT NULL COMMENT 'modify datetime' , UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'AT transaction mode undo table' ROW_FORMAT = Compact; DROP TABLE IF EXISTS `lock_table`;CREATE TABLE `lock_table` ( `row_key` varchar (128 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , `xid` varchar (96 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `transaction_id` bigint (20 ) NULL DEFAULT NULL , `branch_id` bigint (20 ) NOT NULL , `resource_id` varchar (256 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `table_name` varchar (32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `pk` varchar (36 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `gmt_create` datetime NULL DEFAULT NULL , `gmt_modified` datetime NULL DEFAULT NULL , PRIMARY KEY (`row_key`) USING BTREE, INDEX `idx_branch_id`(`branch_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; SET FOREIGN_KEY_CHECKS = 1 ;
2)修改application.yml文件,将事务模式修改为AT模式即可:
1 2 seata: data-source-proxy-mode: AT
3)重启服务并测试
5.TCC模式 5.1基本架构 Seata中的TCC模型依然延续之前的事务架构,如图:
5.2优缺点 TCC模式的每个阶段是做什么的?
Try:资源检查和预留
Confirm:业务执行和提交
Cancel:预留资源的释放
优点
一阶段完成直接提交事务,释放数据库资源,性能好
相比AT模型,无需生成快照,无需使用全局锁,性能最强
不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库
缺点
有代码侵入,需要人为编写try、Confirm和Cancel接口,太麻烦
软状态,事务是最终一致
需要考虑Confirm和Cancel的失败情况,做好幂等处理