分布式事务理论基础及常见解决方案
在构建分布式系统时,事务一致性始终是最棘手的问题之一。为什么我们不能像传统单体应用一样,轻松实现 ACID?为什么很多系统会出现短暂不一致?要回答这些问题,我们必须先回到两个核心理论 —— CAP 理论 和 BASE 理论。
一、CAP 理论
CAP 是指:
-
C:Consistency(一致性)
-
A:Availability(可用性)
-
P:Partition Tolerance(分区容忍性)
1.1CAP 理论的含义:
CAP 理论由 Eric Brewer 在 2000 年提出,并由 Seth Gilbert 和 Nancy Lynch 在 2002 年形式化证明。
CAP 理论核心结论: 在一个分布式系统中,最多只能同时满足其中的两个,无法三者兼得。
1.2 三个属性的解释:
属性 | 说明 |
---|---|
一致性(C) | 所有节点访问同一份最新的数据副本。举个例子:你在上海写入了数据,北京读也必须马上看到这个数据。 |
可用性(A) | 系统始终能返回非错误响应(不保证是最新的)。即系统“活着”,哪怕返回的是旧数据。 |
分区容忍性(P) | 系统在发生网络分区(如节点之间通信中断)时,仍能继续运作。 |
CAP 示例说明:
系统设计 | 舍弃哪一个? | 说明 |
---|---|---|
CP 系统 | 舍弃可用性 | 比如 Zookeeper,为保证强一致性,部分节点挂掉后拒绝服务 |
AP 系统 | 舍弃一致性 | 比如 DNS 或某些 NoSQL(如 Couchbase),返回旧数据也可以,系统仍可用 |
CA 系统 | 舍弃分区容忍性 | 理论上不可实现,一旦发生分区,CA 就无法同时成立 |
二、BASE 理论:牺牲强一致性,换取高可用
CAP 理论之后,互联网企业发现必须在一致性和可用性之间作出平衡。这催生了更灵活的 BASE 理论。
2.1 BASE 是什么?
BASE 是三个概念的组合:
-
Basically Available(基本可用):系统在部分节点出问题时,仍可提供核心功能。
-
Soft State(柔性状态):数据状态可以在一段时间内不一致。
-
Eventually Consistent(最终一致性):系统经过一段时间后,最终会达到一致状态。
2.2 BASE 理论 vs ACID 特性
特性 | ACID(传统数据库) | BASE(分布式系统) |
---|---|---|
一致性 | 强一致 | 最终一致 |
可用性 | 低(事务失败即中止) | 高(允许短时不一致) |
容错性 | 弱 | 强 |
应用场景 | 银行转账、强事务系统 | 电商订单、社交网络 |
BASE 理论强调的是:不强求实时一致,但最终要一致,过程可不一致。
三、常见解决方案
3.1 两大核心模型
类别 | 模型 | 简述 |
---|---|---|
强一致性 | 2PC / XA | 保证所有节点要么一起成功,要么一起失败(同步阻塞) |
最终一致性 | 本地消息表、可靠消息、TCC、SAGA | 允许中间短暂不一致,最终一致(异步补偿) |
3.2、常见实现方案
3.2.1 XA 分布式事务(两阶段提交协议)
-
标准: X/Open XA 协议
-
步骤:
-
prepare
阶段:所有资源预提交,锁住资源; -
commit
阶段:协调者通知提交或回滚。
-
-
支持: MySQL、Oracle、PostgreSQL + Atomikos、Narayana、Bitronix
示例:
Client (应用)|| Start global transaction|
Transaction Coordinator||--> [Prepare] --> 数据库A:执行本地操作 → 写入undo log → 锁定数据 → 返回YES||--> [Prepare] --> 数据库B:执行本地操作 → 写入undo log → 锁定数据 → 返回YES/NO
如果所有参与者都返回 YES,则进入第二阶段 commit
;有任何一个返回 NO,则 rollback
。
优点:强一致性,有标准协议
缺点:性能差、容易阻塞、资源锁定严重、不适合高并发系统
3.2.2 TCC(Try-Confirm-Cancel)
-
每个参与者都需实现三步:
-
Try
:预留资源 -
Confirm
:确认提交 -
Cancel
:撤销操作
-
示例(转账):
Try:冻结账户金额
Confirm:扣款并转账
Cancel:解冻账户
优点:可控性强,支持业务补偿
缺点:实现成本高,需要每个参与方支持三步操作
3.23 SAGA 模型(长事务拆分为局部事务 + 补偿)
-
将长事务拆成多个子事务,按顺序执行
-
若失败,则按相反顺序执行补偿(Undo)
示例(订单流程):
T1:创建订单
T2:扣库存
T3:扣余额
→ 若 T3 失败,执行:C3:退余额
C2:加库存
C1:取消订单
优点:事务粒度小,适合长流程
缺点:需要写补偿逻辑,最终一致性非强一致框架:Apache ServiceComb Pack、Seata Saga 模式
3.2.4 本地消息表 + 轮询(事务消息)
-
在本地数据库记录消息日志(和业务操作放在一个事务中)
-
后台线程异步扫描并发送 MQ 消息
-
消费端处理完成后回调确认
示例:
插入订单记录 + 插入消息日志(一个事务)
轮询线程异步发消息到 MQ(如 RabbitMQ、RocketMQ)
优点:实现简单、可靠性高
缺点:开发麻烦,依赖轮询,实时性差
5. 可靠消息服务(事务消息队列)
-
使用支持事务消息的 MQ(如 RocketMQ、RabbitMQ + outbox pattern)
-
消息发送成功后,消费者处理并确认
RocketMQ 示例(半消息):
发送“准备状态”消息(消息暂不投递)
本地业务执行成功
提交消息,才会正式投递
优点:可靠、高性能
缺点:依赖 MQ,MQ 挂了就影响事务
3.3 怎么取舍
-
需求驱动设计:
-
金融、交易类业务 → 选择强一致性(CAP 中偏 CP,牺牲可用性)
-
电商、内容系统 → 选择最终一致性(CAP 中偏 AP,牺牲强一致性)
-
-
读写比分析:
-
如果读远多于写,可以采用多副本延迟一致性,提高可用性。
-
-
系统容错机制:
-
借助消息队列、补偿机制等设计,构建“柔性事务”,提升系统韧性。
-