分布式事务中2PC与3PC的区别

协调者(Coordinator)

在分布式系统中,每一个机器节点虽然都能明确的知道自己执行的事务是成功还是失败,但是却无法知道其他分布式节点的事务执行情况。因此,当一个事务要跨越多个分布式节点的时候(比如,淘宝下单流程,下单系统和库存系统可能就是分别部署在不同的分布式节点中),为了保证该事务可以满足ACID,就要引入一个协调者(Cooradinator)。其他的节点被称为参与者(Participant)。协调者负责调度参与者的行为,并最终决定这些参与者是否要把事务进行提交。

二阶段提交协议(2PC,two phase commit)

二阶段提交协议主要分为2个阶段:准备阶段和提交阶段

分布式事务中2PC与3PC的区别

当协调者接收到所有的参与者的反馈之后,开始进入事务提交阶段。如果所有参与者都返回YES,那就发送COMMIT请求,如果有一个人返回NO,那就返送Rollback请求。

2PC协议中,如果出现协调者和参与者都挂了的情况,有可能导致数据不一致。

2PC 是几乎所有分布式事务算法的基础,后续的分布式事务算法几乎都由此改进而来,其优缺点非常明显:

  • 优点:在于已经有较为成熟的实现方案,比如 XA。
  • 缺点:XA 是一个阻塞协议。服务在投票后需要等待协调器的决定,此时服务会阻塞并锁定资源。由于其阻塞机制和最差时间复杂度高, 因此,这种设计不能适应随着事务涉及的服务数量增加而扩展的需要,很难用于并发较高以及子事务声明周期较长 (long-running transactions) 的分布式服务中。

三阶段提交协议(3PC)

分布式事务中2PC与3PC的区别

3PC最关键要解决的就是协调者和参与者同时挂掉的问题,所以3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。

在第一阶段,只是询问所有参与者是否可可以执行事务操作,并不在本阶段执行事务操作。当协调者收到所有的参与者都返回YES时,在第二阶段才执行事务操作,然后在第三阶段在执行commit或者rollback。

简单概括一下就是,如果挂掉的那台机器已经执行了commit,那么协调者可以从所有未挂掉的参与者的状态中分析出来,并执行commit。如果挂掉的那个参与者执行了rollback,那么协调者和其他的参与者执行的肯定也是rollback操作。

所以,再多引入一个阶段之后,3PC解决了2PC中存在的那种由于协调者和参与者同时挂掉有可能导致的数据一致性问题。

3PC 在 commit 之前增加了 preCommit 的过程,使得在参与者在收不到确认时,依然可以从容 commit 或者 rollback,避免资源锁定太久导致浪费。但是 3PC 同样存在着很多问题。实现起来非常复杂,因为很难通过多次询问来解决系统间分歧问题,尤其是存在超时状态互不信任的分布式网络中,这也就是著名的拜占庭将军问题。

SAGA

SAGA 算法于 1987 年提出,是一种异步的分布式事务解决方案,其理论基础在于,其假设所有事件按照顺序推进,总能达到系统的最终一致性。

因此 saga 需要服务分别定义提交接口以及补偿接口,当某个事务分支失败时,调用其它的分支的补偿接口来进行回滚,saga 的具体实现分为两种:Choreography 以及 Orchestration,

总结一下:SAGA 模型的优点在于其降低了事务粒度,使得事务扩展更加容易,同时采用了异步化方式提升性能。但是其缺点在于很多时候很难定义补偿接口,回滚代价高,而且由于 SAGA 在执行过程中采用了先提交后补偿的思路进行操作,所以单个子事务在并发提交时的隔离性很难保证。

TCC

TCC(Try-Confirm-Concel) 模型同样是一种补偿性事务,主要分为 Try:检查、保留资源,Confirm:执行事务,Cancel:释放资源三个阶段,如下图所示:

分布式事务中2PC与3PC的区别

总结一下,相比于 SAGA 模型,其优点在于尝试阶段仅仅只是对业务系统做检测,并保留业务资源,并没有真正提交,所以后续 SAGA 需要针对提交的事务做补偿,而 TCC 则仅仅需要释放保留资源,降低了补偿成本;并且,由于在 Try 阶段对资源进行了保留锁定,所以相比于 SAGA 模式,TCC 模式拥有更高的隔离性。

缺点:相比于 SAGA 模式,TCC 模式多增加了一个状态,导致在业务开发过程中,复杂度上升,而且协调器与子事务的通信过程增加,状态轮转处理也更为复杂。

事务消息 MQ

1. 传统事务消息实现

传统事务消息实现,一种思路是依赖于 AMQP 协议用来确保消息发送成功,AMQP 模式下需要在发送在发送事务消息时进行两阶段提交,首先进行 tx_select 开启事务,然后再进行消息发送,最后进行消息的 commit 或者是 rollback。这个过程可以保证在消息发送成功的同时本地事务也一定成功执行,但事务粒度不好控制,而且会导致性能急剧下降,同时依然无法解决本地事务执行与消息发送的原子性问题。

2. RocketMQ 事务消息

RocketMQ 事务消息设计则主要是为了解决 Producer 端的消息发送与本地事务执行的原子性问题,RocketMQ 的设计中 broker 与 producer 端的双向通信能力,使得 broker 天生可以作为一个事务协调者存在;而 RocketMQ 本身提供的存储机制,则为事务消息提供了持久化能力;RocketMQ 的高可用机制以及可靠消息设计,则为事务消息在系统在发生异常时,依然能够保证事务的最终一致性达成。

相关推荐