Seata 高可用与生产实践
Seata Server(TC)是分布式事务的协调中枢,一旦它不可用,所有全局事务都无法开启。生产环境必须做高可用部署,并与注册中心、配置中心、存储选型深度整合。本文给出完整的生产落地实践。
TC 高可用架构
单机模式的局限
单机 TC:
├─ 单点故障:TC 挂 → 全局事务全部中断
├─ 容量瓶颈:所有分支事务注册都打到一个节点
└─ 仅适合开发测试集群高可用方案
Seata 从 1.5 版本开始内置 Raft 模式,无需第三方协调组件:
方案一:Raft 模式(推荐,Seata 1.5+)
├─ TC 多个节点组成 Raft 集群(奇数节点,如 3 / 5)
├─ 选举产生 Leader,事务请求由 Leader 处理
├─ 数据通过 Raft 日志复制到所有节点
├─ Leader 故障 → 自动重新选举,秒级切换
└─ 事务状态不丢失(已同步到多数节点)
方案二:DB 模式 + 负载均衡
├─ 多个 TC 节点共用同一 MySQL(全局事务表)
├─ 前面挂 Nginx / SLB 做负载均衡
├─ 节点无状态,谁处理都行
└─ 数据库成为新的单点 → 数据库也要做主从部署架构图
客户端(业务应用)
│ 通过注册中心发现 TC 列表
▼
┌───── 注册中心(Nacos)─────┐
│ │
┌────┴────┐ ┌────┴────┐
│ TC-1 │ │ TC-2 │
│ (Raft) │◀─── Raft 复制 ───▶│ (Raft) │
└────┬────┘ └────┬────┘
└─────────┬──────────────────┘
▼
MySQL(Raft 模式内置存储,或 DB 模式共享库)高可用检查清单
├─ 节点数:Raft 模式至少 3 节点,最多 7 节点
├─ 网络:节点间延迟低、不跨机房(Raft 对网络敏感)
├─ 存储:Raft 模式下日志落盘(file),DB 模式下库做主从
├─ 监控:监控 TC 的 Leader 状态、事务堆积、心跳
└─ 升级:滚动升级,避免同时重启多数节点注册中心集成
客户端(TM/RM)需要发现 TC 地址,通过注册中心实现。
Nacos 集成配置
yaml
# registry.conf
registry {
type = "nacos"
nacos {
application = "seata-server" # 注册到 Nacos 的服务名
serverAddr = "127.0.0.1:8848"
group = "SEATA_GROUP"
namespace = ""
username = "nacos"
password = "nacos"
}
}注册中心对比
| 注册中心 | 说明 |
|---|---|
| Nacos | 最常用,Spring Cloud Alibaba 生态标配 |
| Consul | 支持健康检查与 KV 存储 |
| Eureka | Netflix 生态 |
| Zookeeper | 老牌协调组件 |
| etcd | 云原生,k8s 环境友好 |
配置中心集成
Seata 的配置项(存储模式、事务超时等)可放到配置中心统一管理,实现动态调整。
Nacos 配置中心
yaml
# registry.conf 中配置
config {
type = "nacos"
nacos {
serverAddr = "127.0.0.1:8848"
group = "SEATA_GROUP"
dataId = "seataServer.properties"
}
}常用配置项
properties
# seataServer.properties 示例
store.mode=db # 存储模式:db / raft / redis / file
store.db.datasourceType=druid
store.db.dbType=mysql
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=utf8
store.db.user=root
store.db.password=123456
store.db.maxConn=20
# 事务相关
service.enableDegrade=false # 是否开启降级(TC 不可用时本地执行)
client.tm.defaultGlobalTransactionTimeout=60000 # 全局事务超时(毫秒)存储模式选型
TC 需要持久化全局事务、分支事务、全局锁,Seata 支持多种存储:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| file | 本地文件存储,简单,不支持集群 | 开发测试 |
| db | MySQL 存储,支持集群 | 生产首选 |
| redis | Redis 存储,性能高 | 高并发、可接受 Redis 单点/集群方案 |
| raft | Seata 1.5+ 内置 Raft,日志文件存储 | 生产(配合 Raft 集群) |
DB 模式表结构
sql
-- 全局事务表
CREATE TABLE `global_table` (
`xid` VARCHAR(128) NOT NULL, -- 全局事务 ID
`transaction_id` BIGINT, -- 事务 ID
`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_status_gmt_modified` (`status`, `gmt_modified`)
);
-- 分支事务表
CREATE TABLE `branch_table` (
`branch_id` BIGINT NOT NULL, -- 分支事务 ID
`xid` VARCHAR(128) NOT NULL, -- 所属全局事务
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256), -- 数据源标识
`branch_type` VARCHAR(8), -- 分支类型 AT/TCC/SAGA/XA
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
);
-- 全局锁表
CREATE TABLE `lock_table` (
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(128),
`transaction_id` BIGINT,
`branch_id` BIGINT,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`)
);表清理与性能
├─ 定时任务清理:超时的 global_table / branch_table 记录
├─ undo_log 保留天数:按业务需要配置,避免无限堆积
├─ lock_table 与 branch_table 走内存缓存 + 定期落库
└─ 大事务(大量分支)会产生大量行,注意表容量规划客户端配置(业务应用)
Spring Boot 依赖
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>对应版本</version>
</dependency>application.yml
yaml
seata:
enabled: true
application-id: order-service
tx-service-group: my_tx_group # 事务分组
registry:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
application: seata-server
config:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
data-id: seataServer.properties事务分组与映射
事务分组(tx-service-group)→ TC 集群的映射关系存在配置中心:
├─ 客户端配置 tx-service-group = my_tx_group
└─ 配置中心中:
service.vgroupMapping.my_tx_group = default
含义:
业务应用请求时,Seata 通过分组名找到对应的 TC 集群
解耦了客户端与具体 TC 地址与 Spring Cloud / Dubbo 整合
Spring Cloud OpenFeign 整合
XID 传播依赖 seata-spring-boot-starter 自动装配:
├─ SeataFeignInterceptor:把 XID 写入 Feign 请求头
└─ 下游服务 SeataHandlerInterceptor:从请求头取出 XID 绑定线程Dubbo 整合
XID 传播依赖 seata-dubbo 扩展:
├─ TransactionPropagationFilter:把 XID 写入 RPC 隐式参数
└─ 消费端 / 提供端自动传递跨服务调用示例
java
@Service
public class OrderService {
@GlobalTransactional(name = "createOrder", timeoutMills = 30000)
public void createOrder(Order order) {
// 1. 本地写订单(AT:自动代理数据源)
orderMapper.insert(order);
// 2. 调用库存服务(XID 自动传播)
stockFeignClient.deduct(order.getSkuId(), order.getCount());
// 3. 调用账户服务(XID 自动传播)
accountFeignClient.deduct(order.getUserId(), order.getAmount());
// 4. 全部成功 → 自动 commit;抛异常 → 自动 rollback
}
}与 OpenFeign 整合时的注意事项
├─ 全局锁冲突会导致分支注册重试,Feign 超时要调大
├─ 服务间调用超时建议大于全局事务超时的一部分
├─ 幂等:分支事务可能重试,业务方法要幂等
└─ 异步调用(MQ)默认不参与全局事务,除非手动传播 XID生产实践要点
事务分组管理
├─ 每个微服务独立 tx-service-group 更精细
├─ 但会带来配置中心 vgroupMapping 条目多
└─ 常见做法:一个业务域一个分组(order_group、pay_group)超时与重试配置
├─ 全局事务超时:默认 60s,根据业务调整
├─ 分支注册重试:默认 5 次,间隔递增
├─ 锁冲突等待:AT 模式全局锁冲突重试 30 次
└─ 网络抖动:TC 与客户端间心跳超时合理设置监控与告警
├─ TC 监控:Leader 状态、活跃事务数、分支事务数
├─ 业务监控:全局事务开启成功率、回滚率
├─ 异常告警:LockConflictException 频繁、分支注册失败
└─ 慢事务:长事务占用全局锁,是性能隐患,重点排查降级策略
TC 不可用时的降级:
├─ service.enableDegrade=true:TC 不可用时,本地事务照常执行
│ └─ 代价:失去分布式一致性保证,需对账兜底
├─ 或:直接熔断全局事务入口(避免半途而废)
└─ 生产建议:开启降级 + 对账任务双保险总结
Seata 生产化的关键是 TC 高可用 + 存储选型 + 事务分组管理:Raft 模式解决了 TC 单点问题,DB 模式与 Redis 模式各有取舍;注册中心与配置中心把 Seata 融入微服务治理体系;事务分组让多业务域共用一套 TC 集群而互不干扰。配合超时、重试、监控、降级策略,才能让分布式事务在生产环境稳定运转。