• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

Spring Cloud 整合 Nacos 1.3.1 + Seata 1.2.0 集群部署(Windows版)

java 来源:扛麻袋的少年 7次浏览

本文目录:

写在开头

  接上一篇文章:Spring Cloud Alibaba Seata 分布式事务解决方案简介。简单的了解 Seata 过后,我们来进入实战阶段。

  Seata 官方部署 新人文档 ,不由的想再次吐槽。部署比较简单,但是初学者直接部署 1.x 以上版本好困难的说,文档看的你是一脸懵逼。网上教程真是多,但是写的都太简单,新人入手真心看不懂。我也研究了2天才全套部署成功,现在以博客的方式分享给大家。有错误也请提出,谢谢

1.环境说明

  本文 Seata 1.2.0 部署,参照官方部署 新人文档 操作。

  部署环境+版本: MySQL 5.7.x + Nacos 1.3.1 + Seata 1.2.0 + Windows 环境演示,Linux 部署类似。

不了解 Nacos?请参考:

  1. Spring Cloud Alibaba Nacos 用于服务注册和配置中心
  2. Nacos 集群搭建和持久化配置

2. Seata 开始部署

2.1 Seata 1.2.0 下载

  进入 Seata 官网下载地址 或者 Seata Github下载地址,选择 Seata 1.2.0 版本下载。

2.2 新人文档中的资源目录介绍

  需要重点关注一下,新人文档 资源目录 一栏。如果你是初次接触 Seata,这块内容可能会忽略,反正我是直接忽略了。但是这块内容是最重要的部分,所有Seata 配置内容都在这里 。官网只提供了一个 GitHub 地址,里面一堆也没介绍,懵逼。。。

详细说明

2.3 Seata Server 端配置

Ⅰ.解压

  将下载的 seata-server-1.2.0.zip 解压到某个路径下。本文解压路径: D:\Java Software\seata-server-1.2.0
  

Ⅱ. MySQL 数据库配置

  1.执行MySQL数据库操作前,需要我们手动创建一个名称为 seata 的数据库,然后在该数据库下建表。建库命令如下:

CREATE DATABASE seata DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;


   2.进入 资源目录 seata/script/server/db/mysql.sql ,执行SQL语句。建表语句如下,你也可以点击链接获取

-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
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;

Ⅲ. Server端参数项配置

  解压后,进入 conf 目录开始参数的配置。我们修改 file.confregistry.conf 这两个文件。

1.对 file.conf 配置:

2.对 registry.conf 配置:

Ⅳ. 启动Seata Server端

  进入 bin 目录,双击 seata-server.bat 启动。(Linux环境请选择 seata-server.sh 启动)

  到此为止,Seata Server 端启动完成。

2.4 config-center 配置中心配置

  配置中心的配置,本文使用 nacos 作为配置中心。

Ⅰ.获取要配置的参数信息

  进入 资源目录 seata/script/config-center/config.txt ,展示的是 Seata 1.2.0 版本所有配置中心的内容,全部配置点击链接查看。本文使用db方式,故选择db相关配置,需要用到的配置如下:

service.vgroupMapping.my_test_tx_group=default  
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
store.mode=db  /*此处修改为db*/
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver  /*自定义修改*/
store.db.url=jdbc:mysql://192.168.204.201:3306/seata?useUnicode=true /*自定义修改*/
store.db.user=root  /*自定义修改*/
store.db.password=root  /*自定义修改*/
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

Ⅱ.将参数配置到Nacos配置中心

  进入 资源目录 seata/script/config-center/nacos/nacos-config.sh ,该配置会将 seata 相关配置批量添加到 nacos 服务器。

  该脚本可以随便放在某个位置,只要脚本 nacos-config.sh 能够读取到 config.txt 文件即可。本文放在如下为止

  你自己打开 nacos-config.sh 脚本 看看它查找 config.txt 的逻辑就可以了,只要能够读取到 config.txt 文件即可。nacos-config.sh 脚本支持传入 四个参数

  1. -h nacos 所在服务器的IP地址,默认为 localhost
  2. -p nacos 端口号,默认为 8848
  3. -g nacos 配置所属 group 名称,默认为 SEATA_GROUP
  4. -t 将 nacos 配置保存到指定的命名空间,默认为 "",代表 public 命名空间注意:-t 参数值接收的是 命名空间ID,不是 命名空间名称

使用 git 命令框 执行 sh nacos-config.sh ,就可以将配置批量保存到 nacos 服务器。如下图所示:

  到此为止,Config Center 配置中心参数,配置完成。

2.5 client 客户端配置

Ⅰ.业务场景

用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:

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

  用户A购买商品,调用 A服务 创建订单完成,调用 B服务 扣减库存,然后调用 C服务 扣减账户余额。每个服务内部的数据一致性由本地事务来保证多个服务调用来完成业务,全局事务数据一致性则由 Seata 来保证。

Ⅱ.业务数据库准备

配置三个业务分别对应各自的数据库。

  • A服务 对应数据库:seata_order ;表:t_order
  • B服务 对应数据库:seata_storage ;表:t_storage
  • C服务 对应数据库:seata_account ;表:t_account

建库,建表语句如下:

# 创建seata_order数据库
CREATE DATABASE seata_order;

# 创建t_order表
CREATE TABLE seata_order.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 DEFAULT CHARSET=utf8;
# 创建seata_storage数据库
CREATE DATABASE seata_storage;

# 创建t_storage表
CREATE TABLE seata_storage.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=2 DEFAULT CHARSET=utf8;

# 插入一条数据 
INSERT INTO seata_storage.t_storage(`id`,`product_id`,`total`,`used`,`residue`)
VALUES('1','1','100','0','100');
# 创建seata_account数据库
CREATE DATABASE seata_account;

# 创建t_account表
CREATE TABLE seata_account.t_account(
    `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'id',
    `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=2 DEFAULT CHARSET=utf8;

# 插入一条数据 
INSERT INTO seata_account.t_account(`id`,`user_id`,`total`,`used`,`residue`) VALUES('1','1','1000','0','1000');

Ⅲ.创建 undo_log 表

  进入 资源目录 seata/script/client/at/db/mysql.sql ,展示的就是 undo_log 表的建表语句,该表需要在涉及到事务处理的每个库中都添加以下。undo_log 表建表语句如下:

-- for AT mode you must to init this sql for you business database. the seata server not need it.
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';

Ⅳ.库表创建完成图示

Ⅴ.添加 pom 依赖

pom.xml 部分的注意事项,可参考:部署指南-注意事项

<!--seata-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <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.2.0</version>
</dependency>

Ⅵ.application.yml 针对 seata 进行配置

  进入 资源目录 seata/script/client/spring/ ,展示的就是 seata 整合 Spring 的全部配置内容,提供了 .properties.yml 两种格式的配置。详细的配置项还挺多,此处就不粘贴了,你可以点击 资源目录 查看。此处挑选了本案例需要的部分内容进行配置,配置如下所示:(项目application.yml完整配置,请参考文末项目完整代码)

  该配置在每个服务模块都需要配置一份,你也可以通过 nacos 配置中心的方式配置使用。Nacos 的使用请参考:Spring Cloud Alibaba Nacos 用于服务注册和配置中心

seata:
  enabled: true
  application-id: ${ spring.application.name}
  tx-service-group: my_test_tx_group
  enable-auto-data-source-proxy: true
  service:
    vgroup-mapping:
      my_test_tx_group: default  # 此处key需要与tx-service-group的value一致,否则会报 no available service 'null' found, please make sure registry config correct 异常
    grouplist:
      default: 192.168.41.113:8091
    enable-degrade: false
    disable-global-transaction: false
  config:
    type: nacos
    nacos:
      namespace:
      serverAddr: 192.168.41.113:8848
      group: SEATA_GROUP
      userName: ""
      password: ""
  registry:
    type: nacos
    nacos:
      application: seata-server  # 此处名称需和 seata server 服务端 application一致,否则会报 no available service 'null' found, please make sure registry config correct 异常
      server-addr: 192.168.41.113:8848
      namespace:
      userName: ""
      password: ""

Ⅶ.业务代码部分

  业务代码使用 SSM + OpenFeign 的方式进行服务间的调用,来实现一个简单的业务功能。AT模式只用一个 @GlobalTransactional 注解即可实现分布式事务。name 属性为事务唯一性表示,可以随意定义。rollbackFor 属性为指定Exception异常才进行事务回滚。

此处附部分业务代码,完整代码请至文末下载。

/** * 创建订单->调用库存服务扣减库存->调用账户服务扣减账户余额->修改订单状态 */
@Override
@GlobalTransactional(name = "fsp-create-order",rollbackFor = Exception.class)
public void create(Order order) { 
    log.info("----->开始新建订单");
    //新建订单
    orderDao.create(order);

    //扣减库存
    log.info("----->订单微服务开始调用库存,做扣减Count");
    storageService.decrease(order.getProductId(),order.getCount());
    log.info("----->订单微服务开始调用库存,做扣减end");

    //扣减账户
    log.info("----->订单微服务开始调用账户,做扣减Money");
    accountService.decrease(order.getUserId(),order.getMoney());
    log.info("----->订单微服务开始调用账户,做扣减end");

    //修改订单状态,从零到1代表已经完成
    log.info("----->修改订单状态开始");
    orderDao.update(order.getUserId(),0);
    log.info("----->修改订单状态结束");

    log.info("----->下订单结束了");
}

3. 测试阶段

3.1 启动服务

  需要依次启动 Nacos、Seata 服务。Seata 依赖 Nacos,需要读取 Nacos 配置。

3.2 启动项目

  该项目由3个服务组成(项目代码实现,由 seata-order-service2001/2002/2003 三个模块组成),在项目启动过程中,Seata Sever 服务端会有相对应提示,如下图所示:

3.3 分布式事务测试

  发送请求 http://localhost:2001/order/create?userId=1&productId=1&count=10&money=100 来模拟下单请求。发送多次请求,可以看到下单都成功了,Seata Server 端也有事务在进行处理的过程。(此时数据库中,因为事务处理完成,并没有任何数据)

3.4 断点测试,查看数据库信息

  断点打在最后一步,修改订单状态阶段。此时,因为事务未处理完,所以每个业务表 undo_log 表会有事务日志记录,seata 库中的 branch_tableglobal_tablelock_table 三个表,也都会有事务日志相关记录。如下图所示:

db 记录的事务相关日志如下:

  进入断点后,数据库表中记录有事务相关的全部数据;当断点释放后,事务正常提交,此时 db 中 branch_tableglobal_tablelock_tableundo_log 表中的数据全部清空。

事务回滚操作:

  使用 postman 发送 50 个请求,中途关闭B服务导致服务中断,当前事务便会进行回滚。我们再来查看数据库中是否会有这条记录。

   然后将 B 服务恢复,下单业务正常执行,事务正常提交。如下图所示:下单id从 1 开始,第8次下单 B 已经停止服务,随后 B服务启动OK,等一段缓冲时间,B服务从第39次开始正常调用。从8-38 区间内的 下单记录库存扣减记录账户扣减记录 均因事务提交失败而回滚,数据库 t_order 表便会缺失 id 8-38 区间的数据,从 39 次开始正常提供服务(因动图过大无法上传,故删除动图帧数 postman 第23-37 、41-48次请求记录,23-37 期间均为500失败状态,41-48次均为200成功状态,图片可能有点跳跃,望理解),如下图所示:

4.Seata 高可用集群部署

4.1 集群部署

  Seata 集群部署比较简单,只需将已配置好的 seata-server 再启动一个即可。seata 默认使用 8091 端口,此次我在 Windows 部署,所以 seata-server 第二个节点选用 8092 端口,进入 cmd 命令行,使用命令:seata-server.bat -p 8092 启动seata-server 第二台节点。(Linux 正式环境,多机器的话,只需要 scp 到另一台机器,启动即可)

  通过 nacos 服务列表,seata-server 实例数由 1 变为 2。端口分别为 8091、8092 。集群搭建完成,挺简单的。想要几个节点就来几个节点,so easy。

4.2 服务注册成功

  3个服务启动成功后,均会通过 RPC 的方式注册到 Seata 集群的两个节点上来,如下图所示:

4.3 Seata集群测试

  使用 postman 发送 50 个请求,中途关闭 8091 节点。由于集群之间通过 Nacos 通信原因,一个节点的突然宕机,会导致部分请求失败,但是服务很快便会恢复正常。

  当再次将 8091 节点启动后,服务还是能够正常请求,8091 节点也有事务相应的日志显示,说明Seata 集群能够正常提供服务。测试如图所示:

本文代码下载地址:Spring Cloud 整合 Nacos 1.3.1 + Seata 1.2.0 集群部署(Windows版 全网最详细) (提取码:hvim)

下一篇:xxxSpring Cloud 即将截止,下一篇待定

博主写作不易,加个关注呗

求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙

我不能保证所写的内容都正确,但是可以保证不复制、不粘贴。保证每一句话、每一行代码都是亲手敲过的,错误也请指出,望轻喷 Thanks(・ω・)ノ


版权声明:本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。
喜欢 (0)