Seata分佈式事務中間件Sample演示

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。

啓動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控制檯看到服務是否已準備就緒:

執行正常的請求

使用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"}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章