文档首页 > > 开发指南> Java SDK> Spring Cloud开发> 接入分布式事务引擎DTM

接入分布式事务引擎DTM

分享
更新时间: 2020/01/19 GMT+08:00

DTM设计思想

在微服务架构下,一次请求调用多个服务,每个服务独享数据库,通过接口隔离,因此数据的一致性受到很大影响。 使用两阶段提交(2PC)将会导致性能大幅下降,增加数据库的压力,而且数据库相对于业务服务来说,难以伸缩。

DTM采用了TCC的分布式事务设计模式,相对于两阶段提交来说,性能更高,不会对数据库的数据加锁。开发人员只需要通过 注解标示分布式事务的参数,无需自己控制事务的逻辑,DTM以服务的形式提供给开发者,降低了开发难度。

步骤说明如下:

步骤1:进入到发起全局事务的方法内时,会先向DTM集群申请注册一个全局事务ID(Global Transaction ID),只有申请成功才可继续后续流程。

步骤2.1:事务发起者将申请到的全局事务ID透传到所调用的事务参与者中。

步骤2.2:事务参与者利用得到的全局事务ID,向DTM集群注册申请一个分支事务ID(Branch Transaction ID),只有申请成功才可继续此事务参与者的后续流程。

步骤2.3:事务参与者完成自身业务逻辑(即完成TCC中的Try阶段)。

步骤2.4:事务参与者将自身业务逻辑结果上传到DTM集群,并示意分支事务结束。

步骤3.1~3.4:与2.1~2.4类似,完成剩余事务参与者的业务逻辑。

步骤4:事务发起者发起TCC二阶段。

步骤5.1:DTM集群根据全局事务ID,找到事务参与者,发起TCC二阶段。

步骤5.2:与5.1类似,完成剩余事务参与者的TCC二阶段。

步骤6:DTM集群通告事务发起者全局事务结束。

前提条件

开始前需要在ServiceStage创建微服务引擎分布式事务引擎

快速开始

  1. 引入下面依赖。

    <dependency>
      <groupId>com.huaweicloud</groupId>
      <artifactId>spring-cloud-starter-huawei-dtm</artifactId>
    </dependency>

  2. 新建Project或module,定义全局事务,支持通过RestTemplate和Feign两种模式调用分支事务。

    1. 通过配置文件(application.yml)定义事务信息。
      dtm:
        appName: reserve #应用名称
        rpc:
          sslEnabled: true  #是否启用ssl
        proxy:
          endpoint: https://192.168.0.5:30125 #dtm服务地址,从dtm引擎中获取
    2. 通过注解DTMTxBegin定义全局事务。
        @DTMTxBegin(appName = "reserve")
        public String getOrder(@RequestParam("id") String id) {
          String discountCouponResult = restTemplate.getForObject("http://coupon/discountCoupon?id=" + id, String.class);
          LOGGER.info("bookRoomResult:" + discountCouponResult);
          String bookTicketResult = restTemplate.getForObject("http://ticket/bookTicket?id=" + id, String.class);
          LOGGER.info("bookTicketResult:" + bookTicketResult);
          return discountCouponResult + "-------" + bookTicketResult;
        }
      }

  3. 新建Project或module,定义分支事务。

    1. 通过配置文件(application.yml)定义事务信息
      dtm:
        appName: coupon #应用名称
        rpc:
          sslEnabled: true  #是否启用ssl
        proxy:
          endpoint: https://192.168.0.5:30125 #dtm服务地址,从dtm引擎中获取
    2. 通过注解DTMTccBranch定义分支事务,放到"try"方法上,通过confirmMethod和cancelMethod定义确认和回滚方法。
        @GetMapping(value = "/discountCoupon")
        @DTMTccBranch(identifier = "coupon", confirmMethod = "confirm", cancelMethod = "cancel")
        public void discountCoupon() throws InterruptedException {
          //try,预留资源,判断是否可以执行。如库存服务,可以在数据库中增加字段,预减库存
        }
      
        public void confirm() {
          //confirm,可以理解为事务提交,如库存服务,真正的把预留的库存扣掉
        }
      
        public void cancel() {
          //cancel,回滚方法,当出现异常的时候调用此方法释放资源,如库存服务,释放预留库存
        }

  4. 在huaweicloud分布式事务控制面板上查看事务执行情况。

运行Demo

通过项目中的示例开始分布式事务,spring-cloud-huawei-sample/dtm-demo下提供了四个工程,用来模拟spring cloud工程使用华为云ServiceStage分布式事务的场景:

  • reserve:预订服务使用RestTemplate,事务发起方。
  • reserve-feign:预订服务使用Feign,事务发起方。
  • coupon:优惠券服务,分支事务。
  • ticket:票务服务,分支事务。

运行demo步骤如下。

  1. 修改配置文件。

    路径为: /src/main/resources/application.yaml
    dtm:
      appName: reserve  ##应用名称
      rpc:
        sslEnabled: true  ##开启SSL验证,华为云目前必须开启
      proxy:
        endpoint: https://192.168.X.XXX:30125 ##dtm服务的地址

  2. 生成docker镜像,并推送到镜像仓库。

    以reverse为例,示例命令如下。

    cd spring-cloud-huawei/spring-cloud-huawei-sample/dtm-demo/reserve docker build -t reserve:0.1 . 

    打tag,这里需要跟云上的路径和组织相对应,示例命令如下。

    docker tag reserve:0.1  swr.cn-north-4.myhuaweicloud.com/wang/reserve:0.1 

    推送到镜像仓库,示例命令如下。

    docker push swr.cn-north-4.myhuaweicloud.com/wang/reserve:0.1

    重复此步骤,完成reserve-feign、coupon、ticket构建归档。

  3. 应用部署

    进入应用列表创建应用,选择ServiceComb引擎,创建应用。应用配置说明如下。

    1. 框架选择:Java chassis。
    2. 运行环境选择:docker。
    3. 部署系统选择:云容器引擎CCE。
    4. 设置集群。
    5. 应用来源选择生成的镜像。
    6. 开启外网访问。
    7. 端口填写8080。
    8. 设置访问方式。
    9. 微服务引擎使用专业版微服务引擎。
    10. 其他配置使用默认。

    重复以上步骤,分别部署reserve-feign、coupon、ticket三个应用。

  4. 验证事务

    通过生成的域名地址访问应用,示例如下。

      http://xxxx/reverse?id=1

    正常页面会返回成功,日志中会有响应的日志记录。

    查看dtm控制台,历史事务,会有相应的事务提交记录。

  5. 回滚

    如果要验证回滚,可以将ticket或者coupon停掉,活跃事务中会看到事务一直在等待重试, 当停掉的事务重新启动后,事务会再次提交,示例中可以在日志中看到。

    如果要验证超时,示例如下。

      http://xxxx/reverse?id=sleep 

    ticket会一直在Confirm方法中阻塞,同样可以通过日志和dtm控制台看到相应情况。

通过RestTemplate使用DTM分布式事务

如果使用RestTemplate实现DTM分布式事务,代码仅需要增加注解, 通过注解DTMTxBegin定义全局事务。

  @DTMTxBegin(appName = "reserve")
  public String getOrder(@RequestParam("id") String id) {
    String discountCouponResult = restTemplate.getForObject("http://coupon/discountCoupon?id=" + id, String.class);
    LOGGER.info("bookRoomResult:" + discountCouponResult);
    String bookTicketResult = restTemplate.getForObject("http://ticket/bookTicket?id=" + id, String.class);
    LOGGER.info("bookTicketResult:" + bookTicketResult);
    return discountCouponResult + "-------" + bookTicketResult;
  }
}
) 

通过注解DTMTccBranch定义分支事务,放到"try"方法上。通过confirmMethod和cancelMethod定义确认和回滚方法。

  @GetMapping(value = "/discountCoupon")
  @DTMTccBranch(identifier = "coupon", confirmMethod = "confirm", cancelMethod = "cancel")
  public void discountCoupon() throws InterruptedException {
    //try,预留资源,判断是否可以执行。如库存服务,可以在数据库中增加字段,预减库存
  }

  public void confirm() {
    //confirm,可以理解为事务提交,如库存服务,真正的把预留的库存扣掉
  }

  public void cancel() {
    //cancel,回滚方法,当出现异常的时候调用此方法释放资源,如库存服务,释放预留库存
  }

通过Feign使用DTM分布式事务

DTM使用方法与RestTemplate用法相同

分享:

    相关文档

    相关产品

文档是否有解决您的问题?

提交成功!

非常感谢您的反馈,我们会继续努力做到更好!

反馈提交失败,请稍后再试!

*必选

请至少选择或填写一项反馈信息

字符长度不能超过200

提交反馈 取消

如您有其它疑问,您也可以通过华为云社区问答频道来与我们联系探讨

跳转到云社区