Appearance
分布式事务
很多人第一次接触分布式事务时,最常见的困惑是:数据库事务不是已经能保证一致性了吗?
问题在于,数据库事务通常更擅长处理:单个数据库、单个事务边界里的操作一致性。
一旦操作跨了多个服务、多个库、多个资源,问题就不再是普通本地事务了。
这篇文章重点讲:
- 分布式事务到底是什么
- 它为什么会出现
- 常见方案在解决什么问题
- 它们分别适合什么场景
- 为什么很多企业问题最后不是“强上事务”,而是重构流程
1. 分布式事务到底是什么
可以这样理解:一笔业务操作需要跨多个服务、多个库或多个资源一起完成时,如何尽量保证整体状态正确。
例如下单场景可能同时涉及:
- 订单服务写订单
- 库存服务扣库存
- 支付服务记录支付
这时如果只靠单库本地事务,就很难保证这几步天然一起成功或一起失败。
2. 为什么本地事务不够了
在单库里,一条事务边界能包住多条 SQL。
但在分布式系统里,常见情况是:
- 不同服务有自己的数据库
- 不同服务独立部署、独立提交
- 调用之间会有网络失败、超时和重试
所以问题就变成:一个服务提交成功了,另一个服务失败了,系统怎么收场。
这就是分布式事务问题的核心。
3. 一个最直观的例子
假设用户下单:
- 订单服务创建订单成功
- 库存服务扣库存失败
这时系统就会出现:
- 订单状态已经生成
- 库存却没扣成功
或者反过来:
- 库存扣了
- 订单却没创建成功
这两种情况都说明:业务整体没有保持一致。
4. 分布式事务为什么会很难
它难就难在你同时要面对:
- 跨服务调用
- 跨数据库提交
- 网络不可靠
- 服务会超时、会重试、会失败
所以它不是“事务范围更大一点”这么简单,而是:原本由单机数据库内核兜住的事情,现在要靠多个独立系统协同完成。
5. 常见分布式事务思路有哪些
企业里常见的思路通常包括:
- 强一致型协议
- 最终一致性方案
- 补偿型事务
5.1 2PC
2PC 是两阶段提交。
它的核心思路是:
- 先问所有参与方能不能提交
- 都能提交时再统一提交
它更偏强一致,但代价通常较高:
- 阻塞明显
- 协调者压力大
- 故障恢复复杂
5.2 TCC
TCC 通常分为:
TryConfirmCancel
它的核心思路是:先预留资源,再确认提交,失败时执行补偿取消。
它更适合对业务流程有明确控制能力的场景。
5.3 可靠消息最终一致性
它的核心思路是:本地事务先保证本地状态正确,再通过消息把变更可靠地传播给其他服务。
这类方案在企业里非常常见,因为它更现实,也更符合高可用系统习惯。
6. 为什么很多系统更偏向最终一致,而不是强一致
因为强一致的代价通常很高:
- 性能差
- 可用性差
- 阻塞明显
- 系统复杂度高
很多互联网业务最终会更倾向:接受短暂不一致,但保证最终收敛。
例如:
- 订单创建后积分稍后到账
- 库存变更通过消息异步同步
- 支付结果稍后驱动订单状态更新
7. TCC 到底适合什么场景
TCC 更适合:
- 业务动作清晰可拆
- 每一步都能设计 Try / Confirm / Cancel
- 资金、库存、额度这类强业务约束场景
例如扣库存时:
Try:先冻结库存Confirm:真正扣减Cancel:释放冻结
它的优点是:业务可控性强。
它的代价是:业务侵入性大,开发复杂度高。
8. 可靠消息最终一致性为什么常见
因为很多业务并不要求每一步都在同一时刻绝对一致。
更常见的做法是:
- 本地事务先提交核心数据
- 再把后续动作通过消息可靠投递出去
- 消费方异步处理并重试
例如:
- 订单服务本地事务提交订单
- 发送“订单已创建”消息
- 库存服务消费消息并扣库存
这样做的关键价值是:把大事务拆成可恢复、可重试、可补偿的异步流程。
9. 分布式事务里为什么幂等很重要
因为在分布式环境里,重试几乎不可避免。
一旦发生:
- 网络超时
- 消息重复投递
- 调用方重复重试
就很容易导致同一个动作被执行多次。
所以分布式事务要想真正落地,通常都要配合:幂等设计。
也就是说:同一个请求重复执行,结果不应不断累加出错。
10. 代码层面最常见的设计习惯
虽然分布式事务本身不是靠几行注解解决的,但代码层面有几个习惯非常重要:
- 先明确业务主动作和补偿动作
- 给操作设计唯一业务单号
- 对消息消费和回调处理做好幂等
- 把长链路拆成可重试、可恢复的小步骤
例如消费端幂等处理会很常见:
java
public void onOrderCreated(OrderCreatedEvent event) {
if (processed(event.getOrderId())) {
return;
}
deductStock(event.getProductId(), event.getCount());
markProcessed(event.getOrderId());
}11. 企业里什么时候不该硬上分布式事务
这是非常关键的一点。
很多问题如果一开始就试图用“大而全的分布式事务框架”兜住,往往会把系统拖得更复杂。
更好的问题应该是:
- 这个流程是否能拆成主流程和异步流程
- 哪一步必须强一致,哪一步可以最终一致
- 是否能通过补偿和幂等降低耦合
很多时候,真正有效的做法不是“找最强事务方案”,而是:重新设计业务边界。
12. 工程上最容易混的几个边界
12.1 误区一:分布式事务就是把本地事务范围放大
不是。
跨服务后,问题的本质已经变成协调、补偿和恢复。
12.2 误区二:2PC 一定最正确,所以最好
它理论上更强,但代价在很多业务里无法接受。
12.3 误区三:最终一致就是可以不管失败
不是。
最终一致要求的是:有明确的补偿、重试、幂等和状态收敛机制。
13. 一句话总结
分布式事务这条线,本质上是在解决跨服务、跨资源的一致性问题;而企业里真正重要的,不是迷信某个事务模式,而是判断哪些地方必须强一致、哪些地方可以最终一致,并把补偿、幂等和恢复机制一起设计好。