Skip to content
清晨的一缕阳光
返回

Seata 核心概念

Seata 核心概念

什么是分布式事务

分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的节点之上。

分布式事务问题

┌─────────────┐      ┌─────────────┐
│  服务 A      │      │  服务 B      │
│  (订单服务)  │─────>│  (库存服务)  │
│             │      │             │
│  创建订单   │      │  扣减库存   │
│  ✅ 成功    │      │  ❌ 失败    │
└─────────────┘      └─────────────┘
       │                     │
       ▼                     ▼
┌─────────────┐      ┌─────────────┐
│  数据库 A    │      │  数据库 B    │
│  订单已创建  │      │  库存未扣减  │  ← 数据不一致!
└─────────────┘      └─────────────┘

CAP 理论

BASE 理论

Seata 简介

Seata(Simple Extensible Autonomous Transaction Architecture)是阿里巴巴开源的一站式分布式事务解决方案。

核心特性

三大角色

┌─────────────────────────────────────────────────────┐
│              Transaction Coordinator (TC)           │
│              事务协调器,维护全局事务状态              │
└───────────────────────┬─────────────────────────────┘

        ┌───────────────┼───────────────┐
        │               │               │
        ▼               ▼               ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Transaction  │ │ Transaction  │ │ Transaction  │
│ Manager (TM) │ │ Resource     │ │ Resource     │
│ 事务管理器    │ │ Manager (RM) │ │ Manager (RM) │
│             │ │ 资源管理器    │ │ 资源管理器    │
│ - 定义事务边界│ │ - 管理资源   │ │ - 管理资源   │
│ - 发起事务   │ │ - 注册分支   │ │ - 注册分支   │
└──────────────┘ └──────────────┘ └──────────────┘
    全局事务         分支事务 1        分支事务 2

全局事务流程

1. TM 向 TC 申请开启全局事务
2. TC 生成全局事务 ID(XID)
3. TM 将 XID 传递给业务服务
4. RM 向 TC 注册分支事务
5. TM 向 TC 提交或回滚全局事务
6. TC 协调所有分支事务提交或回滚

事务模式

1. AT 模式(Auto Transaction)

特点

工作原理

阶段一(Prepare):
1. 执行 SQL 并记录前镜像和后镜像
2. 提交本地事务
3. 释放本地锁

阶段二(Commit/Rollback):
- Commit:异步删除 undo_log
- Rollback:根据 undo_log 补偿数据

适用场景

2. TCC 模式(Try-Confirm-Cancel)

特点

工作原理

Try 阶段:
- 检查和预留资源
- 不执行业务操作

Confirm 阶段:
- 执行业务操作
- 使用 Try 阶段预留的资源

Cancel 阶段:
- 释放 Try 阶段预留的资源

代码示例

@LocalTCC
public interface TccTransactionService {
    
    @TCCBusinessActionName("tccAction")
    @TCCBusinessAction(methodName = "tryMethod", 
                       commitMethod = "confirmMethod", 
                       rollbackMethod = "cancelMethod")
    boolean tryMethod(TccParam param);
    
    boolean confirmMethod(TccParam param);
    
    boolean cancelMethod(TccParam param);
}

适用场景

3. Saga 模式

特点

工作原理

正向操作:Service1 → Service2 → Service3
补偿操作:Service3 补偿 → Service2 补偿 → Service1 补偿

配置示例

{
  "Name": "Saga 事务",
  "Comment": "Saga 事务示例",
  "Version": "1.0",
  "StartState": "Service1",
  "States": {
    "Service1": {
      "Type": "ServiceTask",
      "ServiceName": "service1",
      "Next": "Service2",
      "CompensateState": "Service1Compensate"
    },
    "Service2": {
      "Type": "ServiceTask",
      "ServiceName": "service2",
      "Next": "Service3",
      "CompensateState": "Service2Compensate"
    },
    "Service3": {
      "Type": "ServiceTask",
      "ServiceName": "service3",
      "End": true,
      "CompensateState": "Service3Compensate"
    }
  }
}

适用场景

4. XA 模式

特点

工作原理

阶段一(Prepare):
- 执行 SQL,不提交
- 等待 TC 指令

阶段二(Commit/Rollback):
- Commit:提交所有分支事务
- Rollback:回滚所有分支事务

适用场景

快速开始

1. 部署 Seata Server

# 下载 Seata Server
wget https://github.com/seata/seata/releases/download/v1.7.0/seata-server-1.7.0.tar.gz
tar -xzf seata-server-1.7.0.tar.gz

# 配置文件(registry.conf)
cd seata/conf
vim registry.conf
registry {
  type = "nacos"
  nacos {
    serverAddr = "localhost:8848"
    namespace = "public"
    group = "SEATA_GROUP"
    application = "seata-server"
  }
}

config {
  type = "nacos"
  nacos {
    serverAddr = "localhost:8848"
    namespace = "public"
    group = "SEATA_GROUP"
    dataId = "seataServer.properties"
  }
}

2. 添加依赖

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

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.7.0</version>
</dependency>

3. 配置 Seata

seata:
  enabled: true
  tx-service-group: default_tx_group
  service:
    vgroup-mapping:
      default_tx_group: default
    grouplist:
      default: 127.0.0.1:8091
  registry:
    type: nacos
    nacos:
      server-addr: localhost:8848
      namespace: public
      group: SEATA_GROUP
      application: seata-server
  config:
    type: nacos
    nacos:
      server-addr: localhost:8848
      namespace: public
      group: SEATA_GROUP
      data-id: seataServer.properties

4. 使用 AT 模式

@Service
public class OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private AccountService accountService;
    
    @Autowired
    private StorageService storageService;
    
    @GlobalTransactional  // 开启全局事务
    public void createOrder(Order order) {
        // 1. 创建订单
        orderMapper.insert(order);
        
        // 2. 扣减库存
        storageService.decrease(order.getProductId(), order.getCount());
        
        // 3. 扣减账户余额
        accountService.decrease(order.getUserId(), order.getAmount());
    }
}

5. 配置数据源

@Configuration
public class DataSourceConfig {
    
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return new DruidDataSource();
    }
    
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        return factoryBean.getObject();
    }
}

6. 创建 undo_log 表

-- MySQL
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`),
  KEY `ix_log_created` (`log_created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AT transaction mode undo table';

高可用部署

1. Seata Server 集群

# registry.conf
registry {
  type = "nacos"
  nacos {
    serverAddr = "nacos1:8848,nacos2:8848,nacos3:8848"
    namespace = "public"
    group = "SEATA_GROUP"
    application = "seata-server"
  }
}

# file.conf
store {
  mode = "db"
  db {
    datasource = "druid"
    dbType = "mysql"
    url = "jdbc:mysql://mysql1:3306/seata,mysql2:3306/seata"
    user = "seata"
    password = "seata"
    minConn = 5
    maxConn = 100
  }
}

2. 数据库配置

-- 创建 seata 数据库
CREATE DATABASE seata;

-- 创建事务表
CREATE TABLE `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;

-- 创建分支表
CREATE TABLE `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;

-- 创建锁表
CREATE TABLE `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;

最佳实践

1. 事务粒度

2. 性能优化

3. 异常处理

@GlobalTransactional
public void createOrder(Order order) {
    try {
        // 业务逻辑
        orderMapper.insert(order);
        storageService.decrease(order.getProductId(), order.getCount());
        accountService.decrease(order.getUserId(), order.getAmount());
    } catch (BusinessException e) {
        // 业务异常,抛出异常触发回滚
        throw e;
    } catch (Exception e) {
        // 系统异常,记录日志并抛出
        log.error("创建订单失败", e);
        throw new SystemException("系统异常", e);
    }
}

4. 监控告警

@Component
public class SeataMonitor {
    
    @Autowired
    private AlertService alertService;
    
    @EventListener
    public void onTransactionEvent(TransactionEvent event) {
        if (event.getStatus() == TransactionStatus.Rollbacked) {
            alertService.sendAlert("事务回滚:" + event.getXid());
        }
    }
}

常见问题

1. 事务不生效

问题:@GlobalTransactional 注解不生效

排查步骤

2. 性能问题

问题:使用 Seata 后性能下降

解决方案

3. 数据不一致

问题:分布式事务后数据不一致

解决方案

总结

Seata 提供了多种分布式事务解决方案,AT 模式无侵入且性能优异,TCC 模式适合高性能场景,Saga 模式适合长事务。

合理选择事务模式,优化事务粒度,可以有效解决分布式事务问题。

在生产环境中,建议部署 Seata Server 集群,做好监控告警,并建立完善的异常处理机制。


分享这篇文章到:

上一篇文章
Prompt 工程基础与方法论
下一篇文章
Spring Boot RESTful API 开发