一致性协议

Posted wuweishuo

tags:

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

2pc

2pc解决的是分布式事务问题。
2pc分为提交事务请求阶段和执行事务提交。

1. 提交事务请求阶段

技术图片

1.1 协调者向所有参与者发送事务内容,询问是否可以执行事务提交操作,等待响应或超时
1.2 各参与者执行事务操作,写入undo和redo日志
1.3 参与者返回响应

2. 执行事务提交

2.1 事务提交
如果阶段一参与者返回的都是yes响应,则执行事务提交
技术图片

2.1.1 协调者发送事务提交请求
2.1.2 参与者执行commit操作
2.1.3 参与者返回ack消息
2.1.4 协调者接收到ack消息,事务完成

2.2 中断事务
如果阶段一任一参与者返回no响应,或协调者在等待参与者响应超时,将中断事务
技术图片

2.2.1 协调者发送rollback请求
2.2.2 参与者利用1.2的undo日志执行rollback
2.2.3 参与者返回ack
2.2.4 协调者接收到ack,完成事务中断

2pc存在的问题

  1. 同步阻塞。参与者在整个2pc过程中处于阻塞状态,无法执行其他操作。
  2. 单点问题。协调者如果发生故障,将导致2pc无法执行;特别时在阶段二故障,将导致参与者一直阻塞。
  3. 数据不一致。在阶段二中,如果协调者在给部分参与者发送commit请求后故障,将导致部分参与者提交事务,而另一部分没有提交。
  4. 太过保守。任一节点故障,都会导致2pc失败。

3pc

3pc是2pc的改进版,将2pc的阶段一提交事务请求一分为二,形成canCommnit、preCommit、doCommit。
技术图片

1. canCommit

1.1 协调者向参与者发送事务内容,询问是否可以执行,等待响应
1.2 参与者判断是否可以执行,反馈yes或no

2. preCommit

如果协调者收到的都是yes响应,则执行事务预提交。
2.1 协调者发送preCommit请求
2.2 参与者执行事务操作,写入undo和redo日志
2.3 参与者反馈ack,等待doCommit请求

如果任一参与者返回no,或者协调者等待超时,则向所有参与者发送中断事务请求;如果一个参与者在等待协调者preCommit超时,将中断事务。

3. doCommit

协调者接收到所有ack请求,则执行提交
3.1 协调者发送doCommit请求
3.2 参与执行事务提交,反馈ack
3.3 完成事务

如果任一参与者返回no,或者协调者等待超时,则向所有参与者发送rollback请求;如果一个参与者在等待协调者doCommit超时,将自动执行commit操作。

3pc的改进和问题

3pc相对于2pc,在参与者引入了超时操作,减少了阻塞同时解决的单点问题。
但3pc也存在数据不一致问题,在阶段三,参与者在等待doCommit时,协调者给部分参与者发送了rollBack请求,随后故障,那么剩下的参与者将自动commit。

paxos

paxos是一种基于消息传递且具有高度容错特性的一致性算法,且是目前公认的解决分布式一致性问题最有效的算法之一。
paxos解决的是如何在集群内部对某个数据的值达成一致。

  1. proposer:发起提案
  2. acceptor:对提案投票,保存最新批准的提案和承诺的最大编号
  3. learner:学习最终提案
  4. propose:[n,v],n为提案编号,全局递增;v提案的值。
    技术图片
    一个节点可以充当多种角色。

算法

阶段一:

  1. proposer获取编号n(全局递增),先acceptor发送prepare请求。
  2. acceptor接收到一个编号为n的prepare请求,如果n大于acceptor接收过的所有prepare请求的最大编号,那么将返回它批准过的最大编号的提案(没批准过任何提案则为null),并承诺不再批准小于n的提案;否则返回err1或者不回复。
    阶段二:
  3. 如果proposer接收到大多数acceptor对prepare请求的响应,取其中占大多数提案的值v(如果是null则自己选定一个值),构建[n,v]的提案,发送包含该提案的accept请求给acceptor。;否则重复阶段一 。
  4. acceptor接收到[n,v]的accept请求,如果acceptor未接收过大于n的prepare请求,就批准该提案;否则返回err2或者不回复。
    技术图片

例子

技术图片

proposerA向acceptor发送prepare(1)的请求,acceptorX和acceptorY接收并返回ok,同时承诺不接受小于1的请求;
这时proposerB向acceptor发送prepare(2)的请求,acceptorX/Y/Z都接收并返回ok,同时承诺不接受小于2的请求;
到这时proposerA的prepare(1)才到达acceptorZ,但acceptorZ已经不接收小于2的请求,于是抛弃请求。

技术图片

proposerA接收到acceptorX/Y的响应超过一半,但提案为null,于是发送acceptor([1,2])的请求给acceptor,但acceptor已经不接收小于2的请求,于是抛弃;
proposerB同样发送acceptor([2,4])的请求,acceptorX/Y接收并批准该提案,acceptorZ由于各种原因没有接收到,但批准已超过一半,于是提案成立。

learner获取提案

  1. 一旦acceptor批准一个提案就发送各所有learner。通信次数:M*N。
  2. 选取一个主learner,由主learner同步给所有learner。通信次数:M+N-1。缺点:单点故障。
  3. 选取一个主learner集。集合个数越多,可靠性越好,但通信次数越多。

活性问题

如果acceptorA和acceptorB依次请求prepare,那就陷入死循环。
技术图片

为了避免以上主循环,必须选取一个主proposer,规定只有主proposer才能提出提案。
主proposer的选举可以用paxos,上述问题用失败休眠随机时间减少冲突。

参考资料

从Paxos到Zookeeper 分布式一致性原理与实践
https://angus.nyc/2012/paxos-by-example/
https://www.cnblogs.com/hugb/p/8955505.html

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

Zookeeper——一致性协议:Zab协议

Zab协议:Zookeeper一致性协议

Java 并发MESI缓存一致性协议

nacos的一致性协议介绍

分布式一致性协议

一致性协议-RAFT简述