Seta introduction to distributed transaction DEMO

Posted by Begby on Wed, 15 Jan 2020 13:57:55 +0100

>Simple Extensible Autonomous Transacation Architecture, seata is a simple, scalable and highly autonomous distributed architecture

SEATA Server Configure

>Because we use the official version 1.0.0-GA, most of the instructions found on the Internet are version 0.X, with many changes. For example, the script of db_store.sql is cancelled in the server. If we can't find the relevant content, we can find it through the source code, such as the source code of DB script: mysql db script

  1. download seata-server

  2. Create a database (seata), which can be customized and used in file.conf.

    -- -------------------------------- 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,
        `gmt_modified`      DATETIME,
        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. Edit the file.conf configuration file

    service {
      #transaction service group mapping
      vgroup_mapping.sunrise_tx_group = "default"
      #only support when registry.type=file, please don't set multiple addresses
      default.grouplist = "127.0.0.1:8091"
      #disable seata
      disableGlobalTransaction = false
      #degrade current not support
      enableDegrade = false
      #disable
      disable = false
      #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
      max.commit.retry.timeout = "-1"
      max.rollback.retry.timeout = "-1"
    }
    
    ## transaction log store, only used in seata-server
    store {
      ## store mode: file,db
      mode = "db"
    
      ## file store property
      file {
        ## store location dir
        dir = "sessionStore"
      #degrade current not support
      enableDegrade = false
      #disable
      disable = false
      #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
      max.commit.retry.timeout = "-1"
      max.rollback.retry.timeout = "-1"
    }
    
    ## transaction log store, only used in seata-server
    store {
      ## store mode: file,db
      mode = "db"
    
      ## file store property
      file {
        ## store location dir
        dir = "sessionStore"
      }
    
      ## database store property
      db {
        ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
        datasource = "dbcp"
        ## mysql/oracle/h2/oceanbase etc.
        db-type = "mysql"
        driver-class-name = "com.mysql.jdbc.Driver"
        url = "jdbc:mysql://localhost:3306/seata"
        user = "wr"
        password = "wr"
        min-conn = 1
        max-conn = 3
        global.table = "global_table"
        branch.table = "branch_table"
        lock-table = "lock_table"
        query-limit = 100
      }
    }
    
  4. Edit conf/regiester.conf

    registry {
      # file ,nacos ,eureka,redis,zk,consul,etcd3,sofa
      # Change 1
      type = "eureka"
    
      nacos {
        serverAddr = "localhost"
        namespace = ""
        cluster = "default"
      }
      eureka {
      	# Change 2
        serviceUrl = "http://localhost:21001/eureka"
        application = "default"
        weight = "1"
      }
      redis {
        serverAddr = "localhost:6379"
        db = "0"
      }
      zk {
        cluster = "default"
        serverAddr = "127.0.0.1:2181"
        session.timeout = 6000
        connect.timeout = 2000
      }
      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
      type = "file"
    
      nacos {
        serverAddr = "localhost"
        namespace = ""
      }
      consul {
        serverAddr = "127.0.0.1:8500"
      }
      apollo {
        app.id = "seata-server"
        apollo.meta = "http://192.168.1.204:8801"
      }
      zk {
        serverAddr = "127.0.0.1:2181"
        session.timeout = 6000
        connect.timeout = 2000
      }
      etcd3 {
        serverAddr = "http://localhost:2379"
      }
      file {
        name = "file.conf"
      }
    }
    

    In this implementation, we haven't added the configuration yet, so we only need to change the relevant attributes in the register block. After we implement nacos config in the future, we will update here synchronously.

  5. Start server

    [root@localhost.localdomain /usr/local/geekplus/server/seata]# bin/seata-server.sh 
    

After seeing the following 8091 port services in eureka, it is normal to start Seata server!

Client Configure

AT Model

The data table undo log needs to be added to each business database

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;

Broadway-Demo

>There is a small rule in using the spring boot project, which I call the use trilogy.
According to the example of Broadway WS tally service project:

  • Step 1: add dependency

            <!--seata-->
            <dependency>
                <groupid>com.alibaba.cloud</groupid>
                <artifactid>spring-cloud-alibaba-seata</artifactid>
                <version>2.1.0.RELEASE</version>
                <exclusions>
                    <exclusion>
                        <artifactid>seata-all</artifactid>
                        <groupid>io.seata</groupid>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupid>io.seata</groupid>
                <artifactid>seata-all</artifactid>
                <version>1.0.0</version>
            </dependency>
    
  • Step 2: open annotation

    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
    

    It needs to be explained here that we need to exclude the DataSourceAutoConfigurationBean that is automatically injected by spring boot by default. Because SEATA is a distributed transaction based on data source interception, we need to customize the data source configuration information:

    package com.geekplus.broadway.ws.tally.application;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import io.seata.rm.datasource.DataSourceProxy;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
    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 org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import javax.sql.DataSource;
    
    @Configuration
    public class DataSourceConfiguration {
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource druidDataSource(){
            DruidDataSource druidDataSource = new DruidDataSource();
            return druidDataSource;
        }
    
        @Primary
        @Bean("dataSource")
        public DataSourceProxy dataSource(DataSource druidDataSource){
            return new DataSourceProxy(druidDataSource);
        }
    
        @Bean
        public SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy)throws Exception{
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource(dataSourceProxy);
            sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                    .getResources("classpath*:/com/geekplus/*.xml"));
            sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
            return sqlSessionFactoryBean.getObject();
        }
    }
    

    This configuration class is usually placed in the same directory as the startup class!

  • Part three: configuration change

    spring:
      cloud:
        alibaba:
          seata:
            tx-service-group: sunrise_tx_group 
    

    > TIPS: >TX service group must be consistent with server and client, otherwise it will kill you! >TX service group must be consistent with server and client, otherwise it will kill you! >TX service group must be consistent with server and client, otherwise it will kill you!

The above three steps are the general practice of most spring boot projects. Of course, our SEATA is not so perfect for the time being. At present, the configuration information does not support complete configuration in application.yml. Therefore, we need two core client configuration files, file.conf and register.conf

  • file.conf this file is mainly used to connect RM. We only need to pay attention to the above mentioned TX service group. Other configurations are available by default.

    transport {
      # tcp udt unix-domain-socket
      type = "TCP"
      #NIO NATIVE
      server = "NIO"
      #enable heartbeat
      heartbeat = true
      # the client batch send request enable
      enable-client-batch-send-request = true
      #thread factory for netty
      thread-factory {
        boss-thread-prefix = "NettyBoss"
        worker-thread-prefix = "NettyServerNIOWorker"
        server-executor-thread-prefix = "NettyServerBizHandler"
        share-boss-worker = false
        client-selector-thread-prefix = "NettyClientSelector"
        client-selector-thread-size = 1
        client-worker-thread-prefix = "NettyClientWorkerThread"
        # netty boss thread size,will not be used for UDT
        boss-thread-size = 1
        #auto default pin or 8
        worker-thread-size = 8
      }
      shutdown {
        # when destroy server, wait seconds
        wait = 3
      }
      serialization = "seata"
      compressor = "none"
    }
    
    service {
      #transaction service group mapping
      vgroup_mapping.sunrise_tx_group = "default"
      #only support when registry.type=file, please don't set multiple addresses
      default.grouplist = "127.0.0.1:8091"
      #disable seata
      disableGlobalTransaction = false
    }
    
    client {
      rm {
        async.commit.buffer.limit = 10000
        lock {
          retry.internal = 10
          retry.times = 30
          retry.policy.branch-rollback-on-conflict = true
        }
        report.retry.count = 5
        table.meta.check.enable = false
        report.success.enable = true
      }
      tm {
        commit.retry.count = 5
        rollback.retry.count = 5
      }
      undo {
        data.validation = true
        log.serialization = "jackson"
        log.table = "undo_log"
      }
      log {
        exceptionRate = 100
      }
      support {
        # auto proxy the DataSource bean
        spring.datasource.autoproxy = false
      }
     }
    
  • register.conf this file is used to specify the configuration related to the registry. It has two core block s:

    • Block registry This template indicates the type used by our registry. We need to update the configuration information synchronously according to the type settings, such as the Eureka we use. Therefore, we update eureka.serviceUrl="http://172.16.1.187:21001/eureka"

    • Block config This module is used to set the configuration of our configuration center (we will select apollo for subsequent updates here)

    registry {
      # file ,nacos ,eureka,redis,zk,consul,etcd3,sofa
      type = "eureka"
    
      nacos {
        serverAddr = "localhost"
        namespace = ""
        cluster = "default"
      }
      eureka {
        serviceUrl = "http://172.16.1.187:21001/eureka"
        application = "default"
        weight = "1"
      }
      redis {
        serverAddr = "localhost:6379"
        db = "0"
      }
      zk {
        cluster = "default"
        serverAddr = "127.0.0.1:2181"
        session.timeout = 6000
        connect.timeout = 2000
      }
      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
      type = "file"
    
      nacos {
        serverAddr = "localhost"
        namespace = ""
      }
      consul {
        serverAddr = "127.0.0.1:8500"
      }
      apollo {
        app.id = "seata-server"
        apollo.meta = "http://192.168.1.204:8801"
      }
      zk {
        serverAddr = "127.0.0.1:2181"
        session.timeout = 6000
        connect.timeout = 2000
      }
      etcd3 {
        serverAddr = "http://localhost:2379"
      }
      file {
        name = "file.conf"
      }
    }
    

Running life | Blog Garden | segmentfault | spring4all | csdn | Nuggets | OSChina | Brief book | Headlines | Know about | 51CTO

Topics: Programming Spring MySQL Session Redis