分库分表后分布式事务的最终一致性方案

阿乐
阿乐 管理员 黑卡会员
发布于 2026-09-06 16:59 ·8 浏览 ·0 回复

从 ACID 到 BASE:别再幻想“一次扣款”了

很多同学第一次接触分库分表后的分布式事务,心里都憋着一股劲:能不能像单库那样,有一个全局事务管理器,要么全成功,要么全回滚?可惜,现实世界没有这种银弹。当业务量上来,被迫把订单库、支付库、库存库拆开之后,原本“本地事务+数据库回滚”的强一致性美梦就该醒了。

分布式系统的核心铁律是:网络可能分区,通信可能失败,调用可能超时。当一次业务操作横跨多个数据库节点,如果强行追求同步的强一致性,结果通常是两败俱伤——要么系统可用性被拖垮,要么在极端故障下出现更复杂的“脑裂”。

所以,业界普遍的做法是拥抱 BASE 理论,接受“最终一致性”。先保证主链路快速响应,把状态差异用异步的方式慢慢抹平。这就像现实中的电商售后:你提交退款申请,页面立刻显示“受理成功”,但钱到账可能要等 1-3 个工作日。用户接受这种“延迟”,系统也换来了可用性。

主流的三大派系方案解析

先泼一盆冷水:没有完美的方案,只有最匹配业务场景的取舍。目前工程上最常见的最终一致性方案,不外乎以下三种:

1. 本地消息表:最朴素也最可靠的“土办法”

这个方案的核心思想是“大事化小,小事异步”。在发起方本地事务里,额外写一张业务表和一张消息表,两条记录在同一个本地数据库事务里提交。随后通过一个定时任务或后台线程,扫描这张消息表,把未发送的消息投递到 MQ,或者直接调用下游接口。

它的优点是极度僵硬可靠,不依赖 MQ 的高可用(即使 MQ 挂了,消息还在库里)。缺点是:对业务表有侵入,每次都要多写一张表,而且消费端要做幂等,防止重复执行。很多老牌支付公司至今仍保留这种模式,稳如老狗。

2. 事务消息(半消息):RocketMQ 的看家本领

这算是本地消息表的“优雅升级版”。它的流程是这样的:生产者先发送一条“半消息”(Broker 暂存,不投递),然后执行业务代码。业务成功,就提交 Confirm;业务回滚,就发送 Rollback,Broker 删除半消息。

如果业务执行到一半宕机了,生产者没来得及发 Confirm 或 Rollback,Broker 会反向回查生产者的本地事务状态,强制业务方给个准话。这就解决了本地消息表方案中“如果没有额外做分布式锁,消息可能先于事务提交而提前被投递”的弊端。RocketMQ 的这套实现,是把最终的确定权硬生生从“异步扫描”变成了“同步回查”,更加实时和优雅。

3. Sage 模式:长事务的拆解艺术

如果你的业务流程像一套组合拳——先扣库存,再减余额,最后通知物流——而且每一步都特别耗时,上面两种异步消息方案就有点束手束脚了。这时需要底层的 Saga 模式。

Saga 的核心是把一个大的全局事务,拆分成一串本地子事务序列,并为每一步都定义好“补偿操作”。比如扣库存成功,但余额失败,就触发扣库存的“补偿动作”——把库存加回来。

Sage 的落地通常有两种方式:协同式(每一步结束后,通过事件触发下一步)和编排式(临时建一个中央协调器)。鉴于分布式环境下代码的可维护性,我强推编排式。用状态机在协调器里定义好流程顺序、分支和补偿策略,这样所有流程推进都有据可查,比散落各地的 MQ Topic 要好排查得多。

避坑指南:没有“万能配方”,只有“对症下药”

在选用这些最终一致性方案时,请务必警惕以下几个高频翻车点:

第一,兜底轮询绝不能省。 无论你用经典消息表还是事务消息,无论消息中间件吹嘘自己的送达可靠性有多高,代码里都必须存在一个定时巡检任务。比如,消费端接收到消息后,执行对账逻辑;如果发现业务已完成但消息仍堆积,主动触发补单。绝对不要指望“发一次消息,天下太平”。

第二,幂等性是最终一致性的基石。 因为天然存在网络重发、消费者重启等,同一事件很可能被下游重复消费。所以,每个下游服务的处理接口,必须基于“交易流水号”或“唯一事件 ID”建立去重表,使用数据库唯一约束来截断重复流量。

第三,系统边界要对齐“最终”的时间窗口。 最终一致性不等于“无限期不一致”。对于资金、电商这类高敏感业务,通常会对“不一致”的时长设硬性 SLO(如:支付记录状态延迟不得超过 5 分钟)。一旦异常堆积超过阈值,必须告警、熔断并人工介入,防止“数据腐烂”。

别再执念 100% 的即时同步

最终一致性方案的价值,在于它精准地拿捏了微服务化后的“生存成本”。当系统大到必须分库分表,就已经没有退路可言了。凡事皆可牺牲,唯有“可用性”和“数据不丢”不能妥协。

在做技术选型时,回归业务本质:**如果业务流程像签名一样简单,用事务消息;如果涉及多步跨系统编排且需动态调剂,用状态机 Saga。** 谈原则千万条,唯一重要的那条是:千万别在设计分布式事务时,抱着“单库事务”的思维定式去追求宇宙大同。接受异步,才是在分布式世界里最高的成熟。

全部回复 0

还没有回复,来抢沙发~