前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud Alibaba 实战教程10-seata1.3整合nacos实现分布式事务

SpringCloud Alibaba 实战教程10-seata1.3整合nacos实现分布式事务

作者头像
gang_luo
发布2021-02-04 11:11:04
7260
发布2021-02-04 11:11:04
举报
文章被收录于专栏:gang_luogang_luo

一、介绍

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

一个分布式事务链路需要多个系统参与, 不同的系统负责不同的角色. 一般来说, 分布式事务的参与者需要包含以下 3 个角色.

TC (Transaction Coordinator) - 事务协调者

维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器

定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

二、业务场景

用户进行下单操作,order-service提供创建订单接口,然后通过feign调用远程的accout-service进行账户余额扣减,再通过feign调用远程的product-service进行库存扣减操作。

在这个业务场景下,order-service、accout-service、product-service其中某一个服务发生异常就会造成分布式事务,比如fegin调用product-service时库存不足抛出了异常,那么order-service需要对订单进行回滚,account-service需要对余额进行回滚,这就会造成分布式事务的问题

三、下载最新版本及修改配置

3.1.下载seata-server

https://github.com/seata/seata/tags,这里选择v1.3.0 zip下载

3.2创建seata数据库并初始化以下3张表

代码语言:javascript
复制
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(96),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

3.3修改配置文件 conf/registry.conf文件

代码语言:javascript
复制
registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "192.168.2.6:8001"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "192.168.2.6:8001"
    namespace = ""
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
  }
}

3.4下载config.txt 添加配置

下载地址: https://github.com/seata/seata/tree/develop/script/config-center

放置在/conf目录下,修改文件如下内容(后续初始化至nacos后,可在nacos中修改)

service.vgroup_mapping.your−service−gruop=default,中间的{your-service-gruop}为自己定义的服务组名称,服务中的application.yaml文件里配置服务组名称。

工程中有3个服务,分别是order_service、account_service、product_service,所以配置如下

3.5下载执行脚本

执行脚本下载地址:https://github.com/seata/seata/tree/develop/script/config-center/nacos

这里注意一个地方,如果nacos不是默认端口8848,需要修改脚本文件

执行nacos-config.sh脚本

sh nacos-config.sh -h 192.168.2.6

-h 后面192.168.2.6为nacos地址

成功后提示init nacos config finished, please start seata-server

3.6登录nacos查看配置中心

3.7启动seata-server

./seata-server.bat

四、修改项目

4.1引入依赖

父pom

代码语言:javascript
复制
 <dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
	<version>2.2.0.RELEASE</version>
	<exclusions>
		<exclusion>
			<groupId>io.seata</groupId>
			<artifactId>seata-spring-boot-starter</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>io.seata</groupId>
	<artifactId>seata-spring-boot-starter</artifactId>
	<version>1.3.0</version>
</dependency>

子pom

代码语言:javascript
复制
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
	<exclusions>
		<exclusion>
			<groupId>io.seata</groupId>
			<artifactId>seata-all</artifactId>
		</exclusion>
		<exclusion>
			<groupId>io.seata</groupId>
			<artifactId>seata-spring-boot-starter</artifactId>
		</exclusion>
	</exclusions>
</dependency>

<dependency>
	<groupId>io.seata</groupId>
	<artifactId>seata-spring-boot-starter</artifactId>
</dependency>

4.2添加项目配置

代码语言:javascript
复制
seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: order_service_group
  config:
    type: nacos
    nacos:
      namespace:
      serverAddr: 192.168.2.6:8001
      group: SEATA_GROUP
      userName: "nacos"
      password: "nacos"
  registry:
    type: nacos
    nacos:
      application: seata-server
      serverAddr: 192.168.2.6:8001
      group: SEATA_GROUP
      namespace:
      userName: "nacos"
      password: "nacos"

五、启动项目测试

5.1测试前各表数据

order表

accont表

product表

5.2postman调试

从参数我们可以看出test账户对P002商品下单6个,一共300元

我们的余额满足,库存不满足,会抛出RuntimeException

5.3debug验证

order表中创建了订单

feign调用account_service扣除余额undo_log生成了记录

feign调用product_service扣除库存undo_log生成了记录

因为会库存不足,会抛出RuntimeException

放掉所有断点查看表数据是否有回滚

order表

accont表

product表

通过查看数据发现订单数据没有入库、库存、余额没有扣除,说明当出现异常时,数据有回滚,分布式事务有起作用

六、AT模式工作机制

以一个示例来说明整个 AT 分支的工作过程。

业务表:product

Field

Type

Key

id

bigint(20)

PRI

name

varchar(100)

since

varchar(100)

AT 分支事务的业务逻辑:

代码语言:javascript
复制
update product set name = 'GTS' where name = 'TXC';

一阶段

过程:

1、解析 SQL:得到 SQL 的类型(UPDATE),表(product),条件(where name = 'TXC')等相关的信息。

2、查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据。

代码语言:javascript
复制
select id, name, since from product where name = 'TXC';

得到前镜像:

id

name

since

1

TXC

2014

3、执行业务 SQL:更新这条记录的 name 为 'GTS'。

4、查询后镜像:根据前镜像的结果,通过 主键 定位数据。

代码语言:javascript
复制
select id, name, since from product where id = 1;

得到后镜像:

id

name

since

1

GTS

2014

5、插入回滚日志:把前后镜像数据以及业务 SQL 相关的信息组成一条回滚日志记录,插入到 UNDO_LOG 表中。

代码语言:javascript
复制
{
	"branchId": 641789253,
	"undoItems": [{
		"afterImage": {
			"rows": [{
				"fields": [{
					"name": "id",
					"type": 4,
					"value": 1
				}, {
					"name": "name",
					"type": 12,
					"value": "GTS"
				}, {
					"name": "since",
					"type": 12,
					"value": "2014"
				}]
			}],
			"tableName": "product"
		},
		"beforeImage": {
			"rows": [{
				"fields": [{
					"name": "id",
					"type": 4,
					"value": 1
				}, {
					"name": "name",
					"type": 12,
					"value": "TXC"
				}, {
					"name": "since",
					"type": 12,
					"value": "2014"
				}]
			}],
			"tableName": "product"
		},
		"sqlType": "UPDATE"
	}],
	"xid": "xid:xxx"
}

6、提交前,向 TC 注册分支:申请 product 表中,主键值等于 1 的记录的 全局锁

7、本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。

8、将本地事务提交的结果上报给 TC。

二阶段-回滚

1、收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。

2、通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。

3、数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理,详细的说明在另外的文档中介绍。

4、根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:

代码语言:javascript
复制
update product set name = 'TXC' where id = 1;

5、提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。

二阶段-提交

1、收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。

2、异步任务阶段的分支提交请求将异步和批量地删除相应 UNDO LOG 记录。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-02-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、介绍
  • 二、业务场景
  • 三、下载最新版本及修改配置
    • 3.1.下载seata-server
      • 3.2创建seata数据库并初始化以下3张表
        • 3.3修改配置文件 conf/registry.conf文件
          • 3.4下载config.txt 添加配置
            • 3.5下载执行脚本
              • 3.6登录nacos查看配置中心
                • 3.7启动seata-server
                • 四、修改项目
                  • 4.1引入依赖
                    • 4.2添加项目配置
                    • 五、启动项目测试
                      • 5.1测试前各表数据
                        • 5.2postman调试
                          • 5.3debug验证
                          • 六、AT模式工作机制
                            • 一阶段
                              • 二阶段-回滚
                                • 二阶段-提交
                                相关产品与服务
                                对象存储
                                对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档