The journey of distributed transactions starting from the installation of Seata springboot integrated seata

insert image description here

introduce

What is Seata?

In modern application development, distributed systems are used more and more widely. However, as the complexity of the system increases, it becomes increasingly difficult to handle distributed transactions. This is the background in which Seata emerged. Seata (Simple Extensible Autonomous Transaction Architecture) is an open source distributed transaction solution designed to solve transaction consistency and coordination problems in distributed systems.
In traditional monolithic applications, relational databases are usually used to manage transactions and ensure data consistency. But in a distributed system, transaction management becomes complicated because multiple independent services are involved. The requirement of a distributed transaction is that all involved services are either successfully committed or rolled back to maintain data consistency.

Seata provides two main transaction modes:

  1. AT Mode (Auto Compensation Mode): In AT mode, Seata will automatically compensate transactions without manually writing compensation logic. Seata will arrange all the operations of the transaction into a global transaction, then execute the try operation of each branch, and perform the corresponding compensation operation when an exception occurs.

  2. TCC mode (two-phase commit mode): TCC mode requires developers to manually write the logic of the three phases of Try, Confirm and Cancel. In the TCC mode, Seata is responsible for coordinating the commit and rollback of global transactions, while the try, confirm and cancel operations of each branch are implemented by developers.

Seata also provides scalable registry and storage support, making it suitable for various scenarios.

In general, Seata is a powerful distributed transaction solution that can help developers solve distributed transaction problems and ensure data consistency and reliability in distributed systems. By integrating Seata, developers can more easily build complex distributed applications and improve system stability and performance.

Install Seata Server

Download the Seata Server release

You can download the latest Seata Server release from the Seata official website , and unzip it to a specified directory; there are source and binary versions, here we choose to install the binary file to download. My version is 1.7.0 (2023-07-11, recommended version)
insert image description here

Configure Seata

unzip files

insert image description here
The downloaded file is a zip file, and after decompression, it will be the folder above. The default folder name is seata.

Configure Seata's yml file

Enter seata/confthe directory, there are two configuration files here; we need to application.ymlmodify a name at will; and then application.example.ymlmodify it application.ymlas the main configuration file.
insert image description here
Modify application.ymlthe file, I use nacos here as the registration center, so the places that need to be modified are:

  1. seata:config:type
  2. seata:registry:type
  3. store:mode
  4. store:session:mode
  5. store: lock:mode
  6. store:db The configuration of the database is modified to its own

Configuration file:

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${
    
    user.home}/logs/seata
  extend:
    logstash-appender:
      destination: 127.0.0.1:4560
    kafka-appender:
      bootstrap-servers: 127.0.0.1:9092
      topic: logback_to_logstash
# 这里是主要的配置文件
seata:
  config:
    # support: nacos 、 consul 、 apollo 、 zk  、 etcd3
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      # 如果在nacos上添加了命名空间,则配置命令空间ID
      namespace:
      # 配置分组
      group: SEATA_GROUP
      username:
      password:
      context-path:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key:
      #secret-key:
      data-id: seataServer.properties
  registry:
    # support: nacos 、 eureka 、 redis 、 zk  、 consul 、 etcd3 、 sofa
    type: nacos
    preferred-networks: 30.240.*
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
      namespace:
      cluster: default
      username:
      password:
      context-path:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key:
      #secret-key:
  server:
    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
    max-commit-retry-timeout: -1
    max-rollback-retry-timeout: -1
    rollback-retry-timeout-unlock-enable: false
    enable-check-auth: true
    enable-parallel-request-handle: true
    retry-dead-threshold: 130000
    xaer-nota-retry-timeout: 60000
    enableParallelRequestHandle: true
    recovery:
      committing-retry-period: 1000
      async-committing-retry-period: 1000
      rollbacking-retry-period: 1000
      timeout-retry-period: 1000
    undo:
      log-save-days: 7
      log-delete-period: 86400000
    session:
      branch-async-queue-size: 5000 #branch async remove queue size
      enable-branch-async-remove: false #enable to asynchronous remove branchSession
  store:
    # support: file 、 db 、 redis
    mode: db
    session:
      mode: db
    lock:
      mode: db
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
      user: mysql
      password: mysql
      min-conn: 10
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 1000
      max-wait: 5000
  metrics:
    enabled: false
    registry-type: compact
    exporter-list: prometheus
    exporter-prometheus-port: 9898
  transport:
    rpc-tc-request-timeout: 15000
    enable-tc-server-batch-send-response: false
    shutdown:
      wait: 3
    thread-factory:
      boss-thread-prefix: NettyBoss
      worker-thread-prefix: NettyServerNIOWorker
      boss-thread-size: 1

Load the configuration file config.txt to nacos

Modify the config.txt file

config.txtThe file is in seata/script/config-centerthe directory; the places we need to modify are:

  1. store.mode=db
  2. store.lock.mode=db
  3. store.session.mode=db
  4. The configuration of the store.db database is modified to its own, which is the same as that in the above yml file

Load it on nacos

Enter seata/script/config-center/nacosthe directory to execute nacos-config.shthe file.

sh nacos-config.sh -h 121.37.228.169 -p 8848 -g SEATA_GROUP -t 0af6e97b-a684-4647-b696-7c6d42aecce7 -u nacos -w nacos
  • -h: Nacos IP address
  • -p: Nacos port number
  • -g: Group group name
  • -t: Namespace ID, if not public by default
  • -u: username
  • -w: password
    After the execution is completed, log in to our Nacos configuration management to view the loaded data:
    insert image description here

Start the Seata service

Normal start

Enter seata/binthe directory and execute the command:

sh seata-server.sh 

insert image description here

Here I may encounter an abnormal situation when I start it. Below I have listed some pitfalls I encountered when starting it. can move to启动时遇到的坑

View startup log

My Mac system is open to open log files. Other systems need to execute commands according to the system, or directly enter the seata/logsdirectory to view start.outfiles.

open /Users/ddz/Downloads/seata/logs/start.out

insert image description here
You can see the log output address indicating that the startup is successful.

Open the console page

On the console page , the default account password is seata/seata.
insert image description here

Pit encountered at startup

Here are some pitfalls I encountered in deploying Seata, and there may be differences between them for reference only.

Unable to resolve value for ${console.user.username}

Exception information : Could not resolve placeholder 'console.user.username' in value “${console.user.username}”
insert image description here
Solution : You need to copy all the configuration information in the yml file that was previously modified to another name consoleto the current application.ymlone . Here is to set the account password for our login console page.

Unable to parse the value of ${seata.security.secretKey}

Exception information : Could not resolve placeholder 'seata.security.secretKey' in value "${seata.security.secretKey}"
insert image description here
Solution : You need to copy all the configuration information in the yml file that was previously modified to another name seata.securityto the current application.ymlone .

database connection problem

Exception information : com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
In versions before MySQL5.7, the security is low, and any user can connect to the database, so the official version 5.7 has increased privacy protection of. And the default useSSL = true value is adopted to prevent random modification of the database. In version 8.0, SSL is still retained, and the default value is true.
insert image description here

Solution : Append after the database configuration url &useSSL=false; you need to check the yml configuration file and the configuration list on Nacos store.db.url.
insert image description here

Integrate Seata in Spring Boot project

Above we introduced how to install the seata server locally, and then introduce the integration of seata in our Spring Boot project; here I only use a demo to introduce it, which can be implemented according to your own business logic.

working environment

  • MySQL 5.7.28
  • Maven 3.5.4
  • JDK 1.8
  • Mybot 3.4.1
  • dynamic 3.4.1

cloud, boot, alibaba environment

   <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
   <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
   <spring-cloud-alibaba.version>2.2.6.RELEASE</spring-cloud-alibaba.version>

add dependencies

	<!--    MySQL    -->
	<dependency>
	    <groupId>mysql</groupId>
	    <artifactId>mysql-connector-java</artifactId>
	</dependency>
	<!--    Mybatis    -->
	<dependency>
	    <groupId>com.baomidou</groupId>
	    <artifactId>mybatis-plus-boot-starter</artifactId>
	    <version>3.4.1</version>
	</dependency>
	<!--    多数据源    -->
	<dependency>
	    <groupId>com.baomidou</groupId>
	    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
	    <version>3.4.1</version>
	</dependency>
	<!--    Seata分布式事务    -->
	<dependency>
	    <groupId>com.alibaba.cloud</groupId>
	    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
	</dependency>

configuration yml

server:
  port: 7001
spring:
  application:
    name: ddz-user
  cloud:
    nacos:
      discovery:
        # 服务分组
        group: ddz
        server-addr: 121.37.228.111:8848
        # 必须填命名空间的ID
#        namespace: 9ebef975-dcc0-4430-9c63-1c62d8a86d82
  datasource:
    dynamic:
      # 开启seata分布式事务
      seata: true
      strict: false
      primary: master
      datasource:
        master:
          url: jdbc:mysql://121.37.228.111:3306/ddz?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
          username: ddz
          password: ddz2023
        local:
          url: jdbc:mysql://127.0.0.1:3306/ddz?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
          username: root
          password: ddz2023

# MyBatis Plus配置
mybatis-plus:
  # 搜索指定包别名
  typeAliasesPackage: com.ddz.**.entity
  # 配置mapper的扫描,找到所有的mapper.xml映射文件
  mapperLocations: classpath*:mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
  configuration:
    # 开启驼峰,开启后,只要数据库字段和对象属性名字母相同,无论中间加多少下划线都可以识别
    map-underscore-to-camel-case: true

# Seata 配置
seata:
  application-id: seata-server
  # 是否启用数据源bean的自动代理
  enable-auto-data-source-proxy: false
  tx-service-group: default_tx_group  # 必须和服务器配置一样
  registry:
    type: nacos
    nacos:
      # Nacos 服务地址
      server-addr: 121.37.228.111:8848
      group: SEATA_GROUP
#      namespace: 9ebef975-dcc0-4430-9c63-1c62d8a86d82
      application: seata-server # 必须和服务器配置一样
      #      username:
      #      password:
      cluster: default
  config:
    type: nacos
    nacos:
      server-addr: 121.37.228.111:8848
      group: SEATA_GROUP
#      namespace: 9ebef975-dcc0-4430-9c63-1c62d8a86d82
  service:
    vgroup-mapping:
      default_tx_group: default # 必须和服务器配置一样
    disable-global-transaction: false
  client:
    rm:
      # 是否上报成功状态
      report-success-enable: true
      # 重试次数
      report-retry-count: 5

Integrate Seata in business code

We create two mapperclasses based on two data sources and then controllertest them; I omit the business layer for the convenience of testing here.

Use @GlobalTransactionalannotations to manage global transactions

insert image description here

Demonstrates AT (automatic compensation) mode and TCC (two-phase commit) mode

Use AT (auto compensation) mode

In AT mode, Seata will automatically compensate transactions without manually writing compensation logic. First, let's demonstrate a simple transfer scenario, transferring funds from one account to another and ensuring transaction consistency.

  1. Add the @GlobalTransactional annotation
    Add the @GlobalTransactional annotation to the method of the transfer service to mark the global transaction:
@Service
public class TransferService {
    
    
    
    @GlobalTransactional
    public void transfer(String fromAccount, String toAccount, double amount) {
    
    
        // 扣除转出账户金额
        deductAmount(fromAccount, amount);

        // 增加转入账户金额
        addAmount(toAccount, amount);
    }

    // 实现扣除金额逻辑
    // ...

    // 实现增加金额逻辑
    // ...
}
  1. Test AT mode
    Write test cases to verify transaction management in AT mode:
@RunWith(SpringRunner.class)
@SpringBootTest
public class TransferServiceTest {
    
    

    @Autowired
    private TransferService transferService;

    @Test
    public void testTransfer() {
    
    
        // 假设从账户 A 转账 100 到账户 B
        transferService.transfer("accountA", "accountB", 100.0);
    }
}

Run the test case to observe whether the transfer is successful, and check the log to confirm whether Seata automatically compensated the transaction.

Use TCC (two-phase commit) mode

In the TCC mode, we need to manually write the logic of the three phases of Try, Confirm and Cancel to ensure the correct execution of the transaction. Let's demonstrate a simple order creation scenario, including three stages: placing an order, deducting inventory, and creating an order.

  1. Implement the TCC interface
    Create a TCC interface and implement the logic of the three stages of Try, Confirm and Cancel:
public interface OrderTccService {
    
    

    @GlobalTransactional
    boolean createOrder(OrderDTO orderDTO);

    @TwoPhaseBusinessAction(name = "orderTccService", commitMethod = "confirmOrder", rollbackMethod = "cancelOrder")
    boolean tryCreateOrder(OrderDTO orderDTO);

    boolean confirmOrder(OrderDTO orderDTO);

    boolean cancelOrder(OrderDTO orderDTO);
}
  1. Implement TCC logic
    Write TCC logic in the implementation class:
@Service
public class OrderTccServiceImpl implements OrderTccService {
    
    

    @Override
    public boolean tryCreateOrder(OrderDTO orderDTO) {
    
    
        // 预留库存逻辑
        // ...
        return true;
    }

    @Override
    public boolean confirmOrder(OrderDTO orderDTO) {
    
    
        // 确认创建订单逻辑
        // ...
        return true;
    }

    @Override
    public boolean cancelOrder(OrderDTO orderDTO) {
    
    
        // 取消创建订单逻辑
        // ...
        return true;
    }
}
  1. Test the TCC mode
    Write test cases to verify the transaction management of the TCC mode:
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderTccServiceTest {
    
    

    @Autowired
    private OrderTccService orderTccService;

    @Test
    public void testCreateOrder() {
    
    
        // 创建一个订单
        OrderDTO orderDTO = new OrderDTO();
        // 设置订单信息
        // ...

        orderTccService.createOrder(orderDTO);
    }
}

Run the test case to observe whether the order is successfully created, and check the log to confirm whether the Try, Confirm and Cancel phases of the TCC mode are executed correctly.

Integrate the pit that Seata stepped on

Here are some pitfalls I encountered during the integration process, and there may be differences between them for reference only.

Table ‘ddz.undo_log’ doesn’t exist

Exception information : process connectionProxy commit error: Table 'ddz.undo_log' doesn't exist.
Solution : Cut off the log table needed by Seata in the data source; add a new undo_logtable in each data source.

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;

no available service ‘null’ found, please make sure registry config correct

Exception information : The reason for this is that we did not load Seata config.txton nacos.
Solution : Execute the command to load the configuration to the Nacos configuration center. Refer to above:把配置文件config.txt加载到nacos上

Distributed transaction does not take effect

Reason : The multiple data sources we use dynamicdo not enable Seatadistributed transactions by default.
Solutiondynamic : Add configuration under the yml configuration file seata: trueto enable distributed transactions.

dynamic-datasource can not find primary datasource

Reason : This is an error in the data source configuration information. The reason for this exception is that I am too careless to write the database connection (url) connection incorrectly.
Solution : Double check datasourcethe configuration of the following data sources.

Communications link failure

Reason : Most of the reasons here are that MySQL needs to specify whether to make an SSL connection, and the SSL connection is enabled by default.
Solution : Just add it after the database connection configuration URL &useSSL=false.

Summarize

As distributed systems continue to evolve, so will the field of distributed transactions. In the future, we can further explore more distributed transaction models and solutions to meet the needs of different business scenarios. At the same time, Seata, as an active open source project, will continue to introduce new features and improvements. We can pay attention to the updates of the Seata community and contribute our own strength.

In addition, in addition to Seata, there are other distributed transaction solutions, such as TCC-Transaction, SAGA, , HSTCetc. These solutions are also worthy of our in-depth study and exploration. According to different business scenarios, we can choose the most suitable solution to solve the distributed transaction problem.

References

Nacos Official Documentation
Seata Official Documentation
Spring Boot Official Documentation

Guess you like

Origin blog.csdn.net/weixin_45626288/article/details/132155575