应用管理与运维平台 ServiceStage应用管理与运维平台 ServiceStage

更新时间:2021/07/27 GMT+08:00
分享

非微服务框架代码接入DTM样例指南

本章节以未使用DTM和使用DTM进行银行转帐进行比较,来演示DTM提供的高可靠分布式事务处理能力。

其中,使用到的非微服务框架代码样例在导入样例工程过程中准备的dtm-demo的dtm-origin项目中。

样例设计

非微服务框架代码样例中没有使用任何框架,样例流程如图1所示。

  • 组成:bankA服务、bankB服务、bankCenter服务。
  • 功能:bankCenter服务调用bankA和bankB服务进行初始化和转账等操作。
图1 非侵入样例代码设计流程

业务流程分析

  • 正常场景:BankA 转入 100,BankB 转出 100,两银行金额之和保持1000000000不变。
  • 异常场景:BankA 转入 100,发生异常情况,bankB转出失败,DTM会帮助回滚bankA的数据,两银行金额之和保持1000000000不变。

DTM全局事务发起者

定义非侵入样例本地场景事务发起端,调用bankA转入服务和bankB转出服务,同时概率抛出异常。

// com.huawei.dtm.client.service.TransferService.java
@DTMTxBegin(appName = "transfer-local")
public void transferLocal(int userId, int money) {
    bankAService.transferIn(userId, money);
    ExceptionUtils.addRuntimeException(50);
    bankBService.transferOut(userId, money);
}

样例中同时提供未使用DTM注解@DTMTxBegin的方法,代码如下所示。

// com.huawei.dtm.client.service.TransferService.java
public void transferLocalUnable(int userId, int money) {
    bankAService.transferIn(userId, money);
    ExceptionUtils.addRuntimeException(50);
    bankBService.transferOut(userId, money);
}

bankA服务

  • 增加数据源DTMDataSource
    // com.huawei.dtm.client.config.ClientConfig.java;
    @Bean(name = "bankADataSource")
    @ConfigurationProperties(prefix = "spring.datasource.banka")
    public DataSource bankADataSource() {
        return new DTMDataSource(datasource);
    }
    @Bean(name = "bankAJdbcTemplate")
    public JdbcTemplate bankAJdbcTemplate(@Qualifier("bankADataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
  • 实现转入业务逻辑
    // com.huawei.common.impl.BankAService.java 
    public void transferIn(int id, int money) {
        jdbcTemplate.update(DtmConst.TransferSql.TRANSFER_IN_SQL, money, id);
    }

bankB服务

  • 增加数据源DTMDataSource
    // com.huawei.dtm.client.config.ClientConfig.java;
    @Bean(name = "bankBDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.bankb")
    public DataSource bankDataSource() {
        return new DTMDataSource(datasource);
    }
    @Bean(name = "bankBJdbcTemplate")
    public JdbcTemplate bankJdbcTemplate(@Qualifier("bankBDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
  • 实现转出业务逻辑
    // com.huawei.common.impl.BankBService.java
    public void transferOut(int id, int money) {
        jdbcTemplate.update(DtmConst.TransferSql.TRANSFER_OUT_SQL, money, id);
    }

准备配置文件

配置dtm-client所需配置文件。

  1. 通过Maven执行clean、install,将工程进行打包,生成client服务的jar包。
  2. 登录创建好的弹性云服务器,将dtm-origin-client.jar包上传至弹性云服务器上,并在测试样例dtm-origin-client.jar包同级目录下新建“application.yaml”文件和“dtm-config”文件夹。
  3. 把下列配置拷贝到“application.yaml”文件中,参考表1,修改username、password和url为您创建好的数据库用户名、密码和地址,拷贝完成后保存退出。

    server:
      port: 8012
    
    spring:
      application:
        name: dtm-client
      datasource:
        bankb:
          username: ${db_user_name}
          password: ${db_user_pwd}
          url: jdbc:mysql://${db_ip}:3306/bankb?verifyServerCertificate=false&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
          driver-class-name: com.mysql.cj.jdbc.Driver
        banka:
          username: ${db_user_name}
          password: ${db_user_pwd}
          url: jdbc:mysql://${db_ip}:3306/banka?verifyServerCertificate=false&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
          driver-class-name: com.mysql.cj.jdbc.Driver
    表1 application.yaml配置文件参数详解

    参数

    说明

    db_user_name

    客户端MySQL数据库用户名。

    db_user_pwd

    客户端MySQL数据库的密码。

    db_ip

    客户端MySQL数据库业务数据库地址,分别为banka和bankb的地址。

  4. 在新建目录“dtm-config”下,新建配置文件“dtmClientConfig.properties”,将下列配置拷贝到配置文件“dtmClientConfig.properties”中,参考表2, 按实际修改auto-create-table-dtm-tran-info、dtm-app-name、sc-server-address和rpc-ssl-switch。

    auto-create-table-dtm-tran-info=on
    dtm-app-name=xxxx
    sc-server-address=xxxx
    rpc-ssl-switch=off
    表2 dtmClientConfig.properties配置文件参数详解

    参数

    说明

    auto-create-table-dtm-tran-info

    是否自动创建DTM事务表dtm_tran_info,用来记录事务信息。

    • on:自动创建
    • off:手动创建

    dtm-app-name

    应用名称,该配置项可从“应用管理与运维平台”分布式事务管理 DTM > 引擎实例界面中得到。

    sc-server-address

    服务中心地址,该配置项可从“应用管理与运维平台”分布式事务管理 DTM > 引擎实例界面中得到。

    rpc-ssl-switch

    SSL开关,该配置项可从“应用管理与运维平台”分布式事务管理 DTM > 引擎实例界面中得到。

    • on:开启SSL
    • off:关闭SSL

启动测试样例

  1. 登录ECS,在dtm-origin-client.jar包同级目录下,执行java -Dfile.encoding=utf-8 -jar dtm-origin-client.jar启动client服务。

    [0] 初始化数据库, 重置账号资金; 
    [1] 查询 Bank A 和 Bank B 余额; 
    [2] 非侵入用例 -> 不使用DTM事务 本地场景验证; 
    [3] 非侵入用例 -> DTM 事务 本地场景验证; 
    [4] TCC用例 -> DTM 事务 本地场景调用;
    [5] EXIT;
    请输入命令执行操作:

  2. 输入命令0,初始化数据库。

    2021-03-23 11:28:44.676 [main] INFO  c.h.d.c.service.TransferService - Init bankA initB success

  3. 输入命令1,查询帐号余额,结果如下图所示,两银行余额都是1000000。

    |--- userId ---|--- bankA-money ---|--- bankB-money ---|---- sum ----|
    |             0|            1000000|            1000000|      2000000|
    |             1|            1000000|            1000000|      2000000|
    |             2|            1000000|            1000000|      2000000|
    |             3|            1000000|            1000000|      2000000|
    |             4|            1000000|            1000000|      2000000|
    ......
    |           496|            1000000|            1000000|      2000000|
    |           497|            1000000|            1000000|      2000000|
    |           498|            1000000|            1000000|      2000000|
    |           499|            1000000|            1000000|      2000000|
    2021-03-23 11:30:36.985 [main] INFO  c.h.d.c.service.TransferService - Run finish. total a 500000000,total b 500000000,sum 1000000000

  4. 输入命令2,执行非侵入样例不使用DTM事务的本地场景验证。
  5. 可选:输入运行的线程数量、每个线程的事务数量以及发生异常的概率值,输入格式为“线程数量:单线程事务数量:异常概率”,结果如下图所示,出现数据不一致的情况。

    |--- userId ---|--- bankA-money ---|--- bankB-money ---|---- sum ----|
    |             0|            1000000|            1000000|      2000000|
    |             1|            1000000|            1000000|      2000000|
    [ERROR] user id: 2, bankA: 1000100, bankB: 1000000, total: 2000100
    [ERROR] user id: 3, bankA: 1000100, bankB: 1000000, total: 2000100
    |             4|            1000100|             999900|      2000000|
    ......
    |           496|            1000100|             999900|      2000000|
    |           497|            1000000|            1000000|      2000000|
    [ERROR] user id: 498, bankA: 1000100, bankB: 1000000, total: 2000100
    |           499|            1000000|            1000000|      2000000|
    2021-03-23 11:39:33.290 [main] INFO  c.h.d.c.service.TransferService - Run finish. total a 500030000,total b 499985800,sum 1000015800

  6. 输入命令0初始化数据库后再输入命令3,执行非侵入样例使用DTM事务的本地场景验证。
  7. 输入运行的线程数量、每个线程的事务数量以及发生异常的概率值,输入格式为“线程数量:单线程事务数量:异常概率”,结果如下图所示,可以发现数据保持一致。

    |--- userId ---|--- bankA-money ---|--- bankB-money ---|---- sum ----|
    |             0|            1000000|            1000000|      2000000|
    |             1|            1000000|            1000000|      2000000|
    |             2|            1000100|             999900|      2000000|
    |             3|            1000100|             999900|      2000000|
    |             4|            1000100|             999900|      2000000|
    ......
    |           496|            1000100|             999900|      2000000|
    |           497|            1000000|            1000000|      2000000|
    |           498|            1000000|            1000000|      2000000|
    |           499|            1000000|            1000000|      2000000|
    2021-03-23 11:42:45.033 [main] INFO  c.h.d.c.service.TransferService - Run finish. total a 500015200,total b 499984800,sum 1000000000

  8. 输入命令5,退出执行程序。
分享:

    相关文档

    相关产品