sql分布式事务无法靠单库ACID保证全局一致性,须采用最终一致性方案,包括本地消息表、Saga模式、对账修复及严格设计原则。

SQL分布式事务无法靠单库ACID直接保证全局一致性,必须借助最终一致性方案来平衡可用性与数据正确性。核心思路是放弃强一致,接受短暂不一致,通过异步补偿、状态追踪和重试机制,让系统在有限时间内自动收敛到一致状态。
基于本地消息表的可靠事件传递
这是最常用也最易落地的最终一致性方案。关键是在业务数据库中建一张“消息表”,所有需要跨服务通知的操作,先在本地事务中写业务数据+写消息记录,再由独立的消息投递服务异步读取并发送到MQ(如kafka、rocketmq)。
- 消息表需包含唯一业务ID、消息内容、状态(待发送/已发送/失败)、重试次数、创建时间等字段
- 投递服务采用“定时轮询 + 指数退避重试”,避免高频刷库;状态更新必须用UPDATE WHERE status=’待发送’ AND id=xxx,防止重复投递
- 下游服务消费消息后,需幂等处理(例如用业务ID做去重或乐观锁校验版本号)
使用Saga模式协调长事务
Saga把一个分布式事务拆成多个本地事务,每个步骤都有对应的补偿操作。正向流程依次执行,任一环节失败则按反向顺序调用补偿事务回滚已提交的动作。
- Choreography(编排式):各服务监听事件自主触发下一步,无中心协调者,适合松耦合场景
- Orchestration(指挥式):由专门的Saga协调器控制流程,记录执行状态到数据库,便于监控与人工干预
- 注意补偿操作必须是幂等且可重入的,比如“冻结余额”对应“解冻余额”,而不是“减余额”对应“加余额”
对账与自动修复作为兜底手段
再严谨的异步机制也无法100%规避失败,因此必须设计离线对账系统,定期比对核心业务表(如订单、支付、库存)之间的关键字段,识别不一致数据并触发自动修复或告警人工介入。
- 对账任务建议按业务维度分片(如按日期、商户ID),支持断点续跑和并发控制
- 修复逻辑应封装为可验证的脚本或服务,修复前先生成差异报告,修复后二次校验结果
- 对账周期根据业务容忍度设定,金融类建议T+0实时对账,电商类可接受T+1日批处理
关键设计原则与避坑提醒
最终一致性不是“随便一致”,而是有约束、可预期、可验证的一致性。实施时要守住几条底线:
- 所有异步动作必须有明确的状态标识,禁止“发完即忘”;状态变更优先用数据库UPDATE,而非内存标记
- 跨库更新不能依赖应用层顺序执行,必须通过消息或状态机驱动,防止网络分区导致执行错乱
- 超时、重复、丢失这三类问题必须在设计阶段就覆盖,比如用全局唯一请求ID防重,用TTL机制清理过期消息
- 不要试图在SQL层用XA或2PC解决跨库事务——它会严重拖垮性能,且在微服务架构下运维成本极高
最终一致性不是妥协,而是面向分布式现实的务实选择。重点不在“立刻一致”,而在“一定一致”和“可知不一致”。