分布式事务

       小编目前大一,刚开始着手学习微服务的相关知识,小编会把它们整理成知识点发布出来。我认为同为初学者,我把我对知识点的理解以这种代码加观点的方式分享出来不仅加深了我的理解,或许在某个时候对你也有所帮助,同时也欢迎大家在评论区分享你们的观点。

       知不足而奋进,望远山而前行。  

目录

概述

初始Seata

部署TC服务

微服务集成Seata

XA模式

AT模式


概述

       通过前面微服务保护中,我们知道当项目拆分到不同服务后,每个服务都有自己独立的数据库,独立的tomcat,所以事务的ACID的这种特性就没法满足了。例如下面我们订单服务调用了购物车服务和库存服务,如果调用库存服务出现失败,尽管可以通过抛出异常控制订单服务回滚,但是购物车服务不能感知到异常的。

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

初始Seata

        要想解决分布式事务的问题,我们就要用到另一个微服务的组件——Seata。首先我们来认识一下Seata。Seata是2019年一月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案。致力于提高性能和简单易用的分布式服务事务,为用户打造一站式的分布式解决方案。下面是Seata的官方网站。

seata.apache.org

        同样对于上面订单服务的例子,要想解决分布式事务,各个子事务之间必须能感知到彼此的事务状态,才能保证状态一致。但是微服务之间都是独立的,如果靠内部去知晓别的服务的状态,这肯定不合理,所以我们需要靠外部去完成这件事,正所谓当局者迷,旁观者清。所以我们就需要一个事务协调者,每个服务把自己成功或者失败都告诉事务协调者,一旦有一个服务失败,事务协调者就通知所有服务回滚。上面这只是思路,Seata在实现上肯定没有这么简单,相对来说会复杂一点。

        Seata事务管理中有三个重要的角色:TC-事务协调者,TM-事务管理器,RM-资源管理器。这三个角色的作用分别如下。

      看着似乎还是有点复杂的,但是不用担心,TM,RM这些我们只需要引入Seata对应的依赖就好了。  我们要做的主要就是两件事情,因为TC服务是在所有服务之外的,所以我们首先要去搭建TC服务,第二件事情就是引入Seata依赖,并做一些配置,就相当于与Seata集成。

部署TC服务

        接下来我们来看一下如何部署TC服务。主要分为三步,首先第一步准备数据库表,第二步准备配置文件,第三步进行Docker部署。

        第一步准备数据库表,Seata支持多种存储模式,但考虑到持久化的需要,我们一般选择基于数据库存储。运行完sql脚本后,我们就会得到四张表,第一张branch_table叫做分支表,存储分支事务的信息,第三张global_table叫做全局表,就用来存储全局事务的信息。第四个lock_table和distributed_lock就是锁,保证执行事务期间,线程的安全。

       第二步我们要准备配置文件。

            接着我们也是通过官方网站拿到seteal的配置文件上传到虚拟机/root目录下。

        第三步我们要进行Docker部署。

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

docker run --name seata \
-p 8099:8099 \
-p 7099:7099 \
-e SEATA_IP=你的ip地址 \
-v ./seata:/seata-server/resources \
--privileged=true \
--network hm-net \
-d \
seataio/seata-server:1.5.2

        这里我们要先保证mysql和nacos都在同一个非网桥网络中,如果不在可以通过下面命令进行添加。

docker network connect 网络名 容器名

         运行完毕后我们可以通过日志查看seata是否运行成功,接着我们去nacos看seata服务是否已经注册上来同时访问一下seata部署的端口。

        seata服务确实已经注册到了nacos中心。 

         seata7099端口也可以访问到。         

微服务集成Seata

        到现在我们已经完成了TC服务的部署,接着我们来实现微服务集成Seata,首先第一步还是引入与Seata相关的依赖,接着第二步我们要完成在appliaction.yml中添加配置,让服务找到TC服务地址。因为之前我们已经将seata服务注册到了nacos,所以我们可以动态配置服务地址。

        我们先去nacos添加seata的配置管理 ,这一块直接CV下面的配置,记得把ip地址改成你的虚拟机ip地址。

seata:
  registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址
    type: nacos # 注册中心类型 nacos
    nacos:
      server-addr: 你的ip地址:8848 # nacos地址
      namespace: "" # namespace,默认为空
      group: DEFAULT_GROUP # 分组,默认是DEFAULT_GROUP
      application: seata-server # seata服务名称
      username: nacos
      password: nacos
  tx-service-group: hmall # 事务组名称
  service:
    vgroup-mapping: # 事务组与tc集群的映射关系
      hmall: "default"

         接下来我们就可以去微服务集成了,第一步引入依赖没什么好说的,直接CV就好了。

    <!--统一配置管理-->
  <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>

        第二步配置seata,我们只需要在bootstrap中加入seata的共享配置就好了。

spring:
  application:
    name: item-service # 微服务名称
  profiles:
    active: dev
  cloud:
    inetutils:
      preferred-networks: 192.168.181.140 # 允许nacos外网访问的地址
    nacos:
      server-addr: 192.168.181.140 # nacos 地址
      config:
        file-extension: yaml  # 文件后缀名
        shared-configs:  # 共享配置
          - data-id: shared-jdbc.yaml # 共享mybatis配置
          - data-id: shared-log.yaml # 共享日志配置
          - data-id: shared-swagger.yaml # 共享日志配置
          - data-id: shared-seata.yaml # 共享seata配置

        接着我们就可以去启动服务了,接着我们再来看一下seata的日志,可以看到购物车,商品,订单服务都与seataTC服务建立了连接。

        到这里所有的准备工作就已经完成了,接着我们就可以利用seata去解决分布式事务问题。

XA模式

        seata为解决分布式事务问题提供了非常多的模式,其中最有代表性的的就是XA模式和AT模式。

        XA规范是X/Open组织定义的分布式事务处理标准,XA规范描述了全局的TM与局部的RM之间的接口,几乎所有主流的关系型数据库都对XA规范提供了支持。Seata的XA模式如下:

        观看上面的流程图其实不难发现总共分为两个阶段,一阶段的工作:1.RM注册分支事务到TC。2.RM执行分支业务sql但不提交。3.RM报告执行状态到TC。二阶段的工作:1.TC检测各分支事务执行状态,如果都成功,通知所有RM提交事务,如果有失败,同时所有RM回滚事务。2.RM接收TC指令,提交或回滚事务。

         通过分析流程我们不难知道XA模式的优点就是事务具有强一致性,满足ACID原则,另外常用数据库都支持,实现起来简单,并且没有代码侵入。而它的缺点就是因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差,另外它依赖关系型数据库实现事务。

        具体怎么实现XA模式呢?其实非常简单,就只有两步,第一步我们要修改application.yml文件(每个参与事务的微服务),开启XA模式,第二步就是给发起全局事务的入口方法添加@GlobalTransactional注解,本例中是OrderServiceImpl中的createOrder方法。

seata:
  data-source-proxy-mode: XA # 开启数据源代理的XA模式

        接着第二步在createOrder方法上加上@GlobalTransactional注解

    @Override
    @GlobalTransactional
    public Long createOrder(OrderFormDTO orderFormDTO) {
        // 1.订单数据
        ...
        // 2.保存订单详情
        ...
        // 3.清理购物车商品
        ...
        // 4.扣减库存
        ...
        return order.getId();
    }

        接着重启服务进行测试就好了。

AT模式

        Seata主推的是AT模式,AT模式同样是分阶段提交的事务模型,不过弥补了XA模型中资源锁定周期过长的缺陷。流程图如下:

        一阶段RM的工作:1.注册分支事务,2.记录undo-log(数据快照),3.执行业务sql并提交,4.报告事务状态。二阶段提交时RM的工作:删除undo-log即可。二阶段回滚时RM的工作:根据undo-log恢复数据到更新前。AT模式相比于XA模式就没有了数据等待,而是各自提交,这样性能就得到了很大的提升。但是AT模式能由于中间各自提交就没法满足强一致性,但是可以满足最终一致。

         接着我们来看一下如何实现AT模式,首先我们要添加一张有关at模式的数据库表到微服务对应的数据库中,这张表用来存储产生的数据快照。第二件事我们要修改application.yml文件,将事务模式修改为AT模式。

        第一件事即使把下面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';

        第二步事务模式改成AT,其实也可以不填,因为默认就是AT。

seata:
  data-source-proxy-mode: AT # 开启数据源代理的AT模式

        到这里我们直接就完成了AT模式的实现,直接重启服务进行测试就好了。提示一下undo_log看不到数据很正常,因为如过没问题就直接提交,然后数据快照就删除了,如果有问题,它回滚后也会删除,如果想看到数据可以通过打断点。

      到这里分布式事务的知识就差不多了,相信以后碰到分布式事务的问题,已经学会解决了。

      带着决心起床,带着满意入睡。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值