Spring Boot微服务架构下分布式事务实战方案:Seata AT模式深度配置与生产调优

微服务场景下分布式事务的选型判断

微服务拆分后,一个业务操作跨多个服务的数据一致性保障是架构设计的核心难题。在Spring Boot微服务架构中,分布式事务方案的选择不是非此即彼,而是需要根据业务特征做判断:

强一致性场景(如账户转账、库存扣减):必须用分布式事务保证ACID。Seata的AT模式对业务代码侵入最小,是目前最主流的选择。

最终一致性场景(如订单状态流转、消息通知):可靠消息最终一致性方案更合适,通过RocketMQ事务消息+本地消息表实现。

混合场景:核心链路用Seata AT模式,非核心链路用消息驱动。不要一刀切。

本文聚焦Seata AT模式在Spring Boot微服务中的深度配置与生产调优。

Seata AT模式的事务协调机制解析

Seata AT模式的核心是全局锁机制。事务协调流程分为三个阶段:

一阶段:拦截业务SQL,生成前镜像(before image),执行业务SQL,生成后镜像(after image),生成回滚日志(undo_log),提交本地事务前申请全局锁。

二阶段-提交:异步删除undo_log,释放全局锁。因为一阶段已经提交了本地事务,二阶段提交是异步的,性能开销极低。

二阶段-回滚:根据undo_log中的前镜像反向补偿,释放全局锁。

全局锁的粒度是行级锁,锁的key是表名+主键值。这意味着不同行的数据可以并发操作,同一行的数据会被串行化。理解这一点对性能调优至关重要。

Seata Server的高可用部署配置

生产环境Seata Server必须集群部署。推荐使用Nacos作为注册中心和配置中心:

# seata-server application.yml
server:
  port: 8091

seata:
  config:
    type: nacos
    nacos:
      server-addr: nacos-cluster:8848
      namespace: seata
      group: SEATA_GROUP
      data-id: seataServer.properties
  registry:
    type: nacos
    nacos:
      server-addr: nacos-cluster:8848
      namespace: seata
      group: SEATA_GROUP
      application: seata-server
  store:
    mode: db
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://mysql-cluster:3306/seata?rewriteBatchedStatements=true
      user: seata
      password: ${SEATA_DB_PASSWORD}
      min-conn: 10
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 1000

Seata Server的数据库需要提前创建表结构。全局事务状态表、分支事务表和锁表是核心表,数据量取决于并发事务量。对于高并发场景,建议对global_table的xid和status字段建联合索引,对lock_table的table_name+pk字段建联合索引。

Spring Boot微服务的Seata客户端集成

每个参与分布式事务的微服务都需要集成Seata客户端。依赖和配置如下:

<!-- pom.xml -->
<dependency>
  <groupId>io.seata</groupId>
  <artifactId>seata-spring-boot-starter</artifactId>
  <version>2.2.0</version>
</dependency>
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
  <version>2023.0.1.2</version>
</dependency>
# application.yml
seata:
  enabled: true
  application-id: order-service
  tx-service-group: my-tx-group
  service:
    vgroup-mapping:
      my-tx-group: default
  registry:
    type: nacos
    nacos:
      server-addr: nacos-cluster:8848
      namespace: seata
      group: SEATA_GROUP
      application: seata-server
  config:
    type: nacos
    nacos:
      server-addr: nacos-cluster:8848
      namespace: seata
      group: SEATA_GROUP
      data-id: seataClient.properties

数据源代理是AT模式生效的关键。Seata通过代理数据源拦截SQL执行。如果项目中有多个数据源,每个都需要代理:

@Configuration
public class DataSourceProxyConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public DataSource dataSource() {
        HikariDataSource hikariDataSource = new HikariDataSource();
        return new DataSourceProxy(hikariDataSource);
    }
}

每个微服务数据库中的undo_log表必须手动创建:

CREATE TABLE IF NOT EXISTS `undo_log` (
  `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
  `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
  `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context',
  `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 = utf8mb4 COMMENT ='AT transaction mode undo log';

订单-库存-账户三服务分布式事务实战

以经典的下单扣库存扣余额为例,展示完整的分布式事务配置:

// 订单服务 - 事务发起方
@Service
public class OrderService {

    @DubboReference
    private InventoryService inventoryService;

    @DubboReference
    private AccountService accountService;

    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    public Order createOrder(OrderDTO orderDTO) {
        // 1. 创建订单
        Order order = orderMapper.insert(orderDTO);

        // 2. 扣减库存(远程调用)
        inventoryService.deduct(orderDTO.getProductId(),
                               orderDTO.getCount());

        // 3. 扣减账户余额(远程调用)
        accountService.debit(orderDTO.getUserId(),
                             orderDTO.getAmount());

        // 4. 更新订单状态
        orderMapper.updateStatus(order.getId(), "PAID");
        return order;
    }
}

@GlobalTransactional注解标记事务边界。Seata会自动传播xid到远程调用链路。如果步骤2或3抛出异常,步骤1的订单记录会被自动回滚(基于undo_log的前镜像补偿)。

这里有一个关键细节:远程调用的传播机制。Dubbo和Feign都有对应的Seata拦截器,自动在请求头中携带xid。如果使用RestTemplate或其他HTTP客户端,需要手动传播:

// RestTemplate的xid传播拦截器
public class SeataRestTemplateInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request,
            byte[] body, ClientHttpRequestExecution execution) throws IOException {
        String xid = RootContext.getXID();
        if (xid != null) {
            request.getHeaders().set(RootContext.KEY_XID, xid);
        }
        return execution.execute(request, body);
    }
}

Seata AT模式的生产调优要点

全局锁超时调优:默认全局锁等待时间是30秒。在高并发场景,如果一个事务持有锁时间较长,其他事务会频繁超时回滚。根据业务RT调整:

# seataClient.properties
seata.client.lock.retry-interval=10
seata.client.lock.retry-times=30
seata.client.lock.retry-policy-branch-rollback-on-conflict=true

undo_log清理:已提交事务的undo_log没有自动清理机制,需要定时任务清理。建议保留7天,防止极端情况下需要手动回滚:

@Scheduled(cron = "0 0 3 * * ?")
public void cleanUndoLog() {
    LocalDate expireDate = LocalDate.now().minusDays(7);
    undoLogMapper.deleteByLogCreatedBefore(expireDate);
}

写隔离与脏读防护:AT模式默认是读未提交隔离级别。在全局事务提交前,本地事务已经提交,其他事务可以读到未最终确认的数据。如果业务对隔离性要求严格,需要开启全局锁读防护:

# 开启全局锁读防护
seata.client.undo-data-validation=true
seata.client.undo-log-serialization=jackson

Seata Server性能监控:通过Seata Server暴露的Metrics端点监控事务成功率和延迟:

# prometheus配置
- job_name: 'seata'
  metrics_path: '/metrics'
  static_configs:
  - targets: ['seata-server:8091']

# 关键指标:
# seata_transaction_total{status="committed"}   提交数
# seata_transaction_total{status="rollbacked"}  回滚数
# seata_transaction_duration_seconds           事务耗时分布

当回滚率持续超过5%时需要排查业务逻辑,可能是并发冲突热点或事务粒度过大。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springboot-wei-fu-wu-jia-gou-xia-fen-bu-shi-shi-wu-shi-zhan/

(0)
小编小编
上一篇 54分钟前
下一篇 52分钟前

相关推荐