随着业务规模扩大,IMS系统需要调用多个服务完成单一业务逻辑,分布式事务成为必须面对的问题。本文将详细介绍CAP理论、分布式事务模型与在IMS中的实践方案。
为什么需要分布式事务
在微服务架构下,一个业务操作往往涉及多个服务:
- 订单服务创建订单 → 库存服务扣减库存 → 支付服务处理支付
- 任何一个环节失败都可能导致数据不一致
- 传统单机事务无法跨服务生效
CAP 理论
分布式系统最多只能同时满足以下两个特性:
- Consistency(一致性) - 所有节点在同一时刻看到相同的数据
- Availability(可用性) - 每个请求都能在有限时间内得到响应
- Partition tolerance(分区容错) - 系统在网络分区时仍能运行
在网络分区发生时,必须在一致性和可用性之间选择。CP系统保证一致性,AP系统保证可用性。
分布式事务模式
1. 两阶段提交(2PC)
通过协调者管理多个参与者的提交:
2pc-coordinator.java
// 两阶段提交协调者 public class TwoPhaseCoordinator { // 阶段一:预提交 public prepare(List<TransactionParticipant> participants) { for (Participant p : participants) { boolean prepared = p.prepare(); if (!prepared) { // 某个参与者无法准备,回滚所有 rollbackAll(participants); throw new TransactionException("Prepare failed"); } } return true; } // 阶段二:提交 public commit(List<TransactionParticipant> participants) { for (Participant p : participants) { p.commit(); } } }
2. TCC(Try-Confirm-Cancel)模式
将业务逻辑拆分为三个阶段:
tcc-order.java
// 订单服务的 TCC 实现 public class OrderTccService { // Try:预留资源 @Transactional public tryCreateOrder(OrderDTO order) { // 冻结库存(预留资源) inventoryService.freezeStock(order.getItems()); // 预留支付额度 paymentService.reserveAmount(order.getUserId(), order.getTotal()); // 创建待确认订单 return orderDao.insert(order); } // Confirm:确认执行 public confirmCreateOrder(Long orderId) { // 扣减实际库存 inventoryService.deductStock(orderId); // 实际扣款 paymentService.charge(orderId); // 更新订单状态 orderDao.updateStatus(orderId, "CONFIRMED"); } // Cancel:取消回滚 public cancelCreateOrder(Long orderId) { // 释放冻结的库存 inventoryService.unfreezeStock(orderId); // 释放预留额度 paymentService.releaseAmount(orderId); // 更新订单状态 orderDao.updateStatus(orderId, "CANCELLED"); } }
3. Saga 模式
将长事务拆分为多个本地事务,通过补偿机制实现最终一致:
saga-order.java
// Saga 编排器 public class OrderSagaOrchestrator { public execute(OrderDTO order) { // 步骤 1:创建订单 Long orderId = this.createOrder(order); try { // 步骤 2:扣减库存(正向操作) inventoryService.deduct(order.getItems()); // 步骤 3:扣款(正向操作) paymentService.charge(order); // 步骤 4:发货(正向操作) deliveryService.ship(order); } catch (Exception e) { // 补偿:逆向回滚 compensate(orderId, e); throw e; } return orderId; } private void compensate(Long orderId, Exception e) { // 逆向补偿操作 try { deliveryService.cancelShip(orderId); } catch {} try { paymentService.refund(orderId); } catch {} try { inventoryService.restore(orderId); } catch {} try { orderDao.cancel(orderId); } catch {} } }
4. 消息队列最终一致性
使用可靠消息实现事务一致性:
mq-transaction.java
// 可靠消息实现 public class OrderMessageService { @Autowired private RocketMQTemplate mqTemplate; // 发送半消息 public createOrderWithTransaction(OrderDTO order) { // 1. 本地事务:创建订单(状态为"处理中") Long orderId = orderDao.insert(order); // 2. 发送事务消息 mqTemplate.sendMessageInTransaction( "order-topic", MessageBuilder.withPayload(orderId).build(), "order-group" ); return orderId; } // 事务监听器:本地事务与消息发送原子性 public executeLocalTransaction(Message msg, Object arg) { try { // 执行业务逻辑 orderService.processOrder(msg); return LocalTransactionState.COMMIT_MESSAGE; } catch (Exception e) { return LocalTransactionState.ROLLBACK_MESSAGE; } } }
模式选择建议
| 场景 | 推荐模式 |
| 强一致性要求 | 2PC、Seata AT |
| 性能要求高 | TCC、消息队列 |
| 业务流程长 | Saga |
| 简单同步调用 | 可靠消息 |
IMS系统实践
在IMS系统中,我们采用以下策略:
- 订单模块 - 使用 TCC 模式,确保库存、支付、订单一致性
- 财务报表 - 使用 Saga 模式,长流程可拆分补偿
- 消息通知 - 使用可靠消息,确保通知不丢失
总结
分布式事务没有银弹,需要根据业务场景选择合适的模式。IMS系统通过组合使用多种模式,在保证数据一致性的同时,最大化系统性能和可用性。