分布式一致性协议

Posted Young丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式一致性协议相关的知识,希望对你有一定的参考价值。

1 两阶段提交协议(2PC)

1.1 两阶段提交协议

两阶段提交协议,简称 2PC(2 Prepare Commit),是比较常用的解决分布式事务问题的方式,要么所 有参与进程都提交事务,要么都取消事务,即实现 ACID 中的原子性(A)的常用手段。

分布式事务: 事务提供一种操作本地数据库的不可分割的一系列操作 “要么什么都不做,要么做全 套(All or Nothing)”的机制,而分布式事务就是为了操作不同数据库的不可分割的一系列操作 “要 么什么都不做,要么做全套(All or Nothing)”的机制

1.2 2PC 执行流程

1.2.1 成功执行事务事务提交流程

阶段一:

  • 事务询问

    协调者向所有的参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待各参与者的响应。

  • 执行事务 (写本地的 Undo/Redo 日志)

  • 各参与者向协调者反馈事务询问的响应

阶段二:

  • 发送提交请求:

    协调者向所有参与者发出 commit 请求。

  • 事务提交:

    参与者收到 commit 请求后,会正式执行事务提交操作,并在完成提交之后释放整个事务执行期间占用的事务资源。

  • 反馈事务提交结果:

    参与者在完成事务提交之后,向协调者发送 Ack 信息。

  • 完成事务:

    协调者接收到所有参与者反馈的 Ack 信息后,完成事务。

1.2.2 中断事务流程

假如任何一个参与者向协调者反馈了 No 响应,或者在等待超时之后,协调者尚无法接收到所有参 与者的反馈响应,那么就会中断事务

阶段一:

  • 事务询问

    协调者向所有的参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待各参与者的响应。

  • 执行事务 (写本地的 Undo/Redo 日志)

  • 各参与者向协调者反馈事务询问的响应
    阶段二:

  • 发送回滚请求:
    协调者向所有参与者发出 Rollback 请求。

  • 事务回滚:
    参与者接收到 Rollback 请求后,会利用其在阶段一中记录的 Undo 信息来执行事务回滚操作,并在完成回滚之后释放在整个事务执行期间占用的资源。

  • 反馈事务回滚结果:

    参与者在完成事务回滚之后,向协调者发送 Ack 信息。

  • 中断事务:
    协调者接收到所有参与者反馈的 Ack 信息后,完成事务中断。

1.3 2PC 优点缺点

  1. 优点

    原理简单

  2. 缺点

    • 同步阻塞

      在二阶段提交的执行过程中,所有参与该事务操作的逻辑都处于阻塞状态,即当参与者占有公共资源时,其他节点访问公共资源会处于阻塞状态

    • 单点问题

      若协调器出现问题,那么整个二阶段提交流程将无法运转,若协调者是在阶段二中出现问题时,那么其他参与者将会一直处于锁定事务资源的状态中,而无法继续完成事务操作

    • 数据不一致

      在阶段二中,执行事务提交的时候,当协调者向所有的参与者发送 Commit 请求之后,发生了局部网络异常或者是协调者在尚未发送完 Commit 请求之前自身发生了崩溃,导致最终只有部分参与者收到了 Commit 请求,于是会出现数据不一致的现象。

    • 太过保守

      在进行事务提交询问的过程中,参与者出现故障而导致协调者始终无法获取到所有参与者的响应信息的话,此时协调者只能依靠自身的超时机制来判断是否需要中断事务,这样的策略过于保守,即没有完善的容错机制,任意一个结点的失败都会导致整个事务的失败。

2 三阶段提交协议(3PC)

三阶段提交协议出现背景:一致性协议中设计出了二阶段提交协议(2PC),但是 2PC 设计中还存 在缺陷,于是就有了三阶段提交协议,这便是 3PC 的诞生背景。

2.1 三阶段提交协议

3PC,全称 “three phase commit”,是 2PC 的改进版,将 2PC 的 “提交事务请求” 过程一分为二,共 形成了由CanCommitPreCommitdoCommit三个阶段组成的事务处理协议。

三阶段提交升级点(基于二阶段):

  • 三阶段提交协议引入了超时机制。
  • 在第一阶段和第二阶段中,引入了一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

简单讲:就是除了引入超时机制之外,3PC 把 2PC 的准备阶段再次一分为二,这样三阶段提交就有 CanCommitPreCommitDoCommit三个阶段。

2.2 三个阶段详解

2.2.1 第一阶段(CanCommit 阶段)

类似于 2PC 的准备(第一)阶段。协调者向参与者发送 CanCommit 请求,参与者如果可以提交就返回 Yes 响应,否则返回 No 响应。

  • 事务询问

    协调者向参与者发送 CanCommit 请求。询问是否可以执行事务提交操作。然后开始等待参与 者的响应。

  • 响应反馈:

    参与者接到 CanCommit 请求之后,正常情况下, 如果其自身认为可以顺利执行事务,则返回 Yes 响应,并进入预备状态。 否则反馈 No

2.2.2 第二阶段(PreCommit 阶段)

协调者根据参与者的反应情况来决定是否可以执行事务的 PreCommit 操作。根据响应情况,有以下两种可能。

  • Yes

(1).发送预提交请求: 协调者向参与者发送 PreCommit 请求,并进入 Prepared 阶段。

(2).事务预提交: 参与者接收到 PreCommit 请求后,会执行事务操作,并将 undo 和 redo 信息记录 到事务日志中。 (3).响应反馈: 如果参与者成功的执行了事务操作,则返回 ACK 响应,同时开始等待最终指令。

  • NO

假如有任何一个参与者向协调者发送了 No 响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。则有:

(1).发送中断请求: 协调者向所有参与者发送 abort 请求。

(2).中断事务: 参与者收到来自协调者的 abort 请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断

2.2.3 第三阶段(doCommit 阶段)

该阶段进行真正的事务提交,也可以分为执行提交和中断事务两种情况。

  • 执行成功

    (1). 发送提交请求: 协调者接收到参与者发送的 ACK 响应,那么它将从预提交状态进入到提交状态。 并向所有参与者发送 doCommit 请求。

    (2).事务提交: 参与者接收到 doCommit 请求之后,执行正式的事务提交。 并在完成事务提交之 后释放所有事务资源。

    (3).响应反馈: 事务提交完之后,向协调者发送 ACK 响应。

    (4).完成事务: 协调者接收到所有参与者的 ACK 响应之后,完成事务。

  • 中断事务

    (1).发送中断请求: 协调者向所有参与者发送 abort 请求

    (2).事务回滚: 参与者接收到 abort 请求之后,利用其在阶段二记录的 undo 信息来执行事务的回滚操作, 并在完成回滚之后释放所有的事务资源。

    (3).反馈结果: 参与者完成事务回滚之后,向协调者发送 ACK 消息

    (4).中断事务: 协调者接收到所有参与者反馈的 ACK 消息之后,执行事务的中断。

2.2.4 注意:一旦进入阶段三,可能会出现 2 种故障:

  • 协调者出现问题

  • 协调者和参与者之间的网络故障

如果出现了任一一种情况,最终都会导致参与者无法收到 doCommit 请求或者 abort 请求,针对 这种情况,参与者都会在等待超时之后,继续进行事务提交

2.3 2PC 对比 3PC

  1. 首先对于协调者和参与者都设置了超时机制(在 2PC 中,只有协调者拥有超时机制,即如果在一定时间内没有收到参与者的消息则默认失败),主要是避免了参与者在长时间无法与协调者节点通讯 (协调者挂掉了)的情况下,无法释放资源的问题,因为参与者自身拥有超时机制会在超时后,自动进行本地 commit 从而进行释放资源。而这种机制也侧面降低了整个事务的阻塞时间和范围。

  2. 通过 CanCommit、PreCommit、DoCommit 三个阶段的设计,相较于 2PC 而言,多设置了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的 。

  3. PreCommit 是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的。

    问题:3PC 协议并没有完全解决数据一致问题。

图解分布式一致性协议Paxos

Paxos协议/算法是分布式系统中比较重要的协议,它有多重要呢?

<分布式系统的事务处理>

Google Chubby的作者Mike Burrows说过这个世界上只有一种一致性算法,那就是Paxos,其它的算法都是残次品。

<大规模分布式存储系统>

理解了这两个分布式协议之后(Paxos/2PC),学习其他分布式协议会变得相当容易。

学习Paxos算法有两部分:a) 算法的原理/证明;b) 算法的理解/运作。

理解这个算法的运作过程其实基本就可以用于工程实践。而且理解这个过程相对来说也容易得多。

网上我觉得讲Paxos讲的好的属于这篇:paxos图解Paxos算法详解,我这里就结合wiki上的实例进一步阐述。一些paxos基础通过这里提到的两篇文章,以及wiki上的内容基本可以理解。

算法内容

Paxos在原作者的《Paxos Made Simple》中内容是比较精简的:

Phase 1

(a) A proposer selects a proposal number n and sends a prepare request with number n to a majority of acceptors.

(b) If an acceptor receives a prepare request with number n greater than that of any prepare request to which it has already responded, then it responds to the request with a promise not to accept any more proposals numbered less than n and with the highest-numbered pro-posal (if any) that it has accepted.

Phase 2

(a) If the proposer receives a response to its prepare requests (numbered n) from a majority of acceptors, then it sends an accept request to each of those acceptors for a proposal numbered n with a value v , where v is the value of the highest-numbered proposal among the responses, or is any value if the responses reported no proposals.

(b) If an acceptor receives an accept request for a proposal numbered n, it accepts the proposal unless it has already responded to a prepare request having a number greater than n.

借用paxos图解文中的流程图可概括为:

技术分享图片

实例及详解

Paxos中有三类角色ProposerAcceptorLearner,主要交互过程在ProposerAcceptor之间。

ProposerAcceptor之间的交互主要有4类消息通信,如下图:

技术分享图片

这4类消息对应于paxos算法的两个阶段4个过程:

  • phase 1
    • a) proposer向网络内超过半数的acceptor发送prepare消息
    • b) acceptor正常情况下回复promise消息
  • phase 2
    • a) 在有足够多acceptor回复promise消息时,proposer发送accept消息
    • b) 正常情况下acceptor回复accepted消息

因为在整个过程中可能有其他proposer针对同一件事情发出以上请求,所以在每个过程中都会有些特殊情况处理,这也是为了达成一致性所做的事情。如果在整个过程中没有其他proposer来竞争,那么这个操作的结果就是确定无异议的。但是如果有其他proposer的话,情况就不一样了。

paxos中文wiki上的例子为例。简单来说该例子以若干个议员提议税收,确定最终通过的法案税收比例。

以下图中基本只画出proposer与一个acceptor的交互。时间标志T2总是在T1后面。propose number简称N。

情况之一如下图:

技术分享图片

A3在T1发出accepted给A1,然后在T2收到A5的prepare,在T3的时候A1才通知A5最终结果(税率10%)。这里会有两种情况:

  • A5发来的N5小于A1发出去的N1,那么A3直接拒绝(reject)A5
  • A5发来的N5大于A1发出去的N1,那么A3回复promise,但带上A1的(N1, 10%)

这里可以与paxos流程图对应起来,更好理解。acceptor会记录(MaxN, AcceptN, AcceptV)

A5在收到promise后,后续的流程可以顺利进行。但是发出accept时,因为收到了(AcceptN, AcceptV),所以会取最大的AcceptN对应的AcceptV,例子中也就是A1的10%作为AcceptV。如果在收到promise时没有发现有其他已记录的AcceptV,则其值可以由自己决定。

针对以上A1和A5冲突的情况,最终A1和A5都会广播接受的值为10%。

其实4个过程中对于acceptor而言,在回复promise和accepted时由于都可能因为其他proposer的介入而导致特殊处理。所以基本上看在这两个时间点收到其他proposer的请求时就可以了解整个算法了。例如在回复promise时则可能因为proposer发来的N不够大而reject:

技术分享图片

如果在发accepted消息时,对其他更大N的proposer发出过promise,那么也会reject该proposer发出的accept,如图:

技术分享图片

这个对应于Phase 2 b):

it accepts the proposal unless it has already responded to a prepare request having a number greater than n.

总结

Leslie Lamport没有用数学描述Paxos,但是他用英文阐述得很清晰。将Paxos的两个Phase的内容理解清楚,整个算法过程还是不复杂的。

至于Paxos中一直提到的一个全局唯一且递增的proposer number,其如何实现,引用如下:

如何产生唯一的编号呢?在《Paxos made simple》中提到的是让所有的Proposer都从不相交的数据集合中进行选择,例如系统有5个Proposer,则可为每一个Proposer分配一个标识j(0~4),则每一个proposer每次提出决议的编号可以为5*i + j(i可以用来表示提出议案的次数)

参考文档

以上是关于分布式一致性协议的主要内容,如果未能解决你的问题,请参考以下文章

分布式一致性协议2PC和3PC

超详细解析 | 一致性协议算法-2PC3PCPaxosRaftZABNWR

分布式事务-02:2PC 二阶段提交协议实现过程及原理

分布式系统的一致性协议之 2PC 和 3PC

目前最详细最常见的一致性协议算法-2PC3PCPaxosRaftZABNWR

目前最详细最常见的一致性协议算法-2PC3PCPaxosRaftZABNWR