漫画分布式事务技术选型
🎯 学习目标:掌握架构师核心技能------分布式事务技术选型与一致性解决方案,构建高可靠的分布式系统
🎭 第一章:分布式事务模式对比
🤔 2PC vs 3PC vs TCC vs Saga
想象分布式事务就像不同的团队协作方式...
🎭 分布式事务协作模式:
2PC (二阶段提交):
┌─────────────────────────────────────┐
│ 协调者 (Coordinator) │
│ │ │
│ ┌─────────┼─────────┐ │
│ ▼ ▼ ▼ │
│ 参与者A 参与者B 参与者C │
│ (准备) (准备) (准备) │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ (提交) (提交) (提交) │
│ │
│ 特点: │
│ • 强一致性保证 │
│ • 阻塞性问题 │
│ • 单点故障风险 │
│ • 适用:小规模关键业务 │
└─────────────────────────────────────┘
TCC (Try-Confirm-Cancel):
┌─────────────────────────────────────┐
│ 业务活动管理器 │
│ │ │
│ ┌─────────┼─────────┐ │
│ ▼ ▼ ▼ │
│ 服务A-Try 服务B-Try 服务C-Try │
│ (资源预留) (资源预留) (资源预留) │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ Confirm Confirm Confirm │
│ (确认) (确认) (确认) │
│ │
│ 特点: │
│ • 业务侵入性强 │
│ • 最终一致性 │
│ • 性能较好 │
│ • 适用:业务可拆分场景 │
└─────────────────────────────────────┘
Saga (长事务):
┌─────────────────────────────────────┐
│ Saga编排器 │
│ │ │
│ T1 → T2 → T3 → T4 → T5 │
│ │ │ │ │ │ │
│ C1 ← C2 ← C3 ← C4 ← C5 │
│ (事务) (补偿) │
│ │
│ 特点: │
│ • 长事务友好 │
│ • 业务补偿逻辑 │
│ • 最终一致性 │
│ • 适用:复杂业务流程 │
└─────────────────────────────────────┘
📊 分布式事务技术详细对比
📊 分布式事务技术对比:
┌─────────────┬─────────────┬─────────────┬─────────────┐
│ 特性 │ 2PC │ TCC │ Saga │
├─────────────┼─────────────┼─────────────┼─────────────┤
│ 🔒 一致性 │ 强一致 │ 最终一致 │ 最终一致 │
│ 🚀 性能 │ 低 │ 中 │ 高 │
│ 🔧 复杂度 │ 简单 │ 高 │ 中 │
│ 📊 吞吐量 │ 低 │ 中 │ 高 │
│ 🛡️ 可靠性 │ 中等 │ 高 │ 高 │
│ 💻 业务侵入 │ 小 │ 大 │ 中 │
│ 🌐 适用场景 │ 关键业务 │ 核心交易 │ 复杂流程 │
│ 🎯 推荐度 │ 低 │ 高 │ 高 │
└─────────────┴─────────────┴─────────────┴─────────────┘
技术选型建议:
🎯 银行转账系统 → TCC (资金安全)
🎯 电商下单流程 → Saga (流程复杂)
🎯 库存扣减场景 → TCC (原子操作)
🎯 数据同步任务 → Saga (长时间运行)
🎯 支付系统 → TCC (强一致性要求)
🎯 分布式事务选型决策树
🎯 分布式事务选型流程:
开始选型
│
┌────▼────┐
│一致性要求│
└────┬────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
强一致性 最终一致性 高性能要求
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│关键业务 │ │复杂流程 │ │高并发 │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
▼ ▼ ▼
XA/2PC事务 Saga模式 异步消息
(小规模场景) (长事务场景) (最终一致)
重要业务场景选型:
┌─────────────────┬─────────────┬─────────────┐
│ 业务场景 │ 推荐方案 │ 备选方案 │
├─────────────────┼─────────────┼─────────────┤
│ 银行转账 │ TCC │ XA │
│ 电商下单 │ Saga │ 本地消息表 │
│ 库存扣减 │ TCC │ 分布式锁 │
│ 订单支付 │ TCC │ 2PC │
│ 数据同步 │ Saga │ 消息队列 │
│ 批量处理 │ Saga │ 状态机 │
└─────────────────┴─────────────┴─────────────┘
🛠️ 第二章:Seata分布式事务框架
🏗️ Seata架构与模式
java
// 🛠️ Seata分布式事务实战
/**
* Seata配置中心
*/
@Configuration
@EnableAutoDataSourceProxy
public class SeataConfig {
/**
* AT模式数据源代理
*/
@Bean
@Primary
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
/**
* TCC模式业务资源管理器
*/
@Bean
public TccTransactionManager tccTransactionManager() {
return new TccTransactionManager();
}
/**
* Saga状态机配置
*/
@Bean
public StateMachineEngine stateMachineEngine() {
StateMachineEngineBuilder builder = StateMachineEngineBuilder.newBuilder();
builder.setDataSource(dataSource())
.setTransactionManager(platformTransactionManager())
.setApplicationContext(applicationContext);
return builder.build();
}
}
/**
* AT模式 - 自动补偿
*/
@Service
@Slf4j
public class OrderServiceAT {
@Autowired
private OrderRepository orderRepository;
@Autowired
private AccountServiceClient accountServiceClient;
@Autowired
private ProductServiceClient productServiceClient;
/**
* 创建订单 - AT模式全局事务
*/
@GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
public Order createOrder(CreateOrderRequest request) {
log.info("开始创建订单: userId={}", request.getUserId());
try {
// 1. 创建订单记录
Order order = new Order();
order.setUserId(request.getUserId());
order.setProductId(request.getProductId());
order.setQuantity(request.getQuantity());
order.setAmount(request.getAmount());
order.setStatus(OrderStatus.PENDING);
order.setCreateTime(LocalDateTime.now());
order = orderRepository.save(order);
log.info("订单创建成功: orderId={}", order.getId());
// 2. 扣减账户余额
accountServiceClient.deductBalance(
request.getUserId(),
request.getAmount()
);
log.info("账户扣款成功: userId={}, amount={}",
request.getUserId(), request.getAmount());
// 3. 扣减商品库存
productServiceClient.reduceStock(
request.getProductId(),
request.getQuantity()
);
log.info("库存扣减成功: productId={}, quantity={}",
request.getProductId(), request.getQuantity());
// 4. 更新订单状态
order.setStatus(OrderStatus.SUCCESS);
orderRepository.save(order);
log.info("订单处理完成: orderId={}", order.getId());
return order;
} catch (Exception e) {
log.error("订单创建失败: userId={}", request.getUserId(), e);
throw new OrderException("订单创建失败: " + e.getMessage(), e);
}
}
}
/**
* TCC模式 - 手动补偿
*/
@LocalTCC
@Service
@Slf4j
public class AccountServiceTCC {
@Autowired
private AccountRepository accountRepository;
@Autowired
private AccountFreezeRepository freezeRepository;
/**
* Try阶段 - 冻结资金
*/
@TwoPhaseBusinessAction(
name = "deductBalance",
commitMethod = "confirmDeduct",
rollbackMethod = "cancelDeduct"
)
public boolean deductBalance(
BusinessActionContext context,
@BusinessActionContextParameter("userId") Long userId,
@BusinessActionContextParameter("amount") BigDecimal amount) {
String xid = context.getXid();
log.info("TCC Try阶段 - 冻结资金: xid={}, userId={}, amount={}",
xid, userId, amount);
try {
// 1. 检查账户余额
Account account = accountRepository.findByUserId(userId);
if (account == null) {
throw new AccountException("账户不存在");
}
if (account.getBalance().compareTo(amount) < 0) {
throw new InsufficientBalanceException("余额不足");
}
// 2. 冻结资金
AccountFreeze freeze = new AccountFreeze();
freeze.setXid(xid);
freeze.setUserId(userId);
freeze.setAmount(amount);
freeze.setStatus(FreezeStatus.TRYING);
freeze.setCreateTime(LocalDateTime.now());
freezeRepository.save(freeze);
// 3. 扣减可用余额
account.setBalance(account.getBalance().subtract(amount));
account.setFrozenAmount(account.getFrozenAmount().add(amount));
accountRepository.save(account);
log.info("资金冻结成功: xid={}, userId={}, amount={}",
xid, userId, amount);
return true;
} catch (Exception e) {
log.error("资金冻结失败: xid={}, userId={}, amount={}",
xid, userId, amount, e);
return false;
}
}
/**
* Confirm阶段 - 确认扣款
*/
public boolean confirmDeduct(BusinessActionContext context) {
String xid = context.getXid();
Long userId = (Long) context.getActionContext("userId");
BigDecimal amount = (BigDecimal) context.getActionContext("amount");
log.info("TCC Confirm阶段 - 确认扣款: xid={}, userId={}, amount={}",
xid, userId, amount);
try {
// 1. 查找冻结记录
AccountFreeze freeze = freezeRepository.findByXid(xid);
if (freeze == null) {
log.warn("冻结记录不存在: xid={}", xid);
return true; // 幂等性处理
}
if (freeze.getStatus() == FreezeStatus.CONFIRMED) {
log.warn("重复确认: xid={}", xid);
return true; // 幂等性处理
}
// 2. 确认扣款
freeze.setStatus(FreezeStatus.CONFIRMED);
freeze.setUpdateTime(LocalDateTime.now());
freezeRepository.save(freeze);
// 3. 减少冻结金额
Account account = accountRepository.findByUserId(userId);
account.setFrozenAmount(account.getFrozenAmount().subtract(amount));
accountRepository.save(account);
log.info("扣款确认完成: xid={}, userId={}, amount={}",
xid, userId, amount);
return true;
} catch (Exception e) {
log.error("扣款确认失败: xid={}, userId={}, amount={}",
xid, userId, amount, e);
return false;
}
}
/**
* Cancel阶段 - 取消扣款
*/
public boolean cancelDeduct(BusinessActionContext context) {
String xid = context.getXid();
Long userId = (Long) context.getActionContext("userId");
BigDecimal amount = (BigDecimal) context.getActionContext("amount");
log.info("TCC Cancel阶段 - 取消扣款: xid={}, userId={}, amount={}",
xid, userId, amount);
try {
// 1. 查找冻结记录
AccountFreeze freeze = freezeRepository.findByXid(xid);
if (freeze == null) {
log.warn("冻结记录不存在: xid={}", xid);
return true; // 幂等性处理
}
if (freeze.getStatus() == FreezeStatus.CANCELLED) {
log.warn("重复取消: xid={}", xid);
return true; // 幂等性处理
}
// 2. 取消冻结
freeze.setStatus(FreezeStatus.CANCELLED);
freeze.setUpdateTime(LocalDateTime.now());
freezeRepository.save(freeze);
// 3. 恢复资金
Account account = accountRepository.findByUserId(userId);
account.setBalance(account.getBalance().add(amount));
account.setFrozenAmount(account.getFrozenAmount().subtract(amount));
accountRepository.save(account);
log.info("扣款取消完成: xid={}, userId={}, amount={}",
xid, userId, amount);
return true;
} catch (Exception e) {
log.error("扣款取消失败: xid={}, userId={}, amount={}",
xid, userId, amount, e);
return false;
}
}
}
/**
* Saga模式 - 状态机编排
*/
@Component
@Slf4j
public class OrderSagaService {
@Autowired
private StateMachineEngine stateMachineEngine;
/**
* 执行订单处理Saga
*/
public void processOrderSaga(CreateOrderRequest request) {
log.info("开始执行订单Saga: userId={}", request.getUserId());
try {
// 创建状态机实例
StateMachineInstance instance = stateMachineEngine.startAsync(
"orderProcessSaga",
UUID.randomUUID().toString(),
createSagaContext(request)
);
log.info("订单Saga启动成功: instanceId={}", instance.getId());
} catch (Exception e) {
log.error("订单Saga启动失败: userId={}", request.getUserId(), e);
throw new SagaException("Saga执行失败: " + e.getMessage(), e);
}
}
private Map<String, Object> createSagaContext(CreateOrderRequest request) {
Map<String, Object> context = new HashMap<>();
context.put("userId", request.getUserId());
context.put("productId", request.getProductId());
context.put("quantity", request.getQuantity());
context.put("amount", request.getAmount());
context.put("orderId", null); // 将在状态流转中设置
return context;
}
/**
* Saga状态定义
*/
@SagaOrchestrationStart
public void startOrderProcess(SagaTransactionContext context) {
log.info("Saga开始 - 订单处理: userId={}",
context.getVariable("userId"));
}
@SagaOrchestrationTask("createOrder")
public void createOrder(SagaTransactionContext context) {
log.info("Saga步骤1 - 创建订单");
// 创建订单逻辑
Order order = orderService.createOrderLocal(
(Long) context.getVariable("userId"),
(Long) context.getVariable("productId"),
(Integer) context.getVariable("quantity"),
(BigDecimal) context.getVariable("amount")
);
context.setVariable("orderId", order.getId());
log.info("订单创建成功: orderId={}", order.getId());
}
@SagaOrchestrationTask("deductBalance")
public void deductBalance(SagaTransactionContext context) {
log.info("Saga步骤2 - 扣减余额");
accountService.deductBalanceLocal(
(Long) context.getVariable("userId"),
(BigDecimal) context.getVariable("amount")
);
log.info("余额扣减成功");
}
@SagaOrchestrationTask("reduceStock")
public void reduceStock(SagaTransactionContext context) {
log.info("Saga步骤3 - 扣减库存");
productService.reduceStockLocal(
(Long) context.getVariable("productId"),
(Integer) context.getVariable("quantity")
);
log.info("库存扣减成功");
}
@SagaOrchestrationTask("updateOrderStatus")
public void updateOrderStatus(SagaTransactionContext context) {
log.info("Saga步骤4 - 更新订单状态");
orderService.updateOrderStatusLocal(
(Long) context.getVariable("orderId"),
OrderStatus.SUCCESS
);
log.info("订单状态更新成功");
}
// 补偿方法
@SagaOrchestrationCompensation("createOrder")
public void compensateCreateOrder(SagaTransactionContext context) {
log.info("Saga补偿 - 取消订单");
Long orderId = (Long) context.getVariable("orderId");
if (orderId != null) {
orderService.cancelOrderLocal(orderId);
log.info("订单取消完成: orderId={}", orderId);
}
}
@SagaOrchestrationCompensation("deductBalance")
public void compensateDeductBalance(SagaTransactionContext context) {
log.info("Saga补偿 - 恢复余额");
accountService.refundBalanceLocal(
(Long) context.getVariable("userId"),
(BigDecimal) context.getVariable("amount")
);
log.info("余额恢复完成");
}
@SagaOrchestrationCompensation("reduceStock")
public void compensateReduceStock(SagaTransactionContext context) {
log.info("Saga补偿 - 恢复库存");
productService.restoreStockLocal(
(Long) context.getVariable("productId"),
(Integer) context.getVariable("quantity")
);
log.info("库存恢复完成");
}
}
🎯 面试重点总结
💡 分布式事务架构师面试题
1. 事务模式选择
Q: 什么场景选择TCC?什么场景选择Saga?
A:
- TCC适用场景:资金交易、库存扣减等需要强一致性的核心业务
- Saga适用场景:订单流程、批处理等长事务业务流程
- 选择依据:一致性要求、业务复杂度、性能要求
2. 分布式事务设计
Q: 如何设计一个高可用的分布式事务系统?
A:
- 幂等性设计:防重试、防重复提交
- 补偿机制:业务补偿、技术补偿
- 监控告警:事务状态监控、异常告警
- 容错处理:超时重试、人工介入
3. 性能优化
Q: 分布式事务性能优化策略?
A:
- 异步处理:非关键步骤异步执行
- 批量操作:减少网络开销
- 缓存优化:减少数据库访问
- 分片策略:避免热点数据
🎖️ 分布式事务架构师核心能力
- 方案选型能力:根据业务特点选择合适的事务模式
- 系统设计能力:设计高可用、高性能的事务系统
- 问题诊断能力:快速定位和解决分布式事务问题
- 优化调优能力:持续优化事务系统性能
🔄 分布式事务是分布式系统的核心挑战!掌握技术选型与实现原理,构建高可靠的分布式事务系统!
📌 行动指南
- 点赞 → 让更多Java开发者掌握分布式技术
- 评论 → 留言"分布式技术"领取[分布式系统设计模板]
- 关注 → 追踪更新《更多Java技术精彩内容》(已写完待发布)
- 赞赏 → 解锁完整源码+专属技术咨询
🚀 下期预告
《更多Java技术精彩内容》关注可抢先看
📚 相关推荐:
让我们一起在Java的世界里探索更多精彩内容! 🚀