文章目录
分布式事务是处理跨多个服务或数据库的数据一致性的关键技术。下面我将全面解析分布式事务的应用场景、主流解决方案及其实现原理。
一、分布式事务的应用场景
1.1 必须使用分布式事务的典型场景
场景类型 | 具体案例 | 一致性要求 |
---|---|---|
跨服务转账 | 银行A向银行B转账 | 必须同时成功或失败 |
订单支付 | 创建订单+扣减库存+支付 | 多系统状态必须一致 |
物流跟踪 | 订单状态更新+物流记录创建 | 数据必须同步变更 |
会员积分 | 购物获得积分+等级提升 | 积分与等级需原子更新 |
分布式文件存储 | 文件上传到多个数据中心 | 所有节点需同步成功 |
1.2 判断是否需要分布式事务的标准
- 数据一致性临界点:业务是否允许临时不一致
- 恢复成本:不一致后的修复难度和代价
- 性能影响:事务对系统吞吐量的影响是否可接受
- 系统边界:是否跨越了不同的自治系统
二、分布式事务解决方案全景
2.1 强一致性方案
2.1.1 2PC(两阶段提交)
实现原理:
- 准备阶段:协调者询问所有参与者是否可以提交
- 提交阶段:根据参与者反馈决定提交或回滚
代码示例:
// 伪代码示例
public boolean twoPhaseCommit(List<Participant> participants) {
// 阶段一:准备
boolean allPrepared = participants.stream()
.allMatch(p -> p.prepare());
// 阶段二:提交或回滚
if(allPrepared) {
participants.forEach(p -> p.commit());
return true;
} else {
participants.forEach(p -> p.rollback());
return false;
}
}
优缺点:
- ✅ 强一致性保证
- ❌ 同步阻塞(参与者等待协调者)
- ❌ 单点故障风险
- ❌ 数据锁定时间长
2.1.3 3PC(三阶段提交)
改进点:
- 新增预提交阶段减少阻塞时间
- 引入超时机制解决2PC阻塞问题
阶段流程:
CanCommit → PreCommit → DoCommit
2.2 最终一致性方案
2.2.1 TCC(Try-Confirm-Cancel)
模式:
- Try:预留资源
- Confirm:确认执行业务
- Cancel:取消预留
代码示例:
public class OrderTccService {
@Transactional
public void tryCreateOrder(Order order) {
// 冻结库存而非直接扣减
inventoryService.freeze(order.getItems());
// 创建临时订单
order.setStatus("TRYING");
orderRepository.save(order);
}
@Transactional
public void confirmCreateOrder(Long orderId) {
Order order = orderRepository.findById(orderId);
// 确认正式订单
order.setStatus("CONFIRMED");
// 实际扣减库存
inventoryService.reduce(order.getItems());
}
@Transactional
public void cancelOrder(Long orderId) {
Order order = orderRepository.findById(orderId);
// 取消订单
order.setStatus("CANCELLED");
// 释放冻结库存
inventoryService.unfreeze(order.getItems());
}
}
适用场景:
- 高并发订单系统
- 库存管理系统
- 资金账户系统
2.2.2 Saga模式
实现方式:
- 正向服务:执行业务操作
- 补偿服务:提供逆向操作
示例流程:
订单服务(创建) → 支付服务(扣款) → 库存服务(扣减)
↓ 失败时触发反向操作
订单服务(取消) ← 支付服务(退款) ← 库存服务(回滚)
代码实现:
public class OrderSaga {
public void createOrder(Order order) {
try {
// 1. 创建订单
orderService.create(order);
// 2. 支付
paymentService.charge(order);
// 3. 扣库存
inventoryService.reduce(order.getItems());
} catch (Exception e) {
// 触发补偿流程
compensate(order);
}
}
private void compensate(Order order) {
// 反向执行补偿操作
inventoryService.compensateReduce(order.getItems());
paymentService.refund(order);
orderService.cancel(order);
}
}
2.2.3 本地消息表
实现步骤:
- 业务数据与消息表在同一个本地事务中写入
- 定时任务轮询消息表发送消息
- 消费方处理消息并确认
架构示例:
CREATE TABLE transaction_messages (
id BIGINT PRIMARY KEY,
biz_id VARCHAR(64),
payload TEXT,
status VARCHAR(20),
created_time DATETIME,
retry_count INT
);
@Service
public class OrderService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional
public void createOrder(Order order) {
// 1. 保存订单
orderRepository.save(order);
// 2. 写入消息表(同库事务)
String sql = "INSERT INTO transaction_messages VALUES (?,?,?,?,?,?)";
jdbcTemplate.update(sql,
generateId(),
order.getId(),
JsonUtils.toJson(order),
"PENDING",
new Date(),
0);
}
}
// 独立的消息发送服务
@Scheduled(fixedRate = 5000)
public void processPendingMessages() {
List<Message> messages = jdbcTemplate.query(
"SELECT * FROM transaction_messages WHERE status='PENDING' LIMIT 100",
new MessageRowMapper());
messages.forEach(msg -> {
try {
// 发送到MQ
rocketMQTemplate.send(msg);
// 更新状态
jdbcTemplate.update(
"UPDATE transaction_messages SET status='SENT' WHERE id=?",
msg.getId());
} catch (Exception e) {
// 更新重试次数
jdbcTemplate.update(
"UPDATE transaction_messages SET retry_count=retry_count+1 WHERE id=?",
msg.getId());
}
});
}
2.3 混合方案
2.3.1 Seata框架
支持模式:
- AT(自动TCC)
- TCC
- Saga
- XA
架构组成:
- TC (Transaction Coordinator):事务协调器
- TM (Transaction Manager):事务管理器
- RM (Resource Manager):资源管理器
配置示例:
# application.yml
seata:
enabled: true
application-id: order-service
tx-service-group: my_tx_group
service:
vgroup-mapping:
my_tx_group: default
grouplist:
default: 127.0.0.1:8091
2.3.2 消息队列+本地事务
RocketMQ事务消息流程:
- 发送半消息(对消费者不可见)
- 执行本地事务
- 根据本地事务结果提交或回滚消息
public class OrderProducer {
public void createOrder(Order order) {
// 构建消息
Message msg = new Message(
"ORDER_TOPIC",
"CREATE",
order.getId().toString(),
JsonUtils.toJson(order).getBytes());
// 发送事务消息
TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction(
"order-producer-group",
msg,
order);
// 处理发送结果
if(result.getLocalTransactionState() == LocalTransactionState.COMMIT_MESSAGE) {
log.info("事务提交成功");
} else {
log.error("事务提交失败");
}
}
}
// 事务监听器
@RocketMQTransactionListener
public class OrderTransactionListener implements RocketMQLocalTransactionListener {
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
try {
Order order = (Order) arg;
orderService.save(order);
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e) {
return RocketMQLocalTransactionState.ROLLBACK;
}
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
String orderId = msg.getKeys();
boolean exists = orderService.exists(orderId);
return exists ? RocketMQLocalTransactionState.COMMIT
: RocketMQLocalTransactionState.ROLLBACK;
}
}
三、方案选型指南
3.1 方案对比矩阵
方案 | 一致性 | 性能 | 复杂度 | 适用场景 | 代表实现 |
---|---|---|---|---|---|
2PC | 强一致 | 低 | 中 | 传统银行系统 | XA协议 |
TCC | 最终一致 | 高 | 高 | 电商交易 | Seata |
Saga | 最终一致 | 高 | 高 | 长流程业务 | ServiceComb |
本地消息表 | 最终一致 | 中 | 中 | 异步通知 | 自实现 |
事务消息 | 最终一致 | 高 | 中 | 消息驱动 | RocketMQ |
3.2 选型决策树
是否需要强一致性?
├─ 是 → 考虑2PC/3PC(适合低频关键业务)
└─ 否 → 选择最终一致性方案
├─ 业务可补偿 → TCC/Saga
├─ 异步通知 → 本地消息表
└─ 消息驱动 → 事务消息
3.3 行业实践参考
- 支付系统:TCC模式(蚂蚁金服)
- 电商订单:Saga+消息队列(阿里)
- 物流跟踪:本地消息表(京东)
- 金融交易:2PC(传统银行)
四、实施注意事项
4.1 事务设计原则
- 最小化原则:减少事务范围和持续时间
- 隔离性原则:避免分布式事务中的资源竞争
- 可观测性:完善的日志和监控
- 幂等设计:所有操作必须支持重试
4.2 常见陷阱规避
-
超时处理:设置合理的超时时间
// Seata全局事务超时设置 @GlobalTransactional(timeoutMills = 30000) public void businessMethod() { // ... }
-
空回滚问题:记录Try操作状态
CREATE TABLE tcc_record ( xid VARCHAR(128) PRIMARY KEY, status TINYINT, -- 1:try, 2:confirm, 3:cancel created_time DATETIME );
-
悬挂问题:检查Confirm/Cancel前Try是否完成
-
性能瓶颈:避免热点数据,如:
// 错误做法 - 全局账户表锁 @Transactional public void transfer(Account from, Account to) { // ... } // 正确做法 - 账户分片 @Transactional public void transfer(Long fromId, Long toId) { Account from = accountShardService.getAccount(fromId); Account to = accountShardService.getAccount(toId); // ... }
五、新兴趋势与演进
- Serverless架构:基于事件的分布式事务
- Service Mesh:基础设施层提供事务支持
- 区块链技术:智能合约实现去中心化事务
- Saga模式增强:增加补偿重试策略
# 补偿策略配置示例 compensable: max-retries: 3 backoff: initial-interval: 1000 multiplier: 2
分布式事务的选择和实施需要根据具体业务场景、数据一致性要求和系统架构综合考量。随着云原生技术的发展,分布式事务解决方案也在不断演进,开发者应当持续关注新技术动态,同时掌握经典模式的适用场景和实现原理。