文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

利用Nacos实现Seata事务模式(XA与AT)的快速配置与灵活切换

2024-11-30 01:37

关注

实现

相关安装包可以自行前往官网下载:

部署及配置seata

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=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://localhost:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=root
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功能,提高性能
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.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模式

XA 规范 是 X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准,XA 规范描述了全局的TM与局部的RM之间的接口,几乎所有主流的数据库都对 XA 规范提供了支持。

两阶段提交

XA是规范,目前主流数据库都实现了这种规范,实现的原理都是基于两阶段提交。

图片

图片

一阶段(准备阶段):

  1. 协调发起:

事务协调者向所有参与此次分布式事务的本地事务参与者发出指令,要求它们开始执行本地事务操作。

  1. 本地执行与状态反馈:

二阶段(提交/回滚阶段):

  1. 全局提交决定:
  1. 全局提交执行:

接收到“全局提交”指令的参与者将在本地正式提交其事务,释放之前持有的数据库锁,并确保事务操作永久记录于数据库。

  1. 全局回滚决定与执行:

Seata的XA模型

图片

在分布式事务处理中,RM和TC按照两阶段提交协议执行各自的工作:

RM在一阶段的工作:

  1. 分支事务注册:
  1. 本地事务操作:

RM在数据库或其他资源上执行与分支事务相关的SQL操作,但并不提交这些变更,而是保持数据锁定状态以防止数据不一致。

  1. 状态汇报:

完成本地操作后,RM向TC报告其分支事务的执行状态,包括成功或失败的信息。

TC在二阶段的工作:

若所有分支事务均执行成功,TC通知所有RM提交各自的事务。

若存在任何一个分支事务执行失败,TC则指示所有RM回滚各自的事务,以保证分布式事务的一致性。

RM在二阶段的工作:

如果是提交指令,则正式提交一阶段执行的SQL操作,并释放之前持有的锁。

如果是回滚指令,则撤销一阶段未提交的SQL操作,恢复至事务开始前的数据状态。

代码样例

依赖引入:


    
        org.springframework.boot
        spring-boot-starter-web
    
    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-nacos-discovery
        2.2.3.RELEASE
    
    
        org.springframework.cloud
        spring-cloud-starter-openfeign
        2.2.3.RELEASE
    
    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-seata
        2.2.3.RELEASE
        
            
            
                seata-spring-boot-starter
                io.seata
            
        
    
    
        io.seata
        seata-spring-boot-starter
        1.4.2
    
    
        com.baomidou
        mybatis-plus-boot-starter
        3.4.1
    
    
    
        mysql
        mysql-connector-java
        5.1.47
    
    
        org.projectlombok
        lombok
    

配置引入:

server:
  port: 8011

spring:
  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:8848

seata:
  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
@Override
public 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模式

AT模式同样是分阶段提交的事务模型,不过却弥补了XA模型中资源锁定周期过长的缺陷。

Seata的AT模型

阶段一(准备阶段)RM的工作:

  1. 注册分支事务:

当全局事务开始后,RM会为该事务涉及的本地事务创建并注册一个分支事务,将其纳入到全局事务的管理范围。

  1. 记录undo-log(数据快照):

在执行业务SQL之前,RM会对当前事务要修改的数据进行前镜像的记录,即生成undo-log。这样在事务回滚时可以根据undo-log恢复到事务开始前的状态。

  1. 执行业务sql并提交:

RM按照业务需求执行相应的SQL操作,并在本地将事务置为“预提交”状态,但不真正完成提交。

  1. 报告事务状态:

将分支事务的执行结果(成功或失败)汇报给协调者,等待协调者的下一步指令。

阶段二(提交阶段/回滚阶段)RM的工作:

  1. 提交阶段:

如果协调者收到所有RM的反馈均为“准备成功”,则指示RM正式提交事务。此时,RM删除对应的undo-log,因为事务已成功提交,不再需要回滚信息。

  1. 回滚阶段:

若协调者决定全局事务需要回滚,RM会根据先前记录的undo-log恢复数据到事务开始前的状态,撤销在事务过程中对数据的所有更改,确保数据一致性。

代码样例

修改配置:

seata:
  data-source-proxy-mode: AT # 默认就是AT

AT模式的优点:

  • 一阶段完成直接提交事务,释放数据库资源,性能比较好
  • 利用全局锁实现读写隔离
  • 没有代码侵入,框架自动完成回滚和提交

AT模式的缺点:

  • 两阶段之间属于软状态,属于最终一致
  • 框架的快照功能会影响性能,但比XA模式要好很多
来源:一安未来内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯