Distributed TC transaction AT mode

Distributed transactions have the following solutions:

  • XA
  • TCC
  • Seata framework
  • AT transaction
  • SAGA
  • Reliable message final consistency
  • Best effort notification

Seata

Seata is an open source one-stop distributed transaction solution, which is committed to providing high-performance and easy-to-use distributed transaction services. Seata will provide users with AT, TCC, SAGA and XA transaction modes to create a one-stop distributed solution for users.

Seata AT

Seata's AT mode (Automatic Transaction) is a non intrusive distributed transaction solution

Link 1: Specific working mechanism of Seata AT

TC (Transaction Coordinator)
Because each service cannot perceive whether the transaction is successful or not, a special service is needed to coordinate the running state of each service.

TM (Transaction Manager) applies to TC to start a global transaction

RM (Resource Manager), RM is responsible for managing branch transactions (i.e. local transactions of microservices)

Link 2: Add AT distributed transaction to Spring Cloud microservice

Seata Server is TC, which can be downloaded and started directly from the official warehouse. Download address: https://github.com/seata/seata/releases

Reduce the pressure on TC. There is no cluster. You can only create several more transaction groups to manage several modules

Seata Server configuration

If the computer memory is insufficient, set the memory in seata-server.bat to 256M

%JAVACMD% %JAVA_OPTS% -server -Xmx2048m -Xms2048m -Xmn1024m -Xss512k -XX:Sur......

There are two profiles for Seata Server:

  • seata/conf/registry.conf
  • seata/conf/file.conf

registry.conf

registrv.conf -- register with the registry

registry {
  # file ,nacos ,eureka,redis,zk,consul,etcd3,sofa
  # Select eureka registration configuration here
  type = "eureka"

  nacos {
	......
  }

  # Registration configuration of eureka
  eureka {
    # Address of Registration Center
    serviceUrl = "http://localhost:8761/eureka"
    # Register the name and service ID with the registry. The default is default
    application = "seata-server"
    weight = "1"
  }
  
  redis {
	......
  }
  ......

registry {
  # file ,nacos ,eureka,redis,zk,consul,etcd3,sofa
  type = "eureka"

  nacos {
    serverAddr = "localhost"
    namespace = ""
    cluster = "default"
  }
  eureka {
    serviceUrl = "http://localhost:8761/eureka"
    # application = "default"
    # weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = "0"
    password = ""
    cluster = "default"
    timeout = "0"
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
    username = ""
    password = ""
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
  }
  etcd3 {
    cluster = "default"
    serverAddr = "http://localhost:2379"
  }
  sofa {
    serverAddr = "127.0.0.1:9603"
    application = "default"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    cluster = "default"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  }
  file {
    name = "file.conf"
  }
}

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

  nacos {
    serverAddr = "localhost"
    namespace = ""
    group = "SEATA_GROUP"
  }
  consul {
    serverAddr = "127.0.0.1:8500"
  }
  apollo {
    app.id = "seata-server"
    apollo.meta = "http://192.168.1.204:8801"
    namespace = "application"
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
    username = ""
    password = ""
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.conf"
  }
}

file.conf

file.conf – the transaction coordinator used by the transaction group
Configure the eureka registry, the connection address of eureka service and the registered service name in the registry.conf file
Specify file.conf -- log in the library during the operation of Seata server

config {
  # file,nacos ,apollo,zk,consul,etcd3
  # Here, select use local file to save the configuration
  type = "file"


......

  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  
  file {
    # Use the local file to set the file name of the configuration file here
    name = "file.conf"
  }
}

store {
  ## store mode: file,db,redis
  # Select database storage here
  mode = "db"

  ## file store property
  file {
  	......
  }

  # Database storage
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"

	# Database connection configuration
    url = "jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8"
    user = "root"
    password = "root"
    minConn = 5
    maxConn = 30

	# Transaction log table name setting
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"

    queryLimit = 100
    maxWait = 5000
  }

  ## redis store property
  redis {
  	......
  }
}

transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  # the client batch send request enable
  enableClientBatchSendRequest = true
  #thread factory for netty
  threadFactory {
    bossThreadPrefix = "NettyBoss"
    workerThreadPrefix = "NettyServerNIOWorker"
    serverExecutorThread-prefix = "NettyServerBizHandler"
    shareBossWorker = false
    clientSelectorThreadPrefix = "NettyClientSelector"
    clientSelectorThreadSize = 1
    clientWorkerThreadPrefix = "NettyClientWorkerThread"
    # netty boss thread size,will not be used for UDT
    bossThreadSize = 1
    #auto default pin or 8
    workerThreadSize = "default"
  }
  shutdown {
    # when destroy server, wait seconds
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}
service {
  #transaction service group mapping
  # order_ tx_ Group is consistent with the configuration of "TX service group: order_tx_group" in yml
  # "Seata server" is consistent with the registered name of TC server
  # Get the address of Seata server from eureka, register yourself with Seata server, and set group
  vgroupMapping.order_tx_group = "seata-server"
  #only support when registry.type=file, please don't set multiple addresses
  order_tx_group.grouplist = "127.0.0.1:8091"
  #degrade, current not support
  enableDegrade = false
  #disable seata
  disableGlobalTransaction = false
}

client {
  rm {
    asyncCommitBufferLimit = 10000
    lock {
      retryInterval = 10
      retryTimes = 30
      retryPolicyBranchRollbackOnConflict = true
    }
    reportRetryCount = 5
    tableMetaCheckEnable = false
    reportSuccessEnable = false
  }
  tm {
    commitRetryCount = 5
    rollbackRetryCount = 5
  }
  undo {
    dataValidation = true
    logSerialization = "jackson"
    logTable = "undo_log"
  }
  log {
    exceptionRate = 100
  }
}

Start: double click the seata/bin/seata-server.bat file
Or CMD: seata-server.bat in the current directory
Error reporting: path, home environment
bat is not supported in the new version of jdk

Add AT transaction in business module configuration

file.conf

Which coordinator to use

service{
		VgroupMapping.Transaction group name="Registry coordinator name"
		}
perhaps
service{
		VgroupMapping.group="Transaction group name"
		VgroupMapping.tv="Registry coordinator name"
		}

application.yml

application.yml – transaction group naming
Just write one transaction group for multiple modules

spring:
  ......
  
  cloud:
    alibaba:
      seata: 
        tx-service-group: order_tx_group
     
   datasource:
	url: jdbc:mysql:/l/seata_order?useUnicode=true&driver-class-name: com.mysql.cj.jdbc.Driveruser
	name: root
	password: root
	jdbcUrl: ${spring. datasource.url}

......

On the business method, add annotations
@GlobalTransactional -- used to start global transactions, added only in the first module (method).
@Transactional -- control local transactions

Dependency:

   <seata.version>1.3.0</seata.version>
        <spring-cloud-alibaba-seata.version>2.0.0.RELEASE</spring-cloud-alibaba-seata.version>

        <dependency>
          <groupId>com.alibaba.cloud</groupId>
          <artifactId>spring-cloud-alibaba-seata</artifactId>
          <version>${spring-cloud-alibaba-seata.version}</version>
          <exclusions>
            <exclusion>
              <artifactId>seata-all</artifactId>
              <groupId>io.seata</groupId>
            </exclusion>
          </exclusions>
        </dependency>
        <dependency>
          <groupId>io.seata</groupId>
          <artifactId>seata-all</artifactId>
          <version>${seata.version}</version>
        </dependency>

Error: either not configured or not configured correctly

Write your own data source configuration
By creating the data source proxy object dataSourceProxy

Configuration class

import com.alibaba.druid.pool.DruidDataSource;
import com.zaxxer.hikari.HikariDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
/*
The custom data source auto configuration class conflicts with the default data source auto configuration class in spring,
You need to exclude the default automatic configuration of spring in the startup class
 */
@Configuration
public class DSAutoConfiguration {
    // Create original data source object
     
    /*hikari The database address parameter used is not url, but JDBC url
    spring
    	datasource:
			url: jdbc:mysql:/l/seata_order?useUnicode=true&driver-class-name: com.mysql.cj.jdbc.Driverusername: root
			password: root
			jdbcUrl: ${spring. datasource.url}
*/
   // @ConfigurationProperties injects the configured parameters (spring.datasource in yml) into the HikariDataSource object
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource();
        // return new DruidDataSource();
    }

    // Create a data source proxy object because two objects of the same type are created here. spring does not know who to choose. First, add an object annotation
    @Primary   // Preferred object
    @Bean
    public DataSource dataSourceProxy(DataSource ds) { //DataSource is the target object of the proxy
        return new DataSourceProxy(ds);
    }

In startup class:
Because it is written directly, spring's own default configuration class is excluded

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

yml

Phase II submission

If you fail
Delete log, rollback

Tags: Java Database

Posted on Mon, 04 Oct 2021 17:52:18 -0400 by jpotte00