Spring Cloud Distributed Transaction Seata

Get into the habit of writing together! This is the third day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .

foreword

After reading this article you will learn the following:

  • Seat
  • Seata Server Deployment
  • Seata Transaction Grouping

It will be easier to understand if you know the following:

This article is an applied article and will not elaborate too much theoretical knowledge

Terminology Analysis

The following terms will be used in this deployment:

  • Seata Server: Seata server, officially called transaction coordinator TC (Transaction Coordinator ) , deployed separately
  • Seata Client: Seata client, officially called Resource Manager RM (Resource Manager ), integrated with business systems

Official Glossary: ​​Seata Glossary

Technical selection

Seata has a variety of deployment schemes, the following methods are recommended for the production environment: registration center + configuration center + database

The corresponding technology stack is as follows:

  • Registration Center: Nacos
  • Configuration Center: Nacos
  • Database: MySQL 8.0

Deploy Seata Server

Initialize the database

Create database seata-server and corresponding access user seata

Use the official database script for initialization: seata/script/server/db at develop

Supports Oracle and PostgreSQL in addition to MySQL

custom configuration file

Refer to the official deployment documentation: Quickly deploy Seata Server with Docker compose

编写服务端配置文件registry.conf:

registry {
  type = "nacos"
  
  nacos {
    # 服务名称
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    # 命名空间ID
    namespace = "spring-cloud-development"
    group = "SEATA_GROUP"
    # 集群名称
    cluster = "default"
  }
}
​
config {
  type = "nacos"
  
  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = "spring-cloud-development"
    group = "SEATA_GROUP"
    # 配置文件dataId
    dataId: "seata-server.properties"
  }
}
复制代码

在nacos中增加配置seata-server.properties, 调整为数据库模式:

store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata-server?useUnicode=true&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
store.db.user=seata
store.db.password=seata
复制代码

注意: 配置的dataId和group应与registry.conf中的一致

使用docker-compose启动

对docker-compose不再赘述, 可阅读前言中的官方文档

编写docker-compose.yaml:

# 根据自己的docker版本选择对应的version
version: "3.1"
services:
  seata-server:
    image: seataio/seata-server:1.4.2
    hostname: seata-server
    ports:
      - "8091:8091"
    environment:
      - SEATA_PORT=8091
      - SEATA_IP=127.0.0.1
      # 此处有坑
      - SEATA_CONFIG_NAME=file:/root/seata-config/registry
    volumes:
      # 此处有坑
      - "./seata-server/config:/root/seata-config"
复制代码

这里有两个因为笔者不熟悉docker产生的坑:

环境变量SEATA_CONFIG_NAME, 指的是容器内部的环境

所以路径file:/root/seata-config/registry是指, 服务端读取的配置文件registry.conf为容器内部的/root/seata-config/registry.conf

并非我们本机的/root/seata-config/registry

所以我们要将自己写的配置文件映射到其内部中, 即后面一个坑: "./seata-server/config:/root/seata-config"

它的含义是将本机路径./seata-server/config映射到容器内部路径/root/seata-config

综上, 我们需要完成的操作是:

  1. docker-compose.yaml目录下创建seata-server/config目录
  2. registry.conf文件放置到${docker-compose.yaml目录}/seata-server/config
  3. 运行命令docker-compose up -d

如果您遇到了io.seata.common.exception.NotSupportYetException: config type can not be null, 请仔细阅读上述内容

业务系统集成Seata Client

初始化数据库

在业务系统中增加undo_log表:

-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
复制代码

自定义配置文件

在nacos中增加客户端公共配置文件seata-client.properties:

seata.registry.type=nacos
seata.registry.nacos.server-addr=127.0.0.1:8848
seata.registry.nacos.namespace=spring-cloud-development
seata.registry.nacos.group=SEATA_GROUP
seata.registry.nacos.application=seata-server

seata.config.type=nacos
seata.config.nacos.server-addr=127.0.0.1:8848
seata.config.nacos.namespace=spring-cloud-development
seata.config.nacos.group=SEATA_GROUP
复制代码

注意: 客户端配置的group应与服务端配置相同

引入启动类依赖

按照Seata部署指南推荐的方式在pom.xml中引入依赖spring-cloud-starter-alibaba-seata:

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>最新版</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <version>2.2.1.RELEASE</version>
    <exclusions>
        <exclusion>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
        </exclusion>
    </exclusions>
</dependency>
复制代码

之后再引入上一节中的客户端配置即可:

spring:
  cloud:
    nacos:
      config:
        shared-configs:
          - data-id: seata-client.properties
            group: SEATA_GROUP
复制代码

事务分组

想要学会一个概念, 最重要的是了解为什么要使用它

Looking back at the initial concept, Seata Server is the transaction coordinator TC ( Transaction Coordinator )

That is to say, it plays a crucial role in distributed transactions

But how did it hang? Or did the network fluctuate?

Therefore, transaction grouping can actually be understood as Seata Server cluster grouping, which is for the high availability of TC

Seata Server Configuration

The server needs to clarify its own group name and modify the registry.conffile:

registry {
  
  nacos {
    # Seata Server所属集群名称为dev
    cluster = "dev"
  }
}
复制代码

According to the official document Seata transaction grouping , there is a pit here

You need to add a configuration of the transaction group name corresponding to the cluster name in nacos

Take the above cluster as an example, you need to add service.vgroup-mapping.${分组名}configuration, the content is the cluster name:dev

The reason lies RegistryServicein the following code:

public interface RegistryService<T> {
​
    String PREFIX_SERVICE_MAPPING = "vgroupMapping.";
​
    String PREFIX_SERVICE_ROOT = "service";
​
    String CONFIG_SPLIT_CHAR = ".";
​
    default String getServiceGroup(String key) {
        // 假设分组名为group-dev
        // 会在nacos中寻找dataId为service.vgroupMapping.group-dev的配置
        key = PREFIX_SERVICE_ROOT + CONFIG_SPLIT_CHAR + PREFIX_SERVICE_MAPPING + key;
        if (!SERVICE_GROUP_NAME.contains(key)) {
            ConfigurationCache.addConfigListener(key);
            SERVICE_GROUP_NAME.add(key);
        }
        return ConfigurationFactory.getInstance().getConfig(key);
    }
}
复制代码

If the client encounterscan not get cluster name in registry config 'service.vgroupMapping.xx', please make sure registry config correct

Please read the above carefully

Seata Client Configuration

Add the following to the project configuration:

seata:
  tx-service-group: group-dev
复制代码

The final effect is: the transaction group will use the TC with the group-devcluster namedev

Application scenarios

The official provides a good example, please refer to: Transaction Grouping and High Availability (seata.io)

Summarize

It's shallow on paper

Between understanding Seata and actually deploying Seata, there is a technical gap such as docker/nacos

Finally, summarize the overall process of using Seata:

  1. Deploy Seata Server
  2. group transactions
  3. Business system integration Seata Client

I'm Houtaroy, and it's a lifetime honor to have a single line of code that helps others

Guess you like

Origin juejin.im/post/7084113449579610119
Recommended