美文网首页
Seata分布式事务中间件Sample演示

Seata分布式事务中间件Sample演示

作者: RaiseHead | 来源:发表于2019-09-30 22:17 被阅读0次

    Seata(Simple Extensible Autonomous Transaction Architecture)是2019 年 1 月份蚂蚁金服和阿里巴巴共同开源的 分布式事务 解决方案。以 高效 并且对业务 0 侵入 的方式,解决 微服务 场景下面临的分布式事务问题。

    产生背景

    随着业务数据规模的快速发展,数据量越来越大,原有的单库单表模式逐渐成为瓶颈。这时需要对数据库进行了水平拆分,将原单库单表拆分成数据库分片。分库分表之后,原来在一个数据库上就能完成的写操作,可能就会跨多个数据库,这就产生了跨数据库事务问题。

    同时系统的访问量和业务复杂程度也在快速增长,单体系统架构逐渐成为业务发展瓶颈,将单业务系统拆分成多个业务系统,降低了各系统之间的耦合度,使不同的业务系统专注于自身业务,更有利于业务的发展和系统容量的伸缩。如何保证多个服务间的数据一致性成为一个难题。

    Seata产品模块

    产品模块

    如上图所示,Seata 中有三大模块,分别是 TM、RM 和 TC。 其中 TM 和 RM 是作为 Seata 的客户端与业务系统集成在一起,TC 作为 Seata 的服务端独立部署。

    在 Seata 中,分布式事务的执行流程:

    • TM 开启分布式事务(TM 向 TC 注册全局事务记录);
    • 按业务场景,编排数据库、服务等事务内资源(RM 向 TC 汇报资源准备状态 );
    • TM 结束分布式事务,事务一阶段结束(TM 通知 TC 提交/回滚分布式事务);
    • TC 汇总事务信息,决定分布式事务是提交还是回滚;
    • TC 通知所有 RM 提交/回滚 资源,事务二阶段结束。

    演示项目

    Seata提供了很多Demo工程,这里选择了springboot-dubbo-seata 项目,基于 Spring Boot + Dubbo 的示例。官方源码:https://github.com/seata/seata-samples

    此项目包含如下服务:

    • samples-business 业务服务
    • samples-account 账号服务
    • samples-order 订单服务
    • samples-storage 库存服务

    他们之间的关系如下图:

    调用关系

    数据准备

    使用Mysql创建seata数据库,执行初始化脚本db_seata.sql。

    /*
    Navicat MySQL Data Transfer
    
    Source Server         : account
    Source Server Version : 50614
    Source Host           : localhost:3306
    Source Database       : db_gts_fescar
    
    Target Server Type    : MYSQL
    Target Server Version : 50614
    File Encoding         : 65001
    
    Date: 2019-01-26 10:23:10
    */
    
    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for t_account
    -- ----------------------------
    DROP TABLE IF EXISTS `t_account`;
    CREATE TABLE `t_account` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `user_id` varchar(255) DEFAULT NULL,
      `amount` double(14,2) DEFAULT '0.00',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_account
    -- ----------------------------
    INSERT INTO `t_account` VALUES ('1', '1', '4000.00');
    
    -- ----------------------------
    -- Table structure for t_order
    -- ----------------------------
    DROP TABLE IF EXISTS `t_order`;
    CREATE TABLE `t_order` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `order_no` varchar(255) DEFAULT NULL,
      `user_id` varchar(255) DEFAULT NULL,
      `commodity_code` varchar(255) DEFAULT NULL,
      `count` int(11) DEFAULT '0',
      `amount` double(14,2) DEFAULT '0.00',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=64 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_order
    -- ----------------------------
    
    -- ----------------------------
    -- Table structure for t_storage
    -- ----------------------------
    DROP TABLE IF EXISTS `t_storage`;
    CREATE TABLE `t_storage` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `commodity_code` varchar(255) DEFAULT NULL,
      `name` varchar(255) DEFAULT NULL,
      `count` int(11) DEFAULT '0',
      PRIMARY KEY (`id`),
      UNIQUE KEY `commodity_code` (`commodity_code`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_storage
    -- ----------------------------
    INSERT INTO `t_storage` VALUES ('1', 'C201901140001', '水杯', '1000');
    
    -- ----------------------------
    -- Table structure for undo_log
    -- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
    -- ----------------------------
    DROP TABLE IF EXISTS `undo_log`;
    CREATE TABLE `undo_log` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `branch_id` bigint(20) NOT NULL,
      `xid` varchar(100) NOT NULL,
      `context` varchar(128) NOT NULL,
      `rollback_info` longblob NOT NULL,
      `log_status` int(11) NOT NULL,
      `log_created` datetime NOT NULL,
      `log_modified` datetime NOT NULL,
      `ext` varchar(100) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of undo_log
    -- ----------------------------
    SET FOREIGN_KEY_CHECKS=1;
    
    

    这里创建了4个表:t_account、t_order、t_storage、undo_log。
    其中undo_log是记录需要回滚的事务,其余是业务表。

    启动服务注册中心

    这里用的是alibaba的Nacos,请使用1.1.0版本,防止因为dubbo,nacos因版本不匹配出现的心跳请求出错的情况。

    v1.1.0地址:https://github.com/alibaba/nacos/releases/tag/1.1.0

    下载解压后在bin目录下执行startup.cmd即可启动,端口为8848

    通过浏览器可访问控制台:http://127.0.0.1:8848/nacos/index.html,默认用户名/密码为nacos/nacos。

    nacos控制台

    启动Seata Server

    从官网下载:https://github.com/seata/seata/releases。最新版本0.8.1

    下载解压后在斌目录下执行:

    seata-server.bat -p 8091 -h 127.0.0.1 -m file
    

    启动演示工程

    分别启动:samples-account、samples-order、samples-storage、samples-business

    启动前需要修改配置文件(application.properties),配置数据库连接:

    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/seata?useSSL=false&serverTimezone=Asia/Shanghai
    spring.datasource.username=root
    spring.datasource.password=123456
    

    ==注意==

    服务可能会启动失败

    2019-09-30 14:32:15.205 ERROR 7208 --- [Create-60221145] com.alibaba.druid.pool.DruidDataSource   : create connection SQLException, 
    url: jdbc:mysql://localhost:3306/seata?useSSL=false&serverTimezone=Asia/Shanghai, 
    errorCode 0, state 08001
    

    这是因为我本地的数据库是Mysql8,系统使用的mysql数据库驱动mysql-connector-java版本号为5.1.31。将版本升级就可以了。

    <!-- <mysql-connector.version>5.1.31</mysql-connector.version>  -->
    <mysql-connector.version>8.0.11</mysql-connector.version>
    

    启动后可通过nacos控制台看到服务是否已准备就绪:

    nacos控制台

    执行正常的请求

    使用curl请求http://localhost:8104/business/dubbo/buy

    请求数据:

    {
        "userId":"1",
        "commodityCode":"C201901140001",
        "name":"cup",
        "count":2,
        "amount":"100"
    }
    

    返回操作成功:

    C:\Users\WBPC1108>curl  -X POST -H "Content-Type:application/json" -d "{\"userId\":\"1\",\"commodityCode\":\"C201901140001\",\"name\":\"cup\",\"count\":2,\"amount\":\"100\"}" "http://localhost:8104/business/dubbo/buy"
    {"status":200,"message":"成功","data":null}
    

    查看数据变化。

    请求前:

    请求前数据

    请求后:

    请求后数据

    测试回滚请求

    修改samples-business工程里的BusinessServiceImpl类,主动抛出异常:

    if (!flag) {
      throw new RuntimeException("测试抛异常后,分布式事务回滚!");
    }
    

    请求返回错误信息,数据没变化:

    C:\Users\WBPC1108>curl  -X POST -H "Content-Type:application/json" -d "{\"userId\":\"1\",\"commodityCode\":\"C201901140001\",\"name\":\"cup\",\"count\":2,\"amount\":\"100\"}" "http://localhost:8104/business/dubbo/buy"
    {"timestamp":"2019-09-30T08:25:54.248+0000","status":500,"error":"Internal Server Error","message":"测试抛异常后,分布式事务回滚!","path":"/business/dubbo/buy"}
    

    相关文章

      网友评论

          本文标题:Seata分布式事务中间件Sample演示

          本文链接:https://www.haomeiwen.com/subject/okwhpctx.html