irpas技术客

【SpringCloud Alibaba】Seta安装、处理分布式事务_See_Star_seta 分布式

未知 3554

🔰 学习视频 🔰

尚硅谷SpringCloud框架开发教程(SpringCloudAlibaba微服务分布式架构丨Spring Cloud)

🔰 项目地址 🔰

https://gitee.com/zqcliudaliuda/cloud2021


一、分布式问题

1对1:单机模式、一台服务器上有服务,另一台服务器上有数据库,两个相对应。 1对N:一台服务器上有服务,多台服务器上有数据库,一个调用多个。 N对N:N台服务器上有不同的服务,每个服务对应自己的一个数据库,如下面这个例子。

用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持: 仓储服务:对给定的商品扣除仓储数量。 订单服务:根据采购需求创建订单。 帐户服务:从用户帐户中扣除余额。

单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源,业务操作需要调用三三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证, 但是全局的数据一致性问题没法保证。

一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题

二、Seata简介

Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。

中文官网:https://seata.io/zh-cn/

2.1 术语

🔶 一ID和三组件模型

XID(Transaction ID) - 全局事务IDTC (Transaction Coordinator) - 事务协调者 维护全局和分支事务的状态,驱动全局事务提交或回滚。TM (Transaction Manager) - 事务管理器 定义全局事务的范围:开始全局事务、提交或回滚全局事务。RM (Resource Manager) - 资源管理器 管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

🔶 处理过程

TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID;XID在微服务调用链路的上下文中传播; .RM向TC注册分支事务,将其纳入XID对应全局事务的管辖;TM向TC发起针对XID的全局提交或回滚决议;TC调度XID下管辖的全部分支事务完成提交或回滚请求。

2.2 注解

只需要使用一个@GlobalTransactional注解在业务方法上:

三、安装 3.1 下载

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

下载完成后解压。

3.2 file.conf配置

先备份conf/file.conf再修改。

主要修改:自定义事务组名称+事务日志存储模式为db+数据库连接

自定义事务组名称 持久化方法改成数据库 配置数据库

3.3 数据库

创建数据库 使用seata-server-0.9.0\seata\conf\db_store.sql创建数据库表格。

创建完成后如下:

3.4 registry.conf配置

修改注册中心为nacos,且配置注册地址。

3.5 启动

运行seata-server-0.9.0\seata\bin\seata-server.bat

在nacos可查看到:

四、分布式业务测试

以下演示要先启动Nacos后再启动Seata。

这里我们会创建三个服务,一个订单服务, 一个库存服务, 一个账户服务。当用户下单时,会在订单服务中创建一个订单, 然后通过远程调用库存服务来扣减下单商品的库存,再通过远程调用账户服务来扣减用户账户里面的余额,最后在订单服务中修改订单状态为已完成。该操作跨越三个数据库,有两次远程调用,很明显会有分布式事务问题。

分布式事务业务说明:下订单——扣库存——减账户余额

4.1 数据库准备 4.1.1 数据库建立

seata_ order:存储订单的数据库; seata_ storage:存储库存的数据库; seata_ account:存储账户信息的数据库。

CREATE DATABASE seata_order; CREATE DATABASE seata_storage; CREATE DATABASE seata_account; 4.1.2 业务表

seata_order库下建t_order表

USE seata_order; CREATE TABLE t_order( `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id', `product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id', `count` INT(11) DEFAULT NULL COMMENT '数量', `money` DECIMAL(11,0) DEFAULT NULL COMMENT '金额', `status` INT(1) DEFAULT NULL COMMENT '订单状态:0创建中,1已完结' )ENGINE=INNODB AUTO_INCREMENT=7 CHARSET=utf8;

seata_storage库下建t_storage 表

USE seata_storage; CREATE TABLE t_storage( `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY , `product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id', `total` INT(11) DEFAULT NULL COMMENT '总库存', `used` INT(11) DEFAULT NULL COMMENT '已用库存', `residue` INT(11) DEFAULT NULL COMMENT '剩余库存' )ENGINE=INNODB AUTO_INCREMENT=7 CHARSET=utf8; INSERT INTO t_storage(id, product_id, total, used, residue) VALUES(1,1,100,0,100);

seata_account库下建t_account表

USE seata_account; CREATE TABLE t_account( `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY , `user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id', `total` DECIMAL(10,0) DEFAULT NULL COMMENT '总额度', `used` DECIMAL(10,0) DEFAULT NULL COMMENT '已用额度', `residue` DECIMAL(10,0) DEFAULT 0 COMMENT '剩余可用额度' )ENGINE=INNODB AUTO_INCREMENT=7 CHARSET=utf8; INSERT INTO t_account(id, user_id, total, used, residue) VALUES(1,1,1000,0,1000); 4.1.3 回滚日志表

找到\seata-server-0.9.0\seata\conf\db_undo_log.sql

在3个库当中分别运行。

4.2 微服务准备

可在Gitee内查看详细代码。

业务需求:下订单——减库存——扣余额——改订单状态

🔶 新建maven项目seata-order-service2001

🔶 POM依赖

<dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <groupId>seata-all</groupId> <artifactId>io.seata</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> <version>0.9.0</version> </dependency> <!-- SpringCloud alibaba sentinel--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!-- SpringCloud alibaba nacos--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- SpringCloud alibaba sentinel-datasource-nacos 持久化用的--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>

🔶 application.yaml配置

sserver: port: 2001 spring: application: name: seata-order-service cloud: nacos: discovery: server-addr: localhost:8848 alibaba: seata: # 自定义事务组名称需要与seata-server中的配置相对应。 tx-service-group: my_test_tx_group datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/seata_order username: root password: 123456

🔶 file.conf配置

复制之前配置好的file.conf到项目的resources目录下。

🔶 registry.conf配置

同样,复制之前配置好的registry.conf到项目的resources目录下。

🔶 其他

编写一些业务类、配置等。

4.3 测试

查看数据库中的当前的状态

SELECT * FROM `seata_order`.`t_order`; SELECT * FROM `seata_storage`.`t_storage`; SELECT * FROM `seata_account`.`t_account`;

🔶 正常下单

http://localhost:2001/order/create?userId=1&productId=1&count=10&money=100

{"code":200,"message":"订单创建成功","data":null}

未出任何问题的时候,三个数据库的数据都正常变化,该减少的减少,该增加的增加。

🔶 超时异常,没添加@GlobalTransactional

让账户业务超时20秒,看看效果

http://localhost:2001/order/create?userId=1&productId=1&count=10&money=100, 报错

当库存和账户金额扣减后,订单状态并没有设置为已经完成,没有从零改为1,而且由于feign的重试机制,账户余额还有可能被多次扣减。

🔶 超时异常,添加@GlobalTransactional

在order业务入口添加@GlobalTransactional注解,当产生异常时进行回滚,保证数据的正确。


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #seta #分布式