微服务架构下,跨服务的数据一致性是后端开发面临的核心挑战。Seata作为阿里开源的分布式事务中间件,其AT(Automatic Transaction)模式通过SQL解析和undo_log自动补偿机制,对业务代码侵入性极低。本文以Spring Boot项目为例,完整演示Seata Server部署、AT模式集成、事务注解使用及生产环境调优全过程。
Seata AT模式架构原理与组件职责
Seata AT模式包含三个核心角色:
- TC(Transaction Coordinator):事务协调器,独立部署的Seata Server,负责维护全局事务和分支事务的状态,驱动全局提交或回滚
- TM(Transaction Manager):事务管理器,定义全局事务的开启、提交、回滚边界,通过@GlobalTransactional注解标注
- RM(Resource Manager):资源管理器,管理本地资源(数据库连接),注册分支事务,执行本地SQL并记录undo_log
AT模式的两阶段提交流程:
- 一阶段:拦截业务SQL,解析SQL语义生成before image和after image,将前后镜像存入undo_log表。本地事务在同一个数据库事务中提交(业务SQL + undo_log写入),立即释放本地锁和连接资源
- 二阶段-提交:TC通知各RM异步删除undo_log记录,因一阶段数据已落库,此操作非常快
- 二阶段-回滚:TC通知各RM根据undo_log的before image反向生成补偿SQL,恢复数据到事务开始前状态
Seata Server部署与Nacos注册中心配置
Seata Server使用Nacos作为注册中心和配置中心:
# docker-compose.yml 部署Seata Server 2.0
version: '3.8'
services:
seata-server:
image: seataio/seata-server:2.0.0
container_name: seata-server
ports:
- "8091:8091"
- "7091:7091"
environment:
- SEATA_PORT=8091
- STORE_MODE=db
- SEATA_IP=192.168.1.100
volumes:
- ./seata-config/application.yml:/seata-server/resources/application.yml
# application.yml
seata:
config:
type: nacos
nacos:
server-addr: 192.168.1.50:8848
group: SEATA_GROUP
namespace: seata
data-id: seataServer.properties
registry:
type: nacos
nacos:
server-addr: 192.168.1.50:8848
group: SEATA_GROUP
namespace: seata
cluster: default
store:
mode: db
db:
datasource: druid
db-type: mysql
url: jdbc:mysql://192.168.1.60:3306/seata?useUnicode=true
user: seata
password: SeataPass2026
min-conn: 10
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
query-limit: 1000
Seata Server元数据库初始化SQL:
-- 创建seata数据库
CREATE DATABASE seata DEFAULT CHARACTER SET utf8mb4;
-- global_table: 全局事务表
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)
);
-- branch_table: 分支事务表
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,
gmt_modified DATETIME,
PRIMARY KEY (branch_id)
);
-- lock_table: 全局锁表
CREATE TABLE lock_table (
row_key VARCHAR(128) NOT NULL,
xid VARCHAR(128),
transaction_id BIGINT,
branch_id BIGINT NOT NULL,
resource_id VARCHAR(256),
table_name VARCHAR(64),
pk VARCHAR(36),
status TINYINT,
gmt_create DATETIME,
gmt_modified DATETIME,
PRIMARY KEY (row_key)
);
Spring Boot微服务集成Seata AT模式
Maven依赖引入:
<!-- pom.xml -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2023.0.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.3.0</version>
</dependency>
application.yml配置:
seata:
enabled: true
application-id: order-service
tx-service-group: yunthe_tx_group
service:
vgroup-mapping:
yunthe_tx_group: default
grouplist:
default: 192.168.1.100:8091
registry:
type: nacos
nacos:
server-addr: 192.168.1.50:8848
group: SEATA_GROUP
namespace: seata
config:
type: nacos
nacos:
server-addr: 192.168.1.50:8848
group: SEATA_GROUP
namespace: seata
data-source-proxy-mode: AT
每个参与分布式事务的数据库必须创建undo_log表:
-- 在业务数据库中执行(order_db, inventory_db, account_db)
CREATE TABLE undo_log (
branch_id BIGINT NOT NULL COMMENT '分支事务ID',
xid VARCHAR(128) NOT NULL COMMENT '全局事务ID',
context VARCHAR(128) NOT NULL COMMENT '上下文',
rollback_info LONGBLOB NOT NULL COMMENT '回滚信息',
log_status INT NOT NULL COMMENT '状态',
log_created DATETIME NOT NULL COMMENT '创建时间',
log_modified DATETIME NOT NULL COMMENT '修改时间',
ext VARCHAR(100) COMMENT '扩展信息',
PRIMARY KEY (branch_id),
UNIQUE KEY ux_undo_log (xid, branch_id)
) ENGINE=InnoDB COMMENT='AT模式undo_log表';
分布式事务注解使用与业务场景实现
以电商下单场景为例:订单服务创建订单 → 库存服务扣减库存 → 账户服务扣减余额。任一步骤失败则全部回滚。
// OrderService.java - 全局事务发起方
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private InventoryFeignClient inventoryClient;
@Autowired
private AccountFeignClient accountClient;
@GlobalTransactional(
name = "create-order-tx",
timeoutMills = 60000,
rollbackFor = Exception.class
)
public Order createOrder(OrderDTO dto) {
// 1. 创建订单
Order order = new Order();
order.setUserId(dto.getUserId());
order.setProductId(dto.getProductId());
order.setCount(dto.getCount());
order.setMoney(dto.getMoney());
order.setStatus(0); // 待支付
orderMapper.insert(order);
// 2. 远程调用库存服务扣减库存
Result inventoryResult = inventoryClient.deduct(
dto.getProductId(), dto.getCount()
);
if (!inventoryResult.isSuccess()) {
throw new BusinessException("库存扣减失败: " + inventoryResult.getMessage());
}
// 3. 远程调用账户服务扣减余额
Result accountResult = accountClient.debit(
dto.getUserId(), dto.getMoney()
);
if (!accountResult.isSuccess()) {
throw new BusinessException("余额扣减失败: " + accountResult.getMessage());
}
// 4. 更新订单状态
order.setStatus(1); // 已支付
orderMapper.updateStatus(order.getId(), 1);
return order;
}
}
// InventoryService.java - 分支事务参与方
@Service
public class InventoryService {
@Autowired
private InventoryMapper inventoryMapper;
public boolean deduct(Long productId, Integer count) {
Inventory inventory = inventoryMapper.selectByProductId(productId);
if (inventory.getCount() < count) {
throw new BusinessException("库存不足");
}
// Seata自动拦截此SQL,生成undo_log
int rows = inventoryMapper.deductCount(productId, count);
return rows > 0;
}
}
Seata AT模式生产环境调优与常见排障
事务超时配置需根据业务实际执行时间调整。默认超时60秒,如果涉及多个远程调用且网络延迟较高,建议设为120秒。超时后TC会自动发起回滚,但已提交的分支事务需等待undo_log补偿。
# Nacos中seataServer.properties调优参数
# 全局事务重试间隔(毫秒)
client.rm.reportRetryCount = 5
client.rm.tableMetaCheckEnable = true
client.rm.tableMetaCheckerInterval = 60000
client.rm.sqlParserType = druid
# 异步提交时清理undo_log的线程池
client.rm.asyncCommitBufferLimit = 10000
client.rm.lock.retryInterval = 10
client.rm.lock.retryTimes = 30
# TM侧配置
client.tm.commitRetryCount = 3
client.tm.rollbackRetryCount = 3
client.tm.defaultGlobalTransactionTimeout = 60000
# undo_log序列化方式(jackson兼容性更好)
client.undo.logSerialization = jackson
client.undo.onlyCareUpdateColumns = true
常见排障场景:
场景1:分支事务注册失败。日志出现”can not connect to services-server”错误。排查Nacos注册中心网络连通性,确认tx-service-group与vgroup-mapping配置一致,Seata Server已注册到对应namespace。
场景2:undo_log序列化异常。日志出现”branch update error”。检查业务表是否包含主键,AT模式依赖主键生成前后镜像。如果表无主键需添加自增ID字段。JSON类型字段需确保序列化器支持(推荐jackson)。
场景3:全局锁竞争。高并发下出现”LockConflictException”。AT模式通过全局锁保证写隔离,同一行数据不能被两个全局事务同时修改。优化方案:缩短事务范围,减少锁持有时间;对非核心操作拆分到事务外执行;必要时改用Saga模式。
生产环境监控通过Seata内置的Metrics模块对接Prometheus:
# seata Server application.yml
seata:
metrics:
enabled: true
registry-type: compact
exporter-list: prometheus
exporter-prometheus-port: 9898
# Prometheus采集配置
- job_name: 'seata'
static_configs:
- targets: ['192.168.1.100:9898']
关键监控指标包括:活跃全局事务数(seata.transaction.active)、分支事务数(seata.branch.active)、回滚率(seata.transaction.rollback.rate)、全局锁等待时间(seata.lock.wait.avg)。回滚率超过5%时需排查业务逻辑或数据竞争问题。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springboot-fen-bu-shi-shi-wu-shi-zhan-seataat-mo-shi-ji/