当前位置:首页 > 问答 > 正文

深入聊聊分布式系统里那些绕不开的事务问题和常见模型怎么解决的

说到分布式系统,你可以想象一下,本来一个超市里所有收银和库存管理都是一台超级电脑管的,现在为了应对更大的客流量,你开了好几家分店,每家分店都有自己的收银台和仓库,这就是分布式系统的感觉:活儿分给不同的机器(节点)去干,效率更高,也更不容易因为一台机器坏掉而全盘崩溃。

但问题马上就来了,一个顾客在A分店的网上下单,买了B分店仓库里最后一件货,这个简单的操作,在分布式系统里就变成了两个动作:一是在A分店的销售系统里“创建订单”,二是在B分店的库存系统里“扣减一件库存”,麻烦在于,这两个动作必须作为一个整体来看待:要么都成功,要么都失败,如果订单创建成功了,但库存没扣减,那就会超卖;如果库存扣减了,但订单没创建成功,那这件货就“神秘消失”了,这就是分布式系统里最核心、最绕不开的问题之一:事务问题,也就是如何保证跨多个独立节点的操作依然能保持“原子性”(Atomicity)、“一致性”(Consistency)、“隔离性”(Isolation)和“持久性”(Durability),合称ACID特性。

为了解决这个问题,工程师们想出了很多模型,我们来聊聊几个最常见的。

两阶段提交(2PC)—— 像一场谨慎的集体表决

这是最经典、最直观的模型,它的过程就像一场需要全体同意的投票。

  • 第一阶段:准备阶段,事务协调者(可以理解为项目经理)问所有参与节点(A分店销售、B分店库存):“我准备执行这个操作,你们那边条件都允许吗?能保证一定能成功吗?”每个节点检查自己的情况(比如库存够不够),如果没问题,就把操作所需的信息锁定(比如先把这件货预占住,不让别人买),然后回复“我准备好了”(Yes),如果任何一个节点回复“不行”(No),或者超时没响应,就说明有节点无法完成。
  • 第二阶段:提交阶段,如果协调者收到了所有节点的“Yes”,它就正式下达“提交”指令,所有节点才真正执行操作(创建订单、扣减库存),如果第一阶段有任何一个节点说“No”,协调者就下达“回滚”指令,所有节点释放锁定的资源,当作什么都没发生过。

(来源:数据库系统教科书中的经典分布式事务协议)

2PC的优点是保证了强一致性,但它有个大缺点:性能差且存在单点故障风险,在准备阶段,所有资源都被锁定,其他操作只能干等着,这叫“阻塞”,严重影响并发性能,协调者是个单点,如果它在发出“提交”指令后宕机了,而有些节点已经提交了,有些没收到指令,这些节点就会一直处于不确定状态,不知道到底该提交还是回滚。

三阶段提交(3PC)—— 给2PC打了个“补丁”

深入聊聊分布式系统里那些绕不开的事务问题和常见模型怎么解决的

为了解决2PC的阻塞和不确定性问题,3PC被提了出来,它在2PC的基础上插入了第三个阶段:预提交阶段

  • 在“准备阶段”和“提交阶段”之间,协调者会先发一个“预提交”命令,这个命令的意思是:“大家都准备好,我们大概率要提交了,但还不是最终命令。”节点收到后,会做最终检查,但理论上锁资源的时间可以更短一些。
  • 这样做的好处是,如果协调者在“预提交”之后宕机,新的协调者上台后,看到所有节点都进入了“预提交”状态,就可以安全地推断出原协调者是要提交的,从而避免那种不确定的状态。

(来源:对两阶段提交协议的改进学术论文)

但3PC依然复杂,而且它依赖于一个假设:网络环境是“非拜占庭”的,即节点只会宕机而不会恶意响应,在实际的复杂网络环境中,它的优势并不总是那么明显,所以应用没有2PC广泛。

最终一致性模型 —— “先干了再说”的务实派

面对2PC/3PC的复杂性和性能瓶颈,在很多互联网场景下,人们开始反思:是不是每个场景都需要那么强的、即时的一致性?你发一条微博,晚几秒钟让另一个用户看到,通常是可以接受的。“最终一致性”模型变得非常流行。

深入聊聊分布式系统里那些绕不开的事务问题和常见模型怎么解决的

这个模型的核心思想是:放弃强一致性(特别是隔离性),允许系统在中间状态存在短暂的不一致,但通过一些补偿和修复机制,保证数据最终会达到一致状态。

最常见的实现方式是:

  • 异步消息队列,还是那个下单例子,A分店创建订单后,不是直接去调用B分店的库存服务,而是向一个高可用的消息队列发一条“请扣减B分店XX商品库存1件”的消息,然后就直接返回用户“下单成功”了,B分店的库存服务会异步地从消息队列里取出这个消息并执行,即使B分店的服务暂时不可用,消息也会在队列里存着,等它恢复了再处理,这就解决了节点故障的问题。
  • 补偿机制(Saga模式),这是应对错误情况的,如果库存扣减时发现没货了怎么办?系统会触发一个补偿操作,比如执行一个“取消订单”的流程,并通知用户,这一系列操作被设计成一个长长的“事务链”,每个步骤都有对应的补偿步骤,这就像旅行订票,先订机票,再订酒店;如果酒店订不上,就取消机票,整个过程没有一个大锁,而是通过事后补偿来保证最终结果正确。

(来源:微服务架构实践中流行的Saga模式及相关行业实践总结)

最终一致性模型用“暂时的不一致”换取了极高的可用性性能,非常适合对一致性要求不那么极致的互联网业务,它的挑战在于,业务逻辑会变得更复杂,开发者需要处理好各种中间状态和补偿逻辑。

总结一下

分布式事务没有银弹,2PC像严谨的会议,保证强一致但牺牲灵活;最终一致性像敏捷的小组,先推进再修正,追求速度和可用性,在实际系统中,往往是多种模型混合使用,核心的金融交易可能用TCC(一种更复杂的2PC变种),而用户行为追踪则用最终一致性,理解这些模型的取舍,正是设计和驾驭好分布式系统的关键所在。