分布式事务框架Seata实践

一、介绍

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

Seata分TCTMRM三个角色,TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。

概念:

TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

二、服务端

用Nacos作为seata的注册中心和配置中心

1. Nacos下载安装及配置

1.1 Nacos下载安装

Nacos下载地址:https://github.com/alibaba/nacos/releases

解压 nacos-server-2.3.0.zip,创建nacos需要的数据库,并使用\nacos-server-2.3.0\nacos\conf\mysql-schema.sql 初始化表。

修改\nacos-server-2.3.0\nacos\conf\application.properties,打开以下配置的注释

修改\nacos-server-2.3.0\nacos\bin\startup.cmd 为单机模式运行

双击 startup.cmd 启动Nacos

浏览器输入:http://localhost:8848/nacos/ 

nacos2.3.0默认没有开启鉴权,如要开启,请看https://nacos.io/zh-cn/docs/v2/guide/user/auth.html

1.2 新建一个命名空间 seata_demo

新增命名空间后,在配置列表中就可以看到seata_demo这个tab

2.下载和配置Seata Server端(TC:事务协调者)

https://github.com/seata/seata/releases

目前(2024-1-27)最新版本为2.0.0 

2.1 创建seata数据库

  • 创建名为“seata”的数据库
  • 执行数据库脚本:..\seata-server-2.0.0\seata\script\server\db\mysql.sql

2.2 修改配置信息

解压后,打开文件 ..\seata-server-2.0.0\seata\conf\application.yml 

  • 修改配置中心类型:“seata.config.type”的值修改为nacos,并增加nacos地址信息
  • 修改注册中心类型:“seata.registry.type”的值修改为nacos,并增加nacos地址信息
  • 修改事务会话信息存储方式:“seata.store.mode”的值修改为db

注,“seata.store.mode”说明: 
file模式为单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高;
db模式为高可用模式,全局事务会话信息通过db共享,相应性能差些;
redis模式,性能较高,但存在事务信息丢失风险,请提前配置合适当前场景的redis持久化配置.

详细参数说明见:参数配置 | Apache Seata

2.3 导入配置信息到Nacos配置中心

使用https://github.com/apache/incubator-seata/tree/develop/script/config-center 的config.txt文件,并根据自己需要适当修改。

把文件https://github.com/apache/incubator-seata/blob/develop/script/config-center/config.txt 拷贝到目录“D:\projects\seata-server-2.0.0\seata”下;文件 https://github.com/apache/incubator-seata/blob/develop/script/config-center/nacos/nacos-config.sh拷贝到“\seata-server-2.0.0\seata\bin”目录下(对config.txt文件中的配置信息,如数据库信息做相应的修改,也可以在成功导入到Nacos以后通过Nacos修改)。因为是windows,所以通过GIT的命令行执行shell脚本。进入GIT安装目录双击执行“git-bash.exe”打开命令行窗口,进入到“nacos-config.sh”所在录目录,执行命令:

./nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 05efbaac-4222-4b84-9da0-c74462962098

如果nacos有密码,则后面增加“-u 用户 -w 密码”:

./nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 61fd843e-3484-4636-9216-2493013b8d05 -u 用户 -w 密码

......(省略部分信息)......

通过提示信息可以看到配置已经导入成功。刷新Nacos上的配置列表可以看到刚才导入的配置信息,如果有些配置需要调整,可以直接通过Nacos的界面操作进行修改。

参考:Nacos 配置中心 | Apache Seata

2.4 启动seata server:

双击 \seata-server-2.2.0\seata\bin\seata-server.bat 启动 seata

访问地址:http://localhost:7091/

默认用户名/密码:seata/seata

登录到Nacos上,看到seata服务已注册成功

2.5 遇到的问题

1、数据库连接url问题

Establishing SSL connection without server's identity verification is not recommended. 
According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. 
For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. 
You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.

解决:数据库连接url中增加“useSSL=true”

2、数据库驱动问题

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.

解决:

修改store.db.driverClassName=com.mysql.jdbc.Driver 为store.db.driverClassName=com.mysql.cj.jdbc.Driver

三、客户端

Seata管理的分布式事务的典型生命周期:

(1). TM要求TC开始一项新的全局事务。TC生成代表全局事务的XID。
(2). XID通过微服务的调用链传播。
(3). RM将本地事务注册为XID到TC的相应全局事务的分支。
(4). TM要求TC提交或回退相应的XID全局事务。
(5). TC驱动XID的相应全局事务下的所有分支事务以完成分支提交或回滚。

借鉴官方的例子,通过3个微服务来演示(AT模式)。

AT模式:基于支持本地ACDI事务的关系型数据库,根据两阶段提交协议的演变,一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。二阶段:提交,或通过一阶段的回滚日志进行反向补偿。(更多信息:http://seata.io/zh-cn/docs/overview/what-is-seata.html

三个服务:

  • 仓储服务(Storage) :对给定的商品扣除仓储数量。
  • 订单服务(Order)    :根据采购需求创建订单。
  • 帐户服务(Account):从用户帐户中扣除余额。

1. 数据库

创建数据库:`seata_demo_account`、`seata_demo_order`、`seata_demo_storage`,并为每个库创建对应的业务表:

-- 帐户服务(Account)`seata_demo_account`库表
CREATE TABLE `account_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `money` decimal(10,2) DEFAULT '0.00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 插入测试数据
INSERT INTO account_tbl (user_id, money) VALUES ('1001', 100);
INSERT INTO account_tbl (user_id, money) VALUES ('1002', 200);

-- 订单服务(Order)`seata_demo_order`库表
CREATE TABLE `order_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `commodity_code` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT '0',
  `money` decimal(10,2) DEFAULT '0.00',
  `cttime` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 插入测试数据
INSERT INTO storage_tbl (commodity_code, count) VALUES ('2001', 10);

-- 仓储服务(Storage) `seata_demo_storage`库表
CREATE TABLE `storage_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `commodity_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '商品代码',
  `count` int(11) DEFAULT '0' COMMENT '商品数量',
  `price` decimal(10,2) DEFAULT '1.00' COMMENT '商品单价',
  `cttime` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

在每个业务库中都创建`undo_log`表,用于记录回滚日志,业务数据更新前,会先把记录都保存在这张表,在业务异常时根据这张表的信息进行回滚。如果是正常提交事务,提交后,undo_log表中的对应记录会被删掉。

https://github.com/apache/incubator-seata/blob/2.x/script/client/at/db/mysql.sql

-- `seata_demo_account`, `seata_demo_order`, `seata_demo_storage`业务库中分别创建`undo_log`表
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';
ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);

2. 代码

seata_sample: seata示例代码

参考的官方示例:https://github.com/apache/incubator-seata-samples

附:官方脚本说明https://github.com/seata/seata/tree/1.4.1/script):

客户端的配置信息https://github.com/apache/incubator-seata/tree/2.x/script/client

目录说明:
at: AT模式下的 `undo_log` 建表语句
conf: 客户端的配置文件
saga: SAGA 模式下所需表的建表语句
spring: SpringBoot 应用支持的配置文件

服务端配置信息:https://github.com/apache/incubator-seata/tree/2.x/script/server

目录说明:
db: server 侧的保存模式为 `db` 时所需表的建表语句
docker-compose: server 侧通过 docker-compose 部署的脚本
helm: server 侧通过 Helm 部署的脚本
kubernetes: server 侧通过 Kubernetes 部署的脚本

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值