分布式事务: 主流最终一致性方案对比

张开发
2026/6/6 2:11:40 15 分钟阅读
分布式事务: 主流最终一致性方案对比
分布式事务的最终一致性方案旨在确保在分布式系统中所有参与方最终将达到一致的状态尽管在过程中可能存在短暂的不一致。这种模型在保证系统可用性和分区容错性的同时牺牲了强一致性的实时性要求。以下是几种主流的最终一致性方案的汇总与详解。主流最终一致性方案对比方案一致性模型性能实现复杂度典型适用场景核心思想TCC最终一致高高金融、电商核心业务如扣减库存业务侵入补偿型事务分为Try、Confirm、Cancel三个阶段。Saga最终一致高高长流程、跨服务业务编排将长事务拆分为一系列本地事务通过正向执行和反向补偿来保证最终一致。本地消息表最终一致中中异步通知、对账场景利用数据库本地事务将消息生产和业务操作绑定通过异步轮询重试保证下游消费。可靠消息基于MQ最终一致高低高并发、最终一致场景如状态同步借助消息队列的持久化、重试和确认机制确保消息至少被成功消费一次。方案详解与示例1. TCC (Try-Confirm-Cancel)TCC是一种业务侵入性较强的补偿型事务要求每个服务提供三个接口Try预留资源、Confirm确认提交、Cancel取消释放。核心原理在Try阶段锁定或预留必要资源所有参与者Try成功后在Confirm阶段提交若任一Try失败则在Cancel阶段执行补偿操作释放预留资源。适用场景适用于对一致性要求较高且能容忍短暂资源锁定的核心业务如电商下单时的库存扣减和优惠券核销。代码示例库存服务伪代码// 库存服务接口定义 public interface InventoryService { // Try: 预扣库存 boolean tryDeduct(Long productId, Integer quantity); // Confirm: 确认扣减 boolean confirmDeduct(Long productId, Integer quantity); // Cancel: 取消预扣回退库存 boolean cancelDeduct(Long productId, Integer quantity); } // 实现示例 Service public class InventoryServiceImpl implements InventoryService { Override Transactional public boolean tryDeduct(Long productId, Integer quantity) { // 检查并预扣库存如将可用库存转入冻结库存 int rows inventoryMapper.freezeStock(productId, quantity); return rows 0; } Override Transactional public boolean confirmDeduct(Long productId, Integer quantity) { // 确认扣减清除冻结记录 return inventoryMapper.confirmFreeze(productId, quantity) 0; } Override Transactional public boolean cancelDeduct(Long productId, Integer quantity) { // 取消预扣将冻结库存加回可用库存 return inventoryMapper.unfreezeStock(productId, quantity) 0; } }2. SagaSaga模式将一个分布式事务拆分为一系列连续的本地事务。每个本地事务都有对应的补偿事务。执行流程中如果某个本地事务失败则会按相反顺序触发前面所有已成功事务的补偿操作。适用场景适用于业务流程长、步骤多、跨多个服务的场景如机票酒店预订流程。实现模式编排式由一个中心协调器来触发并监听各个服务。协同式每个服务完成后触发下一个服务并知晓自己的补偿操作。3. 本地消息表该方案利用数据库的本地事务原子性将消息生产和业务操作放在同一个事务中。核心流程业务服务在完成本地数据库操作的同时向同一数据库的“消息表”插入一条待发送的消息记录。有一个独立的“消息发送者”定时轮询消息表将未发送的消息投递到消息队列。下游消费者从MQ消费消息处理业务处理成功后调用回调接口或发送确认消息。消息发送者收到确认后将消息状态更新为“已发送”或删除。代码示例订单创建与消息存储-- 在同一事务中执行订单创建和消息记录插入 START TRANSACTION; -- 1. 创建订单 INSERT INTO order (order_id, user_id, amount, status) VALUES (O001, 1001, 299.00, CREATED); -- 2. 在本地消息表中记录待发送的“扣减库存”事件 INSERT INTO outbox_message (message_id, topic, payload, status, created_time) VALUES (UUID(), inventory.deduct, {orderId:O001,productId:P1001,quantity:1}, PENDING, NOW()); COMMIT;4. 可靠消息基于消息队列此方案高度依赖消息队列如RocketMQ、Kafka的事务消息或类似机制来保证可靠性。核心流程以RocketMQ事务消息为例发送半消息生产者向MQ发送一个“半消息”对消费者不可见。执行本地事务生产者执行本地业务逻辑如创建订单。提交或回滚根据本地事务执行结果向MQ发送Commit或Rollback指令。Commit半消息变为正式消息可供消费者消费。Rollback消息被丢弃。消费与重试消费者消费消息并处理业务。如果消费失败MQ会按重试策略重新投递直到成功或进入死信队列。配置示例RocketMQ生产者// 创建事务监听器用于执行本地事务和检查本地事务状态 TransactionListener transactionListener new TransactionListenerImpl(); TransactionMQProducer producer new TransactionMQProducer(please_rename_unique_group_name); producer.setNamesrvAddr(localhost:9876); producer.setTransactionListener(transactionListener); producer.start(); // 发送事务消息 Message msg new Message(OrderTopic, TagA, OrderID001, Hello world.getBytes(RemotingHelper.DEFAULT_CHARSET)); SendResult sendResult producer.sendMessageInTransaction(msg, null); // 第二个参数可用于传递业务参数方案选型建议高并发与业务复杂优先考虑TCC因其性能好且业务控制粒度细。简单业务允许延迟使用本地消息表实现相对简单对中间件依赖小。长流程、跨系统编排Saga模式更为合适适合流程化的业务场景。已深度依赖消息队列直接采用可靠消息方案充分利用MQ的成熟能力实现最终一致。在实际架构中常组合使用多种方案。例如一个电商下单系统可能创建订单使用本地事务扣减库存采用TCC或预扣库存优惠券核销采用预冻结最终扣减而支付成功后的状态同步则通过消息队列保证最终一致性。系统必须设计完善的补偿机制如订单超时未支付时触发库存回退和优惠券释放并配合重试、告警等异常处理策略。参考来源分布式事务一致性方案介绍_分布式事务处理多喝保证库存、订单、优惠券核销原子性-CSDN博客分布式事务里的最终一致性分布式事务处理与一致性保障方案详解

更多文章