分布式事务协议与解决
对于本地事务处理,很显然我们可以采用很成熟的 ACID 模型来保证数据的严格一致性。而在分布式系统中,必然面临网络等不可靠问题,尤其对一个高访问量、高并发的互联网分布式系统,如果不采用特殊的机制来保证数据的一致性,就很容易会出现数据不一致的情况,因此要实现分布式事务,就需要进行特有的失败回滚、补偿、幂等性等可靠性容错设计。
5.4.1 什么是补偿机制?
在 TCC、Saga 等分布式模型中,我们多次提到补偿机制,补偿机制是实现分布式事务的重要手段之一。
在分布式系统中,由于各个节点的执行可能存在时延、失败等情况,会导致分布式事务中参与者节点状态不一致,从而使得分布式事务无法完成。为了解决这个问题,我们需要引入一种机制来进行补偿。
补偿机制指的是:在分布式事务出现异常时,通过一系列的操作,尽可能使得分布式事务状态回滚到之前的状态,从而避免分布式事务产生不一致的情况。
具体来说,补偿机制通常包括两个方面的内容:
- 补偿操作:在发现分布式事务出现异常时,执行一系列的操作,使得分布式事务状态回滚到之前的状态,这个过程就称为补偿操作。补偿操作通常包括撤销之前的一些操作,例如将之前已经提交的事务进行回滚。
- 补偿流程:对于分布式事务中的每一个参与者节点,需要设计一个相应的补偿流程,用来保证在出现异常时,能够及时执行补偿操作。补偿流程通常包括检测异常情况、触发补偿操作等步骤。
5.4.2 分布式事务解决理论 2PC
如果我们要设计一个强一致性的 CP 架构系统,该如何实现呢?针对强一致性的分布式事务场景,出现了二阶段提交以及三阶段提交协议的解决方案。
二阶段提交协议(Two-phase Commit Protocol,简称 2PC)是一个基于协调者的强一致性原子提交协议。 两阶段提交协议在分布式系统中被广泛应用于解决分布式事务相关问题。目前大部分关系数据库都是用二阶段提交来完成分布式事务,例如 Oracle、MySQL 所支持的 XA 协议也可归类于两阶段提交协议。
1. 二阶段协议概述
在分布式系统中,由于分支事务只能知道自己执行的结果,并不知道其他分支事务的执行情况,因此需要设计一个协调者的角色,各个分支事务向协调者上报执行状态,再由协调者根据各个分支事务的执行结果决定全局事务的提交或回滚。
两阶段提交协议,顾名思义由两个阶段组成,即准备阶段和提交回滚阶段。第一阶段用于各个分支事务的资源锁定,第二阶段用于全局事务的提交或回滚。
1.1 第一阶段:准备阶段
二提交第一阶段为准备阶段,又称为投票阶段,由协调者向参与者发起请求,以询问当前事务是否能正确处理,当参与者收到请求后,开启本地数据库事务,执行分支事务的具体内容,但此时并会提交分支事务。参与者根据执行分支事务的结果,反馈给协调者 YES 或 NO,表示该分支事务是否可正确提交。
1.2 第二阶段:提交/回滚阶段
在准备阶段,参与者向协调者汇报 YES/NO 两种状态。而在阶段二,也有对应两种处理方式:提交全局事务或回滚全局事务。
协调者在超过约定的时间内没有收到全部参与者的响应时,或者收到所有参与者的响应中存在状态为 NO 时,便会发起全局事务回滚。如果收到所有的分支状态都有 YES,便会发起全局事务提交,同时向客户端返回全局事务结果,并结束本次事务。
2. 二阶段协议的优缺点
两阶段提交逻辑设计容易理解、逻辑清晰简单,但在实际场景中也存在不少问题,主要包括以下三点:
- 同步阻塞问题:两阶段提交协议的阻塞主要体现在参与者需要协调者的指令才能执行第二阶段的操作。当协调者发生故障时,参与者在第一阶段锁定的资源将一直无法释放。
- 潜在数据不一致风险:在第二阶段,如果因为网络异常导致一部分参与者收到 Commit 请求,而另一部分没有收到 Commit 请求,那么结果将是部分参与者提交了事务,而另一部分参与者无法提交。
- 单点问题和脑裂:
- 单点问题:二阶段提交过于依赖协调者,当协调者发生故障时,整个集群将不可用。
- 脑裂:当集群出现多个协调者时,将无法保证二阶段提交协议的正确性。
添加评论