第一次接触分布式系统时,最让我头疼的就是数据一致性问题。单机环境下用个@Transactional注解就能搞定的事务,在微服务架构中突然变成了棘手的分布式事务难题。记得去年我们电商系统拆分微服务后,就遇到过用户支付成功但订单状态未更新的生产事故,这就是典型的分布式事务问题。
分布式事务本质上是解决跨服务、跨数据库的数据操作一致性问题。当订单服务扣减库存、账户服务扣款、物流服务创建运单这三个操作需要作为一个整体执行时,传统的本地事务就无能为力了。这就像银行转账,A账户扣款和B账户入账必须同时成功或失败,任何单边操作都会导致数据不一致。
目前主流的分布式事务解决方案有:
Seata(Simple Extensible Autonomous Transaction Architecture)是阿里开源的分布式事务解决方案。它的AT模式对业务代码零侵入,通过代理数据源的方式自动生成回滚日志,特别适合快速落地分布式事务的场景。
Seata包含三个核心组件:
部署架构上,TC需要独立部署,而TM和RM以jar包形式嵌入应用。这种设计既保证了协调器的稳定性,又让客户端保持轻量。我们生产环境用3台机器部署TC集群,通过Nginx做负载均衡,可以支撑日均百万级分布式事务。
AT模式的核心魔法在于它对SQL的解析和回滚日志的自动生成。当开启分布式事务后,Seata会:
以更新订单状态为例:
sql复制UPDATE order SET status = 'paid' WHERE id = 1001
Seata会先查询出id=1001的订单当前状态(before image),执行更新后再记录新状态(after image)。如果事务需要回滚,Seata就能根据undo_log自动生成补偿SQL:
sql复制UPDATE order SET status = 'unpaid' WHERE id = 1001
这种机制相比TCC模式的最大优势是业务无需编写补偿逻辑。我们迁移到Seata后,分布式事务相关代码量减少了70%,开发效率显著提升。
推荐使用1.5.0+版本,新版本在性能和稳定性上有显著提升。配置文件重点参数:
properties复制# registry.conf
registry {
type = "nacos"
nacos {
serverAddr = "127.0.0.1:8848"
namespace = ""
cluster = "default"
}
}
# file.conf
store {
mode = "db"
db {
datasource = "druid"
dbType = "mysql"
url = "jdbc:mysql://127.0.0.1:3306/seata"
user = "root"
password = "123456"
}
}
注意:生产环境务必配置高可用模式,推荐使用DB存储模式而非file模式
Spring Boot项目只需添加依赖:
xml复制<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.5.0</version>
</dependency>
配置数据源代理:
yaml复制seata:
enabled: true
application-id: order-service
tx-service-group: my_tx_group
service:
vgroup-mapping:
my_tx_group: default
在事务发起方法上添加@GlobalTransactional:
java复制@GlobalTransactional(timeoutMills = 60000, name = "createOrder")
public void createOrder(OrderDTO orderDTO) {
// 1. 扣减库存
storageFeignClient.deduct(orderDTO.getCommodityCode(), orderDTO.getCount());
// 2. 创建订单
orderMapper.insert(orderDTO);
// 3. 扣减余额
accountFeignClient.debit(orderDTO.getUserId(), orderDTO.getMoney());
}
我们曾遇到事务超时导致全局回滚,但部分分支事务已提交的情况。解决方案:
默认连接池参数可能导致死锁,建议调整:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
网络抖动可能导致TC重复发起回滚,业务需要做好幂等处理。我们在关键表添加了事务状态字段:
sql复制ALTER TABLE order ADD COLUMN tx_status VARCHAR(10);
通过以下优化,我们将分布式事务耗时从平均800ms降到300ms以内:
监控指标建议重点关注:
| 特性 | AT模式 | TCC模式 | SAGA模式 |
|---|---|---|---|
| 侵入性 | 无 | 高 | 中 |
| 性能 | 高 | 中 | 低 |
| 一致性 | 弱一致 | 强一致 | 最终一致 |
| 适用场景 | 短事务 | 资金交易 | 长流程业务 |
对于90%的电商业务场景,AT模式都能很好满足需求。但对于账务等强一致性要求的场景,建议采用TCC模式。我们系统目前采用AT+TCC混合方案,用AT处理订单、库存等业务,用TCC处理账户余额变更。