让您轻松入门分布式事务Seata和分库分表sharding-sphere的整合
Posted 请叫我东子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了让您轻松入门分布式事务Seata和分库分表sharding-sphere的整合相关的知识,希望对你有一定的参考价值。
1.介绍
本篇将介绍,如何进行seata1.2.0、sharding-sphere4.1.0和dubbo2.7.5 的整合,以及使用nacos作为我们的配置中心和注册中心。如果你还是一个初学者,先建议学习一下,陈建斌的七步带你集成Seata 1.2 高可用搭建,这篇文章清楚的阐述了初学者容易遇到的5个问题,并且都提供完整的解决思路。
2.环境配置
-
mysql: 5.7.12
-
nacos: 1.2.1
-
spring-boot: 2.2.6.RELEASE
-
seata: 1.2.0
-
dubbo:2.7.5
-
sharding-sphere: 4.1.0
-
开发环境: jdk1.8.0
2.1 nacos安装
nacos下载:https://github.com/alibaba/nacos/releases/tag/1.2.1
Nacos 快速入门:https://nacos.io/en-us/docs/quick-start.html
sh startup.sh -m standalone
在浏览器打开Nacos web 控制台:http://127.0.0.1:8848/nacos/index.html
输入nacos的账号和密码 分别为nacos:nacos
这是时候naocs 就正常启动了。
2.2 seata1.2.0安装
2.2.1 在 Seata Release 下载最新版的 Seata Server 并解压得到如下目录:
.
├──bin
├──conf
└──lib
2.2.2 修改 conf/registry.conf 配置,
目前seata支持如下的file、nacos 、apollo、zk、consul的注册中心和配置中心。这里我们以nacos
为例。
将 type 改为 nacos
registry
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos
application = "seata-server"
serverAddr = "127.0.0.1:8848"
namespace = "40508bb4-179e-4c98-a2f1-c2c031c20b3c"
cluster = "default"
username = "worker2"
password = "xxxxxxx"
config
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos
serverAddr = "127.0.0.1:8848"
namespace = "40508bb4-179e-4c98-a2f1-c2c031c20b3c"
group = "SEATA_GROUP"
username = "worker2"
password = "xxxxxxx"
- serverAddr = “127.0.0.1:8848” :nacos 的地址
- namespace = “” :nacos的命名空间默认为``
- cluster = “default” :集群设置未默认
default
2.2.3 修改 conf/config.txt配置
service.vgroupMapping.order-service-seata-service-group=default
service.vgroupMapping.account-service-seata-service-group=default
service.vgroupMapping.storage-service-seata-service-group=default
service.vgroupMapping.business-service-seata-service-group=default
store.mode=db
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.datasource=druid
store.db.dbType=mysql
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true
store.db.user=root
store.db.password=123456
store.db.minConn=1
store.db.maxConn=3
store.db.global.table=global_table
store.db.branch.table=branch_table
store.db.query-limit=100
store.db.lockTable=lock_table
配置的详细说明参考官网:https://seata.io/zh-cn/docs/user/configurations.html
这里主要修改了如下几项:
- store.mode :存储模式 默认file 这里我修改为db 模式 ,并且需要三个表
global_table
、branch_table
和lock_table
- store.db.driverClassName: 0.8.0版本默认没有,会报错。添加了
com.mysql.jdbc.Driver
- store.db.datasource=dbcp :数据源 dbcp
- store.db.db-type=mysql : 存储数据库的类型为
mysql
- store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true : 修改为自己的数据库
url
、port
、数据库名称
- store.db.user=root :数据库的账号
- store.db.password=123456:数据库的密码
- service.vgroupMapping.order-service-seata-service-group=default
- service.vgroupMapping.account-service-seata-service-group=default
- service.vgroupMapping.storage-service-seata-service-group=default
- service.vgroupMapping.business-service-seata-service-group=default
2.2.4 db模式下的所需的三个表
数据库脚本位于https://github.com/seata/seata/tree/develop/script/server/db
这里我用的是mysql数据库,直接下载mysq.sql就可以了。
global_table
的表结构
CREATE TABLE `global_table` (
`xid` varchar(128) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`status` tinyint(4) NOT NULL,
`application_id` varchar(64) DEFAULT NULL,
`transaction_service_group` varchar(64) DEFAULT NULL,
`transaction_name` varchar(64) DEFAULT NULL,
`timeout` int(11) DEFAULT NULL,
`begin_time` bigint(20) DEFAULT NULL,
`application_data` varchar(2000) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
branch_table
的表结构
CREATE TABLE `branch_table` (
`branch_id` bigint(20) NOT NULL,
`xid` varchar(128) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`resource_group_id` varchar(32) DEFAULT NULL,
`resource_id` varchar(256) DEFAULT NULL,
`lock_key` varchar(128) DEFAULT NULL,
`branch_type` varchar(8) DEFAULT NULL,
`status` tinyint(4) DEFAULT NULL,
`client_id` varchar(64) DEFAULT NULL,
`application_data` varchar(2000) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
lock_table
的表结构
create table `lock_table` (
`row_key` varchar(128) not null,
`xid` varchar(96),
`transaction_id` long ,
`branch_id` long,
`resource_id` varchar(256) ,
`table_name` varchar(32) ,
`pk` varchar(32) ,
`gmt_create` datetime ,
`gmt_modified` datetime,
primary key(`row_key`)
);
2.2.5 将 Seata 配置添加到 Nacos 中
nacos导入脚本位于https://github.com/seata/seata/tree/develop/script/config-center/nacos
使用方法:
sh $SEATAPATH/script/config-center/nacos/nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 40508bb4-179e-4c98-a2f1-c2c031c20b3c -u worker-w xxxxxx
参数描述:
-
-h: host, 默认值 localhost.
-
-p: port, 默认值 is 8848.
-
-g: 配置分组 默认值 ‘SEATA_GROUP’.
-
-t: 命名空间.
-
-u: 用户名, nacos 1.2.0+ 之后添加权限验证 默认为“”
-
-w: 密码, nacos 1.2.0+ 之后添加权限验证 默认为“”
在 Nacos 管理页面应该可以看到Group 为SEATA_GROUP的配置
这样seata-sever就搭建完成。
3.sharding-sphere中seata柔性事务实现
3.1 实现原理
整合Seata AT
事务时,需要把TM
,RM
,TC
的模型融入到ShardingSphere
分布式事务的SPI
的生态中。在数据库资源上,Seata
通过对接DataSource
接口,让JDBC
操作可以同TC
进行RPC
通信。同样,ShardingSphere
也是面向DataSource
接口对用户配置的物理DataSource
进行了聚合,因此把物理DataSource
二次包装为Seata
的DataSource
后,就可以把Seata AT
事务融入到ShardingSphere
的分片中。
3.2实现原理图
3.3 实现的步骤
-
Init(Seata引擎初始化)
包含Seata柔性事务的应用启动时,用户配置的数据源会按seata.conf的配置,适配为Seata事务所需的DataSourceProxy,并且注册到RM中。 -
Begin(开启Seata全局事务)
TM控制全局事务的边界,TM通过向TC发送Begin指令,获取全局事务ID,所有分支事务通过此全局事务ID,参与到全局事务中;全局事务ID的上下文存放在当前线程变量中。 -
执行分片物理SQL
处于Seata全局事务中的分片SQL通过RM生成undo快照,并且发送participate指令到TC,加入到全局事务中。ShardingSphere的分片物理SQL是按多线程方式执行,因此整合Seata AT事务时,需要在主线程和子线程间进行全局事务ID的上下文传递,这同服务间的上下文传递思路完全相同。 -
Commit/rollback(提交Seata事务)
提交Seata事务时,TM会向TC发送全局事务的commit和rollback指令,TC根据全局事务ID协调所有分支事务进行commit和rollback。
4.sharding-sphere中seata的整合
4.1使用Spring-boot引入Maven依赖
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>$shardingsphere.version</version>
</dependency>
<!-- 使用BASE事务时,需要引入此模块 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-base-seata-at</artifactId>
<version>$sharding-sphere.version</version>
</dependency>
4.2.Seata的AT模式使用的BASE柔性事务管理器
在每一个分片数据库实例中执创建undo_log表(以MySQL为例)
CREATE TABLE IF NOT EXISTS `undo_log`
(
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'increment id',
`branch_id` BIGINT(20) NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(100) 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 NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME NOT NULL COMMENT 'modify datetime',
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
4.3.在classpath中增加seata.conf
client
application.id = example ## 应用唯一id
transaction.service.group = my_test_tx_group ## 所属事务组
4.4业务方发起全局事务,配置柔性事务类型
@GlobalTransactional(timeoutMills = 300000, name = "dubbo-gts-seata-example")
@Override
public ObjectResponse handleBusiness(BusinessDTO businessDTO)
TransactionTypeHolder.set(TransactionType.BASE);
//执行业务逻辑
备注:也可是使用注解@ShardingTransactionType
的形式
@GlobalTransactional(timeoutMills = 300000, name = "dubbo-gts-seata-example")
@ShardingTransactionType(TransactionType.BASE)
@Override
public ObjectResponse handleBusiness(BusinessDTO businessDTO)
//执行业务逻辑
5.案例实现
参考官网中用户购买商品的业务逻辑。整个业务逻辑由4个微服务提供支持:
- 库存服务:扣除给定商品的存储数量。
- 订单服务:根据购买请求创建订单。
- 帐户服务:借记用户帐户的余额。
- 业务服务:处理业务逻辑。
请求逻辑架构
5.1 源码地址
https://github.com/lidong1665/seata-spring-boot-dubbo-nacos-shardingsphere-examples
-
samples-common :公共模块
-
samples-account :用户账号模块
-
samples-order :订单模块
-
samples-storage :库存模块
-
samples-business :业务模块
5.2 数据库
注意: MySQL必须使用InnoDB engine
.
如下,并且每个库中都需要一个undo_log表
5.3 以账号服务为例
分析需要项目中所需要的配置
5.3.1 引入的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<artifactId>seata-spring-boot-dubbo-nacos-shardingsphere-examples</artifactId>
<packaging>pom</packaging>
<name>seata-spring-boot-dubbo-nacos-shardingsphere-examples</name>
<groupId>io.seata</groupId>
<version>1.2.0</version>
<description>Demo project for Spring Boot Dubbo</description>
<modules>
<module>samples-common-service</module>
<module>samples-account-service</module>
<module>samples-order-service</module>
<module>samples-storage-service</module>
<module>samples-business-service</module>
</modules>
<properties>
<springboot.verison>2.2.6.RELEASE</springboot.verison>
<java.version>1.8</java.version>
<mybatis-plus.version>2.3</mybatis-plus.version>
<nacos.version>0.2.3</nacos.version>
<lombok.version>1.16.22</lombok.version>
<dubbo.version>2.7.5</dubbo.version>
<nacos-client.verison>1.2.1</nacos-client.verison>
<seata.version>1.2.0</seata.version>
<netty.version>4.1.32.Final</netty.version>
<sharding-sphere.version>4.1.0</sharding-sphere.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>$springboot.verison</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>$springboot.verison</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>$springboot.verison</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>$dubbo.version</version>
<exclusions>
<exclusion>
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>$dubbo.version</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-config-spring -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-configcenter-nacos</artifactId>
<version>$dubbo.version</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>$dubbo.version</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metadata-report-nacos</artifactId>
<version>$dubbo.version</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.seata/seata-all -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<versionShardingShpere分库分表5-ShardingSphere分布式事务详解