likes
comments
collection
share

一文搞懂微服务的Seata➕Nacos配置

作者站长头像
站长
· 阅读数 20

微服务的Seata➕Nacos配置

关于作者

  • 作者介绍


前言

在分布式系统中,事务管理是一个非常重要的问题。Seata是一款轻量级的分布式事务解决方案,它基于阿里巴巴的Dubbo RPC框架,并且可以与Spring Cloud集成。本文将介绍如何在Spring Cloud Alibaba中使用Seata,包括Seata的架构、配置以及使用方法。

准备工作

在开始配置Spring Cloud Alibaba Seata之前,我们需要先确保系统已满足以下条件:

  • Java运行环境已安装
  • Maven已安装
  • 了解Spring Boot基础知识

Seata架构

Seata的架构包括三个组件:Transaction Coordinator(TC)、Transaction Manager(TM)和Resource Manager(RM)。其中,TC负责全局事务的协调和管理,TM负责本地事务的管理,RM负责资源的分支事务管理。

下图展示了Seata的基本架构:

一文搞懂微服务的Seata➕Nacos配置

在Seata中,全局事务由一个TC实例进行协调和管理。TC可以通过与TM和RM进行通信来实现全局事务的提交和回滚。

在一个分布式系统中,每个服务都可以作为一个TM实例运行。当服务需要进行事务操作时,TM会向TC注册一个本地事务,并且向RM发送分支事务请求。RM可以将分支事务与本地事务进行关联,从而实现分支事务的管理。

Seata融合Nacos

Seata远端配置

Seata是一款开源的分布式事务解决方案,而Nacos是一款分布式配置中心。要将Seata与Nacos进行融合,可以按照以下步骤操作:

从Seata官网仓库下载源码包,并解压,建表。

Seata Server 共有以下 3 种存储模式(store.mode):

模式说明准备工作
file文件存储模式,默认存储模式; 该模式为单机模式,全局事务的会话信息在内存中读写,并持久化本地文件 root.data,性能较高-
db数据库存储模式; 该模式为高可用模式,全局事务会话信息通过数据库共享,性能较低。建数据库表
redis缓存处处模式; Seata Server 1.3 及以上版本支持该模式,性能较高,但存在事务信息丢失风险,配置 redis 持久化配置

在 db 模式下,我们需要针对全局事务的会话信息创建以下 3 张数据库表。

  • 全局事务表,对应的表为:global_table
  • 分支事务表,对应的表为:branch_table
  • 全局锁表,对应的表为:lock_table

在 MySQL 中,创建一个名为 seata 的数据库实例,并在该数据库内执行以下 SQL。

global_table 的建表 SQL 如下。

-- -------------------------------- storeMode为“db”时使用的脚本 --------------------------------
-- 全局事务表--
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;

branch_table 的建表 SQL 如下。

-- 事务分支表 --
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;

lock_table 的建表 SQL 如下。

-- 锁定表--
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;

distributed_lock 的建表 SQL 如下。

-- seata新版本加的锁表--
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    PRIMARY KEY (`lock_key`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8mb4;
 
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);

数据库中添加回滚日志表UNDO_LOG:

UNDO_LOG必须在每个业务数据库中出现,用于保存回滚操作数据。

  • 当全局事务提交时,对应的UNDO_LOG记录直接删除。
  • 当全局事务回滚时,通过该表回滚到以前的数据,并删除UNDO_LOG记录。

Seata的UNDO_LOG表和数据库的UNDO_LOG是相似的,只不过它们的范围不一样

undo_log 的建表 SQL 如下。

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,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

注意:

  • 前面的UNDO_LOG表是加在业务数据库中的。每个业务数据库都要有UNDO_LOG
  • seata1.4.2之后,需要回滚的表日期类型不能使用datetime,可以使用timestamp

在Seata的script/config-center路径下获取config.txt文件。

#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
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
transport.serialization=seata
transport.compressor=none

#Transaction routing rules configuration, only for the client
service.vgroupMapping.default_tx_group=default
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false

#Transaction rule configuration, only for the client
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=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
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.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h

#Log rule configuration, for client and server
log.exceptionRate=100

#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
store.mode=file
store.lock.mode=file
store.session.mode=file
#Used for password encryption
store.publicKey=

#If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block.
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

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
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&rewriteBatchedStatements=true
store.db.user=username
store.db.password=password
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

#These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block.
store.redis.mode=single
store.redis.single.host=127.0.0.1
store.redis.single.port=6379
store.redis.sentinel.masterName=
store.redis.sentinel.sentinelHosts=
store.redis.maxConn=10
store.redis.minConn=1
store.redis.maxTotal=100
store.redis.database=0
store.redis.password=
store.redis.queryLimit=100

#Transaction rule configuration, only for the server
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
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

在Nacos配置中心里新建seataServer.properties配置,并将config.txt文件内的内容复制进去。

一文搞懂微服务的Seata➕Nacos配置

修改Seata服务的配置,具体包括:

  • 获取Seata的程序包并解压。

  • 进入conf目录下的registry.conf文件。

  • 找到registry下的type配置,将其改为nacos

  • 找到nacos配置并进行修改。

    一文搞懂微服务的Seata➕Nacos配置

    config {
      type = "nacos"
    
      nacos {
        serverAddr = "127.0.0.1:8848"
        group = "SEATA_GROUP"
        namespace = ""
        username = "nacos"
        password = "nacos"
      }
    }
    
    registry {
      type = "nacos"
    
      nacos {
        application = "seata-server"
        serverAddr = "127.0.0.1:8848"
        group = "SEATA_GROUP"
        namespace = ""
        cluster = "default"
        username = "nacos"
        password = "nacos"
      }
    }
    

编辑Nacos的配置,具体包括:

  • 在Nacos配置中心里新建seataServer.properties配置。
  • 将Seata的配置信息复制进去,如defaultregistry.conf中的default

启动Seata和Nacos服务,完成Seata与Nacos的融合。

一文搞懂微服务的Seata➕Nacos配置

以上步骤详细描述了将Seata与Nacos进行融合的过程。请根据实际需求进行相应的调整和修改。

Seata本地配置

在Spring Cloud Alibaba中使用Seata需要进行如下配置:

  1. 添加依赖

在项目中添加如下依赖:

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-all</artifactId>
    <version>1.7.0</version>
</dependency>
  1. 配置文件

在项目的配置文件中 application.yml 添加如下配置:

seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: ${spring.application.name}-fescar-service-group
  service:
    vgroup-mapping:
      ${spring.application.name}-fescar-service-group: default
    group-default:
      default:
        defaultGlobalTransactionTimeout: 60000
  registry:
    type: nacos
    nacos:
      server-addr: ${spring.cloud.nacos.discovery.server-addr}
      namespace: ${spring.cloud.nacos.config.namespace}
      group: SEATA_GROUP
      cluster: default
  config:
    type: nacos
    nacos:
      server-addr: ${spring.cloud.nacos.discovery.server-addr}
      namespace: ${spring.cloud.nacos.config.namespace}
      group: SEATA_GROUP
      cluster: default
  • seata.enabled:是否启用Seata。
  • seata.application-id:Seata应用ID,通常使用Spring应用程序名称。
  • seata.tx-service-group:Seata事务服务组ID,通常使用${spring.application.name}-fescar-service-group
  • seata.service.vgroup-mapping:Seata服务分组映射。
  • seata.service.group-default:Seata服务默认配置。
  • seata.registry.type:Seata注册中心类型,这里使用的是Nacos。
  • seata.registry.nacos.server-addr:Nacos注册中心地址,从Spring Cloud配置中心获取。
  • seata.registry.nacos.namespace:Nacos注册中心命名空间,从Spring Cloud配置中心获取。
  • seata.registry.nacos.group:Nacos注册中心分组。
  • seata.registry.nacos.cluster:Nacos注册中心集群。
  • seata.config.type:Seata配置中心类型,这里使用的是Nacos。
  • seata.config.nacos.server-addr:Nacos配置中心地址,从Spring Cloud配置中心获取。
  • seata.config.nacos.namespace:Nacos配置中心命名空间,从Spring Cloud配置中心获取。
  • seata.config.nacos.group:Nacos配置中心分组。
  • seata.config.nacos.cluster:Nacos配置中心集群。

Seata使用方法

在Spring Cloud Alibaba中使用Seata非常简单,只需要按照如下步骤进行操作:

  1. 启动Seata Server

首先需要启动Seata Server,Seata Server是一个独立的进程,用于管理全局事务。可以通过下载Seata Server并运行启动脚本来启动Seata Server。

一文搞懂微服务的Seata➕Nacos配置

  1. 配置数据源代理

在使用Seata时,需要使用数据源代理来拦截SQL语句,从而实现分支事务的管理。在Spring Cloud Alibaba中,可以使用Seata提供的数据源代理来实现。

具体来说,可以在项目中引入Seata提供的数据源代理依赖,并在数据源配置中使用Seata提供的数据源代理类来代理数据源。

例如,在使用Druid作为数据源时,可以按照如下方式配置数据源代理:

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-datasource-proxy</artifactId>
    <version>1.7.0</version>
</dependency>
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    proxy-filters: com.alibaba.druid.filter.stat.StatFilter, io.seata.rm.datasource.SeataDataSourceProxy

在数据源配置中,将Seata提供的数据源代理类io.seata.rm.datasource.SeataDataSourceProxy添加到proxy-filters中即可。

  1. 配置分布式事务

主启动上加注解 @EnableTransactionManagement

在进行分布式事务操作时,需要通过Seata提供的@GlobalTransactional注解来标记全局事务。

例如,在使用MyBatis进行数据库操作时,可以按照如下方式使用@GlobalTransactional注解:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    @GlobalTransactional
    public void transfer(String fromAccount, String toAccount, BigDecimal amount) {
        User fromUser = userMapper.selectByAccount(fromAccount);
        User toUser = userMapper.selectByAccount(toAccount);
        fromUser.setBalance(fromUser.getBalance().subtract(amount));
        toUser.setBalance(toUser.getBalance().add(amount));
        userMapper.updateByPrimaryKey(fromUser);
        userMapper.updateByPrimaryKey(toUser);
    }
}

在上述代码中,使用@GlobalTransactional注解标记了transfer()方法,从而实现了分布式事务。

故障排除

如果在配置或使用过程中遇到了问题,可以检查以下几点:

  • Seata相关配置是否正确
  • Seata Server是否正常启动,并可以被访问
  • Seata Client是否正确配置,并与Seata Server保持连接
  • 业务代码中是否正确使用了Seata的事务处理机制

通过仔细检查这些关键点,你应该能够顺利地配置和使用Spring Cloud Alibaba Seata,实现高效的数据存储和处理。

小结

本文介绍了在Spring Cloud Alibaba中使用Seata的方法,包括Seata的架构、配置以及使用方法。通过使用Seata,可以在分布式系统中实现分布式事务的管理,从而保证数据的一致性和完整性。

转载自:https://juejin.cn/post/7271092862849351737
评论
请登录