spring cloud alibaba seata + nacos的搭建

seata分为服务端和客户端,分别来介绍是怎么启动的。

server

1、下载启动包:https://github.com/seata/seata/releases/download/v1.2.0/seata-server-1.2.0.zip

2、修改conf/registry.conf

registry.conf中分为两部分,一部分是注册中心,一部分为配置中心,在这里注册中心和配置中心我选择的都是nacos。

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

  nacos {
    application = "serverAddr"
    serverAddr = "127.0.0.1:8848"
    namespace = "public"
    cluster = "default"
  }
}

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

  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = "public"
    cluster = "default"
  }
}

为何将application 设置为serverAddr?

在我目前使用的seata版本中(目前使用的版本为0.7,换成其他版本应该不需要配置,默认是seata-server,但是具体还是需要看一下源码),NacosRegistryServiceImpl(因为我选择的是nacos作为注册中心)中有一个属性PRO_SERVER_ADDR_KEY,默认的值为serverAddr,seata client会定时的以serverAddr作为服务名称向nacos拉取列表,所以将application 设置为serverAddr。拉取服务列表的代码如下:

    @Override
    public List lookup(String key) throws Exception {
        Configuration config = ConfigurationFactory.getInstance();
        String clusterName = config.getConfig(PREFIX_SERVICE_ROOT + CONFIG_SPLIT_CHAR + PREFIX_SERVICE_MAPPING + key);
        if (null == clusterName) {
            return null;
        }
        if (!LISTENER_SERVICE_MAP.containsKey(clusterName)) {
            List clusters = new ArrayList<>();
            clusters.add(clusterName);
          // 向nacos拉取服务列表
            List firstAllInstances = getNamingInstance().getAllInstances(PRO_SERVER_ADDR_KEY, clusters);
            if (null != firstAllInstances) {
                List newAddressList = new ArrayList<>();
                for (Instance instance : firstAllInstances) {
                    if (instance.isEnabled() && instance.isHealthy()) {
                        newAddressList.add(new InetSocketAddress(instance.getIp(), instance.getPort()));
                    }
                }
                CLUSTER_ADDRESS_MAP.put(clusterName, newAddressList);
            }
            subscribe(clusterName, new EventListener() {
                @Override
                public void onEvent(Event event) {
                    List instances = ((NamingEvent) event).getInstances();
                    if (null == instances && null != CLUSTER_ADDRESS_MAP.get(clusterName)) {
                        CLUSTER_ADDRESS_MAP.remove(clusterName);
                    } else if (!CollectionUtils.isEmpty(instances)) {
                        List newAddressList = new ArrayList<>();
                        for (Instance instance : instances) {
                            if (instance.isEnabled() && instance.isHealthy()) {
                                newAddressList.add(new InetSocketAddress(instance.getIp(), instance.getPort()));
                            }
                        }
                        CLUSTER_ADDRESS_MAP.put(clusterName, newAddressList);
                    }
                }
            });
        }
        return CLUSTER_ADDRESS_MAP.get(clusterName);
    }

3、将配置信息上传至nacos。在https://github.com/seata/seata/tree/1.2.0/script/config-center中一个文件config.txt,将这个文件下载下来,修改一下其中的信息,主要修改一下几个配置:

(1)vgroup_mapping后面的是自己定义的,不过要和seata client端配置的spring.cloud.alibaba.seata.tx-service-group要一样即可,有几个client就配置几个,此处我只有两个client端,就配置了两个。

service.vgroup_mapping.order-service-group=default
service.vgroup_mapping.storage-service-group=default

spring cloud alibaba seata + nacos的搭建_第1张图片

(2)数据源信息的修改:

spring cloud alibaba seata + nacos的搭建_第2张图片

(3)上传至nacos,利用https://github.com/seata/seata/tree/1.2.0/script/config-center/nacos 下的nacos-config.sh上传。

sh nacos-config.sh 127.0.0.1(nacos的ip地址)

下面是我的配置文件:

transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=false
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
service.vgroup_mapping.order-service-group=default
service.vgroup_mapping.storage-service-group=default
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=false
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
store.mode=file
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionSize=512
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
store.file.sessionReloadReadSize=100
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true
store.db.user=root
store.db.password=1111
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
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.log.exceptionRate=100
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

4、创建三张表。

-- -------------------------------- 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;

5、启动nacos

6、启动seata-server,点击bin目录下的seata-server.bat。看到以下信息说明启动成功了。

到此为止server端已经配置完毕,接下来开始client端的配置。

client

1、添加依赖。我的项目有父项目和子项目。

父项目的依赖如下:

 
        org.springframework.boot
        spring-boot-starter-parent
        2.2.2.RELEASE
    

    pom

    
        2.1.0.RELEASE
        3.1.2
        Finchley.RELEASE
    

    
        
            
                com.alibaba.cloud
                spring-cloud-alibaba-dependencies
                ${springcloud.alibaba.version}
                pom
                import
            

            
            
                com.baomidou
                mybatis-plus-boot-starter
                ${mybatis-plus-boot-starter.version}
            

            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud.version}
                pom
                import
            
        
    

子项目的依赖如下: 

 
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        

        
            org.springframework.boot
            spring-boot-starter-web
        

        
            com.alibaba.cloud
            spring-cloud-alibaba-seata
        

        
            mysql
            mysql-connector-java
            runtime
        

        
            com.baomidou
            mybatis-plus-boot-starter
        

        
            org.projectlombok
            lombok
        

        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-config
        

    

2、配置。

(1)配置配置中心,在bootstrap.yml中配置。

spring:
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848

(2)nacos注册中心,数据源以及其他配置。

server:
  port: 8888

spring:
  cloud:
    nacos:
      discovery:
#        server-addr: 127.0.0.1:8848,127.0.0.1:8847 多个nacos服务用逗号隔开
        server-addr: 127.0.0.1:8848
    alibaba:
      seata:
        tx-service-group: order-service-group # seata 服务分组,要与服务端nacos-config.txt中service.vgroup_mapping的后缀对应
  application:
    name: nacos-provider #名称需要配置,不然不会注册
  datasource:
    url: jdbc:mysql://localhost:3306/seata_order?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: 1111
    type: com.alibaba.druid.pool.DruidDataSource

#logging:
#  level:
#    io.seata: debug
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
  mapper-locations: mappers/*.xml

3、将registry.conf文件拷贝到根目录下,就是server端的registry.conf。

spring cloud alibaba seata + nacos的搭建_第3张图片

4、创建业务表和undo_log 表

CREATE TABLE `order_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `commodity_code` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT '0',
  `money` int(11) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=62 DEFAULT CHARSET=utf8;
CREATE TABLE `storage_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `commodity_code` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
CREATE TABLE `undo_log` (
  `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(6) NOT NULL COMMENT 'create datetime',
  `log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='AT transaction mode undo table';

5、将数据源修改为DataSourceProxy。

@Configuration
public class DataSourceProxyConfig implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof DataSource) {
            return new DataSourceProxy((DataSource)bean);
        }
        return bean;
    }
}

如果有@EnableAutoDataSourceProxy注解也可以加上这个注解

spring cloud alibaba seata + nacos的搭建_第4张图片 如果有这个配置,也可以直接在配置文件中配置

6、在业务方法上添加@GlobalTransactional注解。

    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    public void placeOrder(String userId, String commodityCode, Integer count) {
        BigDecimal orderMoney = new BigDecimal(count).multiply(new BigDecimal(5));
        Order order = new Order();
        order .setUserId(userId);
        order.setCommodityCode(commodityCode);
        order.setCount(count);
        order.setMoney(orderMoney);

        orderMapper.insert(order);
        storageFeignClient.deduct(commodityCode, count);
    }

7、创建undo_logo,如果每个client端一个数据库,那么要在所有的数据库中创建这张表,否则不会回滚。

-- 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`
(
    `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(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

8、启动即可。

客户端启动信息如下:

服务端信息如下:

spring cloud alibaba seata + nacos的搭建_第5张图片

还有一个仓储服务,和上面的配置一样 

将Seata服务端安装到本地

出现以下问题:说明maven版本太低,需要下载版本3.6.0版本的maven,然后修改IDEA的maven配置

spring cloud alibaba seata + nacos的搭建_第6张图片

问题

 can not connect to services-server.

客户端连接不上服务端,确保两端的ip是在同一局域网内。

比如客户端注册的ip地址为192.168.228.1,服务端注册的为192.168.92.1,这样两端的ip地址不在同一网段内,也会连接不上

你可能感兴趣的:(java,spring,cloud,微服务)