Spring Boot 3微服务分布式事务实战:Seata AT模式与Saga编排的生产部署

微服务架构分布式事务的必要性判断

微服务拆分后,一个业务操作往往跨越多个服务,每个服务有独立的数据库,本地事务无法保证跨服务的数据一致性。但并非所有跨服务操作都需要分布式事务——很多场景可以通过最终一致性、补偿机制和幂等设计来规避,引入分布式事务框架的成本(性能损耗、运维复杂度、故障面扩大)不低。

需要引入分布式事务的典型场景:

– 资金类操作:余额扣减+流水记录必须原子化
– 库存+订单:超卖不可接受,必须强一致
– 多步骤业务流程:中间步骤失败需要回滚已完成的步骤

可以不用分布式事务的场景:

– 跨服务的数据只读查询
– 非关键数据的异步同步(如搜索索引更新)
– 可以通过消息队列实现最终一致性的操作

Seata AT模式:零侵入的自动分布式事务

Seata的AT(Automatic Transaction)模式通过代理数据源实现自动的两阶段提交,对业务代码侵入最小。核心原理:一阶段拦截SQL解析语义,生成回滚日志(undo_log),二阶段根据回滚日志自动提交或回滚。

Seata Server(TC事务协调器)部署:

# docker-compose-seata.yaml
version: '3.8'
services:
  seata-server:
    image: seataio/seata-server:2.2.0
    ports:
      - '8091:8091'
    environment:
      - SEATA_IP=seata-server
    volumes:
      - ./seata-config:/seata-server/resources
    depends_on:
      - seata-db
  seata-db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: seata_pwd
      MYSQL_DATABASE: seata
    volumes:
      - ./seata-init.sql:/docker-entrypoint-initdb.d/init.sql

Spring Boot 3集成Seata AT模式:

// 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-test-group
  service:
    vgroup-mapping:
      my-test-group: default
  registry:
    type: nacos
    nacos:
      server-addr: nacos:8848
      namespace: seata

每个参与事务的微服务数据库需要建undo_log表:

-- 每个业务库执行
CREATE TABLE IF NOT EXISTS `undo_log` (
  `branch_id`     BIGINCT       NOT NULL,
  `xid`           VARCHAR(128)  NOT NULL,
  `context`       VARCHAR(128)  NOT NULL,
  `rollback_info` LONGBLOB      NOT NULL,
  `log_status`    INT(11)       NOT NULL,
  `log_created`   DATETIME(6)   NOT NULL,
  `log_modified`  DATETIME(6)   NOT NULL,
  UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

业务代码只需在需要分布式事务的方法上加@GlobalTransactional注解:

@Service
public class OrderService {

    @GlobalTransactional(timeoutMills = 30000, name = 'create-order')
    public OrderResult createOrder(CreateOrderRequest request) {
        // 1. 创建订单(本地事务)
        Order order = orderMapper.insert(buildOrder(request));

        // 2. 调用库存服务扣减库存(远程事务)
        inventoryClient.deduct(request.getProductId(), request.getQuantity());

        // 3. 调用账户服务扣减余额(远程事务)
        accountClient.debit(request.getUserId(), order.getTotalAmount());

        return OrderResult.success(order);
    }
}

AT模式的全局锁机制是性能关键——一阶段本地提交后,Seata会锁定相关行,直到全局事务提交或回滚。高并发场景下全局锁争用严重,AT模式的TPS会显著下降。

Saga模式:长流程的补偿式事务

当业务流程涉及多个步骤且部分步骤无法回滚(如已发出的邮件、已调用的第三方API),AT模式的全局回滚不再适用。Saga模式通过正向执行+补偿回滚实现最终一致性。

Seata Saga的状态机定义(JSON DSL):

// saga-order.json — 订单创建Saga流程
{
  'Name': 'create-order-saga',
  'Comment': '订单创建Saga流程',
  'StartState': 'CreateOrder',
  'States': {
    'CreateOrder': {
      'Type': 'ServiceTask',
      'ServiceName': 'orderService',
      'ServiceMethod': 'create',
      'CompensateMethod': 'cancel',
      'Next': 'DeductInventory',
      'Input': ['$input.order']
    },
    'DeductInventory': {
      'Type': 'ServiceTask',
      'ServiceName': 'inventoryService',
      'ServiceMethod': 'deduct',
      'CompensateMethod': 'restore',
      'Next': 'DebitAccount',
      'Input': ['$input.order.productId', '$input.order.quantity']
    },
    'DebitAccount': {
      'Type': 'ServiceTask',
      'ServiceName': 'accountService',
      'ServiceMethod': 'debit',
      'CompensateMethod': 'credit',
      'Next': 'Succeed',
      'Input': ['$input.order.userId', '$input.order.totalAmount']
    },
    'Succeed': {
      'Type': 'Succeed'
    },
    'Fail': {
      'Type': 'Fail'
    }
  }
}

补偿方法必须满足幂等性——网络超时重试可能导致补偿方法被多次调用:

@Service
public class InventoryService {

    // 正向操作
    public boolean deduct(String productId, int quantity) {
        int affected = inventoryMapper.deduct(productId, quantity);
        if (affected == 0) {
            throw new BusinessException('库存不足');
        }
        return true;
    }

    // 补偿操作(幂等)
    public boolean restore(String productId, int quantity) {
        // 乐观锁版本号保证幂等
        inventoryMapper.restore(productId, quantity);
        return true;
    }
}

AT vs Saga的选型决策矩阵

| 维度 | AT模式 | Saga模式 |
|——|——–|———-|
| 一致性 | 强一致(短暂隔离期) | 最终一致 |
| 侵入性 | 低(仅加注解+undo_log) | 中(需写补偿方法) |
| 性能 | 全局锁限制并发 | 无全局锁,性能好 |
| 适用流程长度 | 3~5步 | 5步以上长流程 |
| 回滚能力 | 自动回滚 | 业务补偿 |
| 第三方服务 | 不支持(无法代理外部SQL) | 支持补偿 |

混合场景的推荐方案:核心资金链路用AT模式保证强一致,外围通知类操作用Saga或消息队列异步处理。

生产环境的运维与容灾

Seata Server的可用性直接影响所有分布式事务,必须做高可用部署:

# Seata Server多副本+Nacos注册
seata:
  server:
    raft:
      cluster: 'seata-server1:8091,seata-server2:8091,seata-server3:8091'
      snapshot-interval: 600

# 关键运维操作
# 1. 查看挂起的全局事务
curl 'http://seata-server:8091/api/v1/global-session?status=Begin'

# 2. 强制回滚超时事务
curl -X DELETE 'http://seata-server:8091/api/v1/global-session/{xid}'

# 3. undo_log清理(全局事务提交后可安全删除)
DELETE FROM undo_log WHERE log_status = 9 AND log_modified < DATE_SUB(NOW(), INTERVAL 7 DAY)

分布式事务不是微服务的标配——是最后的选择。在引入之前,先评估业务能否接受最终一致性、能否通过设计规避(如合并服务边界、使用事件驱动架构)。只有强一致性的刚性需求才值得付出分布式事务的复杂度代价。

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

(0)
小编小编
上一篇 4小时前
下一篇 4小时前

相关推荐