接之前一篇《Seata如何实现两阶段提交(2PC)分布式事务》,实际开发中seata基本不会用file存储和管理服务节点信息,下面小编将结合nacos来整合seata,实现XA和AT模式的灵活转换。
相关安装包可以自行前往官网下载:
registry.conf:
registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "nacos" nacos { application = "seata-tc-server" serverAddr = "127.0.0.1:8848" group = "DEFAULT_GROUP" namespace = "" cluster = "BJ" username = "nacos" password = "nacos" }}config { # file、nacos 、apollo、zk、consul、etcd3 type = "nacos" nacos { serverAddr = "127.0.0.1:8848" namespace = "" group = "SEATA_GROUP" username = "nacos" password = "nacos" dataId = "seataServer.properties" }}
seataServer.properties:
特别注意,为了让TC服务的集群可以共享配置,同样选择nacos作为统一配置中心。
# 数据存储方式,db代表数据库store.mode=dbstore.db.datasource=druidstore.db.dbType=mysqlstore.db.driverClassName=com.mysql.cj.jdbc.Driverstore.db.url=jdbc:mysql://localhost:3306/seata?useUnicode=true&rewriteBatchedStatements=truestore.db.user=rootstore.db.password=rootstore.db.minConn=5store.db.maxConn=30store.db.globalTable=global_tablestore.db.branchTable=branch_tablestore.db.queryLimit=100store.db.lockTable=lock_tablestore.db.maxWait=5000# 事务、日志等配置server.recovery.committingRetryPeriod=1000server.recovery.asynCommittingRetryPeriod=1000server.recovery.rollbackingRetryPeriod=1000server.recovery.timeoutRetryPeriod=1000server.maxCommitRetryTimeout=-1server.maxRollbackRetryTimeout=-1server.rollbackRetryTimeoutUnlockEnable=falseserver.undo.logSaveDays=7server.undo.logDeletePeriod=86400000# 客户端与服务端传输方式transport.serialization=seatatransport.compressor=none# 关闭metrics功能,提高性能metrics.enabled=falsemetrics.registryType=compactmetrics.exporterList=prometheusmetrics.exporterPrometheusPort=9898
sql脚本:
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;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;
以上是XA模式所需脚本,AT模式追加以下脚本:
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;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;
其中lock_table导入到TC服务关联的数据库,undo_log表导入到微服务关联的数据库。
启动seata:
图片
XA 规范 是 X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准,XA 规范描述了全局的TM与局部的RM之间的接口,几乎所有主流的数据库都对 XA 规范提供了支持。
XA是规范,目前主流数据库都实现了这种规范,实现的原理都是基于两阶段提交。
图片
图片
一阶段(准备阶段):
事务协调者向所有参与此次分布式事务的本地事务参与者发出指令,要求它们开始执行本地事务操作。
二阶段(提交/回滚阶段):
接收到“全局提交”指令的参与者将在本地正式提交其事务,释放之前持有的数据库锁,并确保事务操作永久记录于数据库。
图片
在分布式事务处理中,RM和TC按照两阶段提交协议执行各自的工作:
RM在一阶段的工作:
RM在数据库或其他资源上执行与分支事务相关的SQL操作,但并不提交这些变更,而是保持数据锁定状态以防止数据不一致。
完成本地操作后,RM向TC报告其分支事务的执行状态,包括成功或失败的信息。
TC在二阶段的工作:
若所有分支事务均执行成功,TC通知所有RM提交各自的事务。
若存在任何一个分支事务执行失败,TC则指示所有RM回滚各自的事务,以保证分布式事务的一致性。
RM在二阶段的工作:
如果是提交指令,则正式提交一阶段执行的SQL操作,并释放之前持有的锁。
如果是回滚指令,则撤销一阶段未提交的SQL操作,恢复至事务开始前的数据状态。
依赖引入:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.3.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <version>2.2.3.RELEASE</version> <exclusions> <!--版本较低,1.3.0,因此排除--> <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> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency></dependencies>
配置引入:
server: port: 8011spring: application: name: bank-11 datasource: url: jdbc:mysql://localhost:3306/bank1?characterEncoding=utf8&useSSL=false driver-class-name: com.mysql.jdbc.Driver username: root password: root cloud: nacos: server-addr: 127.0.0.1:8848seata: registry: type: nacos nacos: server-addr: 127.0.0.1:8848 namespace: "" group: DEFAULT_GROUP application: seata-tc-server # tc服务在nacos中的服务名称 username: nacos password: nacos tx-service-group: order_tx_group #自定义事务组名称需要与seata-server中的对应 data-source-proxy-mode: XA service: vgroup-mapping: order_tx_group: BJ # TC 集群(必须与seata-server保持一致)
bank22服务参考bank11配置即可,bank11调用bank22服务
@GlobalTransactional@Overridepublic void updateAccountBalance(String accountNo, Double amount) { log.info("******** Bank1 Service Begin ... xid: {}" , RootContext.getXID()); //张三扣减金额 baseMapper.updateAccountBalance(accountNo,amount); //向李四转账 String transfer = bank2Client.transfer(amount); if("fallback".equals(transfer)){ //调用李四微服务异常 throw new RuntimeException("调用李四微服务异常"); } //人为制造错误 if(amount > 100){ throw new RuntimeException("bank1 make exception amount > 100"); }}
XA模式的优点:
XA模式的缺点:
AT模式同样是分阶段提交的事务模型,不过却弥补了XA模型中资源锁定周期过长的缺陷。
阶段一(准备阶段)RM的工作:
当全局事务开始后,RM会为该事务涉及的本地事务创建并注册一个分支事务,将其纳入到全局事务的管理范围。
在执行业务SQL之前,RM会对当前事务要修改的数据进行前镜像的记录,即生成undo-log。这样在事务回滚时可以根据undo-log恢复到事务开始前的状态。
RM按照业务需求执行相应的SQL操作,并在本地将事务置为“预提交”状态,但不真正完成提交。
将分支事务的执行结果(成功或失败)汇报给协调者,等待协调者的下一步指令。
阶段二(提交阶段/回滚阶段)RM的工作:
如果协调者收到所有RM的反馈均为“准备成功”,则指示RM正式提交事务。此时,RM删除对应的undo-log,因为事务已成功提交,不再需要回滚信息。
若协调者决定全局事务需要回滚,RM会根据先前记录的undo-log恢复数据到事务开始前的状态,撤销在事务过程中对数据的所有更改,确保数据一致性。
修改配置:
seata: data-source-proxy-mode: AT # 默认就是AT
AT模式的优点:
- 一阶段完成直接提交事务,释放数据库资源,性能比较好
- 利用全局锁实现读写隔离
- 没有代码侵入,框架自动完成回滚和提交
AT模式的缺点:
- 两阶段之间属于软状态,属于最终一致
- 框架的快照功能会影响性能,但比XA模式要好很多
本文链接:http://www.28at.com/showinfo-26-70466-0.html利用Nacos实现Seata事务模式(XA与AT)的快速配置与灵活切换
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com