想搞懂分布式事务那些事儿,2PC和3PC模型到底怎么个玩法
- 问答
- 2025-12-27 22:43:51
- 3
想搞懂分布式事务那些事儿,咱们得先从一个简单的场景说起,想象一下,你网上购物,点击“支付”按钮,这个动作背后,其实触发了至少两个系统的操作:第一个是银行的系统,要从你的账户里扣掉100块钱;第二个是电商平台的系统,要把你的订单状态从“待支付”改成“已支付”,这两个操作必须像一个操作一样,要么都成功,要么都失败,绝对不能出现钱扣了但订单没成功的情况,或者订单成功了但钱没扣的尴尬,这种需要跨多个系统(或数据库)协同完成一个完整业务操作的情况,分布式事务”要解决的核心问题,它的目标就是保证所有参与方最终的数据一致性。(来源:对分布式事务核心概念的普遍理解)
那怎么保证这种“要么全做,要么全不做”的特性呢?业界提出了很多模型,其中最经典、最基础的就是两阶段提交,简称2PC,你可以把它想象成一个小组在做重大决策时的开会过程,这个小组里有一个“协调者”(通常是发起事务的那个系统,比如电商平台的交易服务),还有好几个“参与者”(就是银行系统、库存系统等等)。
2PC模型怎么玩?
2PC,顾名思义,分两个阶段。
第一阶段:准备阶段(投票阶段) 协调者像个主持人,向所有参与者发问:“兄弟们,我准备要执行一个事务了(比如扣款100元、变更订单状态),你们各自检查一下自己的状况,看看能不能成功执行?如果能,就把准备工作做好(比如先把这100块钱在你的账户里冻结住,但先不真正划走),然后告诉我你的决定。” 这个时候,每个参与者会进行自查:我的系统正常吗?账户余额够吗?商品有库存吗?如果一切OK,参与者就会在本地把事务操作记录下来(写入日志),然后回复协调者:“我这边没问题,准备就绪!”(Yes投票),如果任何一步出错了,比如发现账户余额不足,参与者就会回复:“我这边搞不定!”(No投票)。
第二阶段:提交阶段(执行阶段) 协调者焦急地等待着所有参与者的回复,它要根据大家的投票结果来做出最终决定:
- 如果所有参与者都回复了“Yes”,协调者就会很高兴,向大家发出最终指令:“好!全员通过!现在我正式宣布,事务提交!你们各自执行最终操作吧(真的扣款、真的改状态)!” 参与者们收到“提交”指令后,才会真正完成数据的永久修改,并再次回复协调者:“搞定!”
- 如果有一个或多个参与者回复了“No”,或者超时没回复,协调者就会宣布:“很遗憾,有人反对或失联,事务中止!大家都撤销在第一阶段做的准备工作吧(比如解冻那100块钱)。” 参与者们收到“回滚”指令后,就会撤销之前的预备操作,恢复到事务开始前的状态。
2PC看起来挺完美的,通过一个“民主集中制”的过程保证了一致性,但它有几个明显的缺点,主要出在“协调者”这个单点上:(来源:对2PC缺点的普遍分析)

- 同步阻塞问题:在整个投票过程中,所有参与者的事务资源(比如那100块钱)都处于锁定或冻结状态,他们必须傻等着协调者的最终指令,期间不能干别的,如果协调者很忙或者网络慢,大家就得等很久,系统的性能和吞吐量会大受影响。
- 单点故障问题:这是最要命的,万一协调者在发出“准备”指令后,在等待投票结果或者刚刚发出“提交”指令还没来得及通知到所有人时,自己突然宕机了,这下就乱套了!那些已经投了“Yes”的参与者会一直卡在“准备就绪”的状态,不知道到底该提交还是回滚,它们的事务资源也就一直被锁着,动弹不得,虽然可以通过选举新协调者等方式来补救,但过程非常复杂。
- 数据不一致风险:还有一种极端情况,协调者只向一部分参与者发送了“提交”指令,然后自己就崩溃了,这会导致一部分参与者提交了事务(比如钱扣了),而另一部分参与者没收到指令,最终会超时回滚(比如订单没成功),这就造成了数据不一致,是我们最不想看到的结果。
为了缓解2PC的问题,3PC模型登场了。
三阶段提交,就是在2PC的两个阶段中间,硬插进去一个阶段,变成了三个阶段:(来源:对3PC模型设计的普遍解释)
第一阶段:CanCommit阶段 这个阶段和2PC的准备阶段很像,但有一个关键区别:它更像是一次“预检查”或“摸底调查”,协调者问大家:“我有个事务想干,你们觉得自己‘能不能’ commit?” 这个询问很轻量,参与者不需要进行真正的资源锁定或写日志,只是基于当前状态做个快速判断并回复“可以”或“不行”,这减少了因协调者早期崩溃而导致的资源长时间锁定。
第二阶段:PreCommit阶段 如果协调者在第一阶段收到了全部的“可以”回复,它就会进入第二阶段,发出 PreCommit 指令,这时,参与者们才像2PC的准备阶段一样,开始做实质性的准备工作:写日志、锁定资源,然后回复协调者“准备就绪(Ack)”。 如果协调者在第一阶段收到了任何“不行”的回复,就会直接发出 Abort(中止)指令,事务就此终止。

第三阶段:DoCommit阶段 如果协调者在第二阶段收到了所有参与者的Ack,它就会发出最终的 DoCommit 指令,参与者们正式提交事务。 这个阶段的关键改进在于:引入了超时机制,参与者们在PreCommit阶段完成后,会启动一个定时器,如果在这个阶段,参与者迟迟收不到协调者的DoCommit或Abort指令(比如协调者宕机了),它不会像2PC那样无限期傻等,而是会默认执行提交事务,为什么敢这么做?因为能进入到第三阶段,意味着所有参与者在第二阶段都已经明确表示“我准备好了”(PreCommit成功),这说明大家大概率都是健康的,共识已经基本达成,与其无限期阻塞,不如默认推进事务,这样可以避免因协调者单点故障导致的整个系统僵死。
如果协调者在第二阶段发现了问题,或者在第三阶段决定中止,它会发出Abort指令,参与者收到Abort,或者在该阶段超时前收到Abort,都会回滚事务。
3PC解决了什么问题?又带来了什么新问题?
3PC主要针对2PC的“同步阻塞”和“单点故障”问题做了优化,通过引入预检查阶段和超时机制,降低了参与者资源被长时间锁定的概率,也使得在协调者宕机的情况下,系统有能力自动向前推进(提交),避免了整个系统的无限期阻塞,提高了系统的可用性。
但3PC并非完美:(来源:对3PC局限性的普遍分析)
- 复杂性更高:三个阶段比两个阶段更复杂,通信次数更多。
- 数据不一致风险依然存在:虽然概率降低了,但3PC仍然可能出现数据不一致,在第三阶段,因为网络分区,一部分参与者收到了DoCommit指令并提交了,而另一部分参与者因为网络问题没收到指令,之后它们超时了,也默认执行了提交,但万一它们之间有的提交成功有的提交失败呢?或者协调者实际上在发出DoCommit后立即宕机,导致指令并未完全送达?这种极端情况下的不一致风险无法根除。
2PC和3PC是理解分布式事务的基石,2PC简单但问题明显,3PC通过增加复杂度和引入超时机制来改善可用性,但牺牲了一些性能,且一致性问题并未完全解决,在实际的大型分布式系统中,为了更好的性能和可用性,人们更多采用最终一致性方案(如TCC、Saga)或基于Paxos/Raft等共识算法的方法,但2PC和3PC所阐述的基本思想和面临的核心挑战,依然是所有分布式事务方案需要思考和权衡的起点。
本文由畅苗于2025-12-27发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/69674.html
