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<InetSocketAddress> 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<String> clusters = new ArrayList<>();
            clusters.add(clusterName);
          // 向nacos拉取服务列表
            List<Instance> firstAllInstances = getNamingInstance().getAllInstances(PRO_SERVER_ADDR_KEY, clusters);
            if (null != firstAllInstances) {
                List<InetSocketAddress> 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<Instance> instances = ((NamingEvent) event).getInstances();
                    if (null == instances && null != CLUSTER_ADDRESS_MAP.get(clusterName)) {
                        CLUSTER_ADDRESS_MAP.remove(clusterName);
                    } else if (!CollectionUtils.isEmpty(instances)) {
                        List<InetSocketAddress> 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

(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、添加依赖。我的项目有父项目和子项目。

父项目的依赖如下:

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
    </parent>

    <packaging>pom</packaging>

    <properties>
        <springcloud.alibaba.version>2.1.0.RELEASE</springcloud.alibaba.version>
        <mybatis-plus-boot-starter.version>3.1.2</mybatis-plus-boot-starter.version>
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${springcloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--mybatis-plus-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus-boot-starter.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

子项目的依赖如下: 

 <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-seata</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

    </dependencies>

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。

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注解也可以加上这个注解

 如果有这个配置,也可以直接在配置文件中配置

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、启动即可。

客户端启动信息如下:

服务端信息如下:

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

将Seata服务端安装到本地

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

问题

 can not connect to services-server.

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 Spring Cloud Alibaba 技术栈搭建项目手脚架可以提高开发效率和项目可维护性,以下是基于 Spring Cloud Alibaba 技术栈的项目手脚架搭建步骤: 1. 环境准备 确保已安装 JDK,Maven,Nacos,RocketMQ,Seata 和 Sentinel 等必需的软件。 2. 创建 Spring Boot 项目 使用 Spring Initializr 创建一个 Spring Boot 项目,添加必需的依赖项: ```xml <!-- Spring Boot 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Cloud Alibaba 依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-dubbo</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> </dependency> <!-- RocketMQ 依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-stream-rocketmq</artifactId> </dependency> ``` 3. 配置 Nacos 在 application.properties 文件中添加 Nacos 相关配置: ```properties spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 spring.cloud.nacos.config.server-addr=127.0.0.1:8848 spring.cloud.nacos.config.namespace=dev ``` 4. 配置 Dubbo 在 application.properties 文件中添加 Dubbo 相关配置: ```properties spring.application.name=service-provider spring.cloud.dubbo.application.name=service-provider spring.cloud.dubbo.registry.address=nacos://127.0.0.1:8848 spring.cloud.dubbo.protocol.name=dubbo spring.cloud.dubbo.protocol.port=20880 ``` 5. 配置 RocketMQ 在 application.properties 文件中添加 RocketMQ 相关配置: ```properties spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876 spring.cloud.stream.rocketmq.binder.group=group1 ``` 6. 配置 Seata 在 application.properties 文件中添加 Seata 相关配置: ```properties spring.cloud.alibaba.seata.tx-service-group=my_test_tx_group ``` 7. 配置 Sentinel 在 application.properties 文件中添加 Sentinel 相关配置: ```properties spring.cloud.sentinel.transport.dashboard=127.0.0.1:8080 ``` 8. 创建 Dubbo 服务接口 ```java public interface HelloService { String sayHello(String name); } ``` 9. 实现 Dubbo 服务接口 ```java @Service(version = "1.0.0") public class HelloServiceImpl implements HelloService { @Override public String sayHello(String name) { return "Hello, " + name; } } ``` 10. 配置 Dubbo 服务提供者 ```java @Configuration public class DubboProviderConfig { @Bean public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName("service-provider"); return applicationConfig; } @Bean public RegistryConfig registryConfig() { RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setAddress("nacos://127.0.0.1:8848"); return registryConfig; } @Bean public ProtocolConfig protocolConfig() { ProtocolConfig protocolConfig = new ProtocolConfig(); protocolConfig.setName("dubbo"); protocolConfig.setPort(20880); return protocolConfig; } @Bean public ProviderConfig providerConfig() { ProviderConfig providerConfig = new ProviderConfig(); providerConfig.setTimeout(3000); return providerConfig; } @Bean public ServiceConfig<HelloService> helloServiceServiceConfig() { ServiceConfig<HelloService> serviceConfig = new ServiceConfig<>(); serviceConfig.setInterface(HelloService.class); serviceConfig.setRef(new HelloServiceImpl()); serviceConfig.setVersion("1.0.0"); return serviceConfig; } } ``` 11. 创建测试类 ```java @RunWith(SpringRunner.class) @SpringBootTest public class HelloServiceTest { @Reference(version = "1.0.0") private HelloService helloService; @Test public void sayHelloTest() { String result = helloService.sayHello("World"); Assert.assertEquals("Hello, World", result); } } ``` 12. 启动项目 正常启动项目,并在浏览器中访问 http://localhost:8848/nacos,可以看到 Nacos 控制台。 在 Dubbo 服务提供者启动后,在 Dubbo 服务消费者中调用 Dubbo 服务,验证服务调用成功。 在 Sentinel 控制台中配置相关规则,验证 Sentinel 报警和限流功能。 在 RocketMQ 控制台中创建一个主题,发送消息,验证消息发送和接收功能。 在 Seata 控制台中创建一个事务分组,验证分布式事务功能。 以上就是使用 Spring Cloud Alibaba 技术栈搭建项目手脚架的步骤,可以根据实际需求进行扩展和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值