微服务:分布式事务

💥 该系列属于【SpringBoot基础】专栏,如您需查看其他SpringBoot相关文章,请您点击左边的连接

目录

一、引言

二、Seata

三、部署TC服务

[1. 准备数据库表](#1. 准备数据库表)

[2. 准备配置文件](#2. 准备配置文件)

[3. Docker部署](#3. Docker部署)

四、微服务集成Seata

[1. 引入依赖](#1. 引入依赖)

[2. 改造配置](#2. 改造配置)

[3. 启动项目,观察日志](#3. 启动项目,观察日志)

五、XA模式

[1. Seata的XA模式](#1. Seata的XA模式)

[2. 实现](#2. 实现)

六、AT模式

[1. Seata的AT模式](#1. Seata的AT模式)

[2. AT模式与XA模式最大的区别是什么?](#2. AT模式与XA模式最大的区别是什么?)

[3. 实现](#3. 实现)


一、引言

在分布式系统中,如果一个业务需要多个服务合作完成,而且每一个服务都有事务,多个事务必须同时成功或失败,这样的事务就是分布式事务。其中的每个服务的事务就是一个分支事务。整个业务称为全局事务。

参与事务的多个子业务在不同的微服务,跨越了不同的数据库。虽然每个单独的业务都能在本地遵循ACID,但是它们互相之间没有感知,不知道有人失败了,无法保证最终结果的统一,也就无法遵循ACID的事务特性了。

现以下情况之一就可能产生分布式事务问题:

  • 业务跨多个服务实现

  • 业务跨多个数据源实现

二、Seata

在众多的开源分布式事务框架中,功能最完善、使用最多的就是阿里巴巴在2019年开源的Seata了。

在Seata的事务管理中有三个重要的角色:

  • TC ( Transaction Coordinator ) - 事务协调者: 维护全局和分支事务的状态,协调全局事务提交或回滚。

  • TM (Transaction Manager) - 事务管理器: 定义全局事务的范围、开始全局事务、提交或回滚全局事务。

  • RM (Resource Manager) - 资源管理器: 管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

Seata的工作架构如图所示:

其中,TMRM 可以理解为Seata的客户端部分,引入到参与事务的微服务依赖中即可。将来TMRM 就会协助微服务,实现本地分支事务与TC之间交互,实现事务的提交或回滚。

TC服务则是事务协调中心,是一个独立的微服务,需要单独部署。

三、部署TC服务

1. 准备数据库表

Seata支持多种存储模式,但考虑到持久化的需要,我们一般选择基于数据库存储。执行提前准备的seata-tc.sql,导入数据库表:

2. 准备配置文件

准备了一个seata目录,其中包含了seata运行时所需要的配置文件:

将整个seata文件夹拷贝到虚拟机的/root目录:

3. Docker部署

在虚拟机的/root目录执行下面的命令:

bash 复制代码
docker run --name seata \
-p 8099:8099 \
-p 7099:7099 \
-e SEATA_IP=192.168.88.128 \
-v /root/seata:/seata-server/resources \
--privileged=true \
--network hmall \
-d \
seataio/seata-server:1.5.2

确保mysql,nacos和seata再同一个network hmall之下

四、微服务集成Seata

1. 引入依赖

为了方便各个微服务集成seata,我们需要把seata配置共享到nacos,因此item-service, cart-service和trade-service模块不仅仅要引入seata依赖,还要引入nacos依赖:

XML 复制代码
<!--统一配置管理-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  </dependency>
  <!--读取bootstrap文件-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-bootstrap</artifactId>
  </dependency>
  <!--seata-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
  </dependency>

2. 改造配置

在nacos上添加一个共享的seata配置,命名为shared-seata.yaml

然后,改造hm-trade,hm-cart和hm-item两个微服务模块:bootstrap.yaml

bash 复制代码
spring:
  application:
    name: trade-service # 服务名称
  profiles:
    active: dev
  cloud:
    nacos:
      server-addr: 192.168.150.101 # nacos地址
      config:
        file-extension: yaml # 文件后缀名
        shared-configs: # 共享配置
          - dataId: shared-jdbc.yaml # 共享mybatis配置
          - dataId: shared-log.yaml # 共享日志配置
          - dataId: shared-swagger.yaml # 共享日志配置
          - dataId: shared-seata.yaml # 共享seata配置

3. 启动项目,观察日志

bash 复制代码
docker logs -f seata 

集成seata成功。

五、XA模式

1. Seata的XA模式

Seata对原始的XA模式做了简单的封装和改造,以适应自己的事务模型,基本架构如图:

RM一阶段的工作:

  1. 注册分支事务到TC

  2. 执行分支业务sql但不提交

  3. 报告执行状态到TC

TC二阶段的工作:

  1. TC检测各分支事务执行状态

    1. 如果都成功,通知所有RM提交事务

    2. 如果有失败,通知所有RM回滚事务

RM二阶段的工作:

  • 接收TC指令,提交或回滚事务

XA模式的优点是什么?

  • 事务的强一致性,满足ACID原则

  • 常用数据库都支持,实现简单,并且没有代码侵入

XA模式的缺点是什么?

  • 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差

  • 依赖关系型数据库实现事务

2. 实现

首先,我们要在配置文件中指定要采用的分布式事务模式。我们可以在Nacos中的共享shared-seata.yaml配置文件中设置:

bash 复制代码
seata:
  data-source-proxy-mode: XA

其次,我们要利用@GlobalTransactional标记分布式事务的入口方法:

六、AT模式

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

1. Seata的AT模式

阶段一RM的工作:

  • 注册分支事务

  • 记录undo-log(数据快照)

  • 执行业务sql并提交

  • 报告事务状态

阶段二提交时RM的工作:

  • 删除undo-log即可

阶段二回滚时RM的工作:

  • 根据undo-log恢复数据到更新前

2. AT模式与XA模式最大的区别是什么?

简述AT模式与XA模式最大的区别是什么?

  • XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。

  • XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。

  • XA模式强一致;AT模式最终一致

可见,AT模式使用起来更加简单,无业务侵入,性能更好。因此企业90%的分布式事务都可以用AT模式来解决。

3. 实现

微服务对应的数据库中创建快照表undo_log:

sql 复制代码
-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) 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 KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';

执行结果:

在Nacos中的共享shared-seata.yaml配置文件中设置:(也可以不写,因为AT是默认值)

bash 复制代码
seata:
  data-source-proxy-mode: AT

其次,我们要利用@GlobalTransactional标记分布式事务的入口方法:

相关推荐
Bald Baby7 分钟前
JWT的使用
java·笔记·学习·servlet
刘大浪8 分钟前
后端数据增删改查基于Springboot+mybatis mysql 时间根据当时时间自动填充,数据库连接查询不一致,mysql数据库连接不好用
数据库·spring boot·mybatis
魔道不误砍柴功13 分钟前
实际开发中的协变与逆变案例:数据处理流水线
java·开发语言
陌小呆^O^35 分钟前
Cmakelist.txt之Liunx-rabbitmq
分布式·rabbitmq
dj244294570736 分钟前
JAVA中的Lamda表达式
java·开发语言
攻心的子乐38 分钟前
shell脚本启动springboot项目
spring boot
工业3D_大熊1 小时前
3D可视化引擎HOOPS Luminate场景图详解:形状的创建、销毁与管理
java·c++·3d·docker·c#·制造·数据可视化
szc17671 小时前
docker 相关命令
java·docker·jenkins
CP-DD1 小时前
Docker 容器化开发 应用
运维·docker·容器