为什么微服务不要随便用分布式事务
一句话速记
分布式事务的代价是:性能下降(协调开销、锁等待)+ 可用性降低(任一参与者故障则整体阻塞)+ 复杂度激增(幂等、补偿、回滚逻辑)。互联网业务 99% 的场景可以用领域边界拆分(把需要强一致的数据放同一服务)+ 最终一致性 + 业务幂等替代,只有真正必要时(金融核心)才用 TCC。
关键细节
1)分布式事务的真实代价
性能代价:
单机事务(本地):
BEGIN → 业务逻辑 → COMMIT(毫秒级)
2PC 分布式事务:
协调者向 N 个参与者发 Prepare(N 次网络往返)
等待所有回复(等最慢的那个)
协调者发 Commit(N 次网络往返)
总延迟 = 本地事务延迟 × 2 + 2 × N × 网络 RTT
10ms + 2 × 3 × 5ms = 10 + 30 = 40ms(4x 延迟)
TCC 三次业务调用(Try + Confirm + Cancel)
每次都有网络 RTT + 业务处理时间
粗略估算:3 × (业务处理 + 网络RTT) = 延迟 3x
可用性代价:
可用性 = 所有参与者可用性的乘积
假设:每个服务 SLA = 99.9%(3 个九)
2PC 涉及 3 个服务:
0.999 × 0.999 × 0.999 = 0.997 ≈ 99.7%(两个半九)
单月不可用时间:43.2 分钟 → 129.6 分钟(3x 增加)
TCC 同理:涉及服务越多,整体可用性越低
2)何时需要分布式事务(真正的需求)
✅ 真正需要:
金融核心:转账(扣 A 加 B 必须原子,否则钱凭空消失)
库存超卖:下单扣库存 + 创建订单 必须原子(超卖是业务灾难)
⚠️ 可以用最终一致:
订单 + 支付 + 物流(三个系统):允许临时不一致(补偿可恢复)
用户注册 + 积分发放:允许积分延迟几秒到账
消息通知:允许消息延迟
❌ 不需要:
纯读操作(查询不需要事务)
幂等操作(重复执行无副作用)
独立业务(不跨服务的操作)
3)替代方案:领域边界设计
问题根源:微服务拆分过细,导致一个业务操作跨多个服务
解法 1:合并服务(最直接)
如果两个数据必须强一致 → 它们可能属于同一个领域边界
把"订单"和"库存"放同一个服务 → 本地事务解决
解法 2:数据复制 + 最终一致
库存服务 → 发事件到 MQ → 订单服务消费(最终一致)
缺点:有一致性窗口(几十毫秒到几秒)
适合:非强实时场景
解法 3:事件驱动架构(Event-Driven)
操作改为"发布领域事件"
各服务订阅事件,各自处理(幂等)
最终一致,无中心协调者
解法 4:Saga 编排(长流程)
将长事务拆为独立步骤 + 补偿
容忍临时不一致(但最终一致)
4)最终一致性的工程实现
原则:Embrace Eventual Consistency(拥抱最终一致性)
做到最终一致需要:
1. 业务操作幂等(重复执行 = 执行一次)
2. 消息至少一次投递(At-Least-Once)
3. 对账机制(定时扫描不一致,自动修复)
4. 人工介入兜底(极少数无法自动修复的情况)
对账系统(Reconciliation):
定时任务(如每小时):对比 A 服务数据和 B 服务数据
发现不一致 → 发告警 + 自动补偿(如果可以)→ 推人工处理(如果无法自动)
例:支付对账
支付宝每天发送对账文件(全量 / 差异)
商户系统比对:多付 → 退款;少付 → 追收;一致 → 正常
5)CAP 理论的工程解读
CAP:Consistency(一致性)+ Availability(可用性)+ Partition Tolerance(分区容忍)
三者只能同时满足两个
实际互联网系统:网络分区不可避免(P 必须有)
所以选择:
CA(不可能):忽略 P,单机系统才行
CP(一致性 + 分区容忍):牺牲可用性(ZooKeeper 选 CP)
AP(可用性 + 分区容忍):牺牲强一致(Eureka 选 AP,Redis 默认 AP)
BASE 理论(互联网的实用版):
Basically Available(基本可用)
Soft State(软状态,允许临时不一致)
Eventually Consistent(最终一致)
→ 分布式系统工程实践的指导原则
延伸追问
- Q:你在项目中怎么避免分布式事务的? → 首先通过领域建模,把强一致的数据放同一服务(同一 DB,本地事务);其次通过业务梳理,确认哪些场景真的需要强一致(通常比想象少);对于跨服务的场景,用本地消息表 + MQ 保证最终一致,消费端幂等处理重复消息;定时对账任务发现和修复不一致。
- Q:TCC 框架(Seata)用起来容易吗? → Seata AT 模式(自动,侵入性低):不需要写 Try/Confirm/Cancel,框架自动生成 undo log,业务侵入性低,适合无法改造旧代码的场景;TCC 模式:需要自己实现三个方法,侵入性高,但控制粒度更细,性能更好。实际落地需要团队有较强分布式事务经验,otherwise 引入复杂度 > 解决的问题。
- Q:最终一致性下,用户看到”临时不一致”怎么处理(用户体验)? → 产品层面:显示”处理中”状态,给用户预期管理(“积分将在 5 分钟内到账”);技术层面:减少一致性窗口(优化 MQ 消费延迟);补偿层面:用户投诉时有快速修复通道(客服工具)。绝大多数用户不会在 5 秒内刷新页面查看是否一致。
我的记法
- 分布式事务 = 延迟 3~4x + 可用性下降 + 复杂度 × N
- 替代:领域边界收敛(强一致放同一服务)+ 最终一致 + 幂等 + 对账
- CAP 选 AP + BASE 思想 = 互联网标准答案
- 真正需要:金融转账(用 TCC),其他尽量避免
- 一句话:「分布式事务是最后手段,先问能不能用最终一致+幂等替代」
状态
- 已背速记
- 能解释 CAP + BASE
- 能说替代分布式事务的三种设计思路