一致性协议-看着一篇就够了

153 阅读7分钟
  1. Basic Paxos

分为两个步骤,第一个是去获得proimise, 如果已经有Accepted值了,用Aceepted的值。 如果没有,那么用最大的promise的id和值。 id的值一直用最大的。可以变更。

  1. 总结:

有A选A,无A选最大的P。P的值始终用最大的。

以上是没有考虑核心问题的流程

  1. 核心问题有两个:

1网络的不可靠性

2并发的问题

  1. Multi Paxos

为了解决核心问题,升级了Paxos,加入了主节点,然后把在主节点内解决并发问题

这样的话问题就演化成了,

  • 如何选主(BasicPaxos)。 ----并发问题
  • 如何把数据复制到各个节点上(Entity Replication)。
  • 如何保证过程是安全的(Safety)。
  1. 前置工作选主

心跳链接主节点,当没有主节点,选举使用的算法: basic Paxos,多数被Accepted被选举成功。

非主节点的请求会把审批请求转发到主节点进行审批。

以通俗理解为选主过后,就不会再有其他节点与它竞争。

因为可以视作是经过选举时的那一次准备之后,后续的提案都是对相同提案 ID 的一连串的批准过程。

第二步执行审批并把数据同步到其他节点(两阶段提交)

在正常情况下,当客户端向主节点发起一个操作请求,譬如提出“将某个值设置为 X”,此时主节点将 X 写入自己的变更日志,但先不提交,接着把变更 X 的信息在下一次心跳包中广播给所有的从节点,并要求从节点回复确认收到的消息,从节点收到信息后,将操作写入自己的变更日志,然后给主节点发送确认签收的消息,主节点收到过半数的签收消息后,提交自己的变更、应答客户端并且给从节点广播可以提交的消息,从节点收到提交消息后提交自己的变更,数据在节点间的复制宣告完成。

异常情况下如何同步数据呢?

假设出现两个分区,然后两个分区都有自己的master,这种情况下,他们互不干扰,也相互不知道。

网络分区问题: 使用任期编号来解决。

当网络恢复后,谁的任期编号大,那么谁就来当主节点。

通过心跳机制,同步这段时间缺失的记录。

如果请求到了slave怎么办?

由slave转发到master.

安全性:

以上的所有过程都是在围绕这个处理,目标就是安全性。

  1. Raft/ZAB协议

一致性算法使用中间件
ZABZookepper
RaftRedis

Paxos/Raft/ZAB都是强一致的分布式共识协议,都是CP。

ZAB VS RAFT

区别总结:

选主:

ZAB选主是有ZXID(最新事务id)和Myid(机器ID)来保证的。 ZXID最大,选ZXID, ZXID存在相同选最大Myid。

Raft: 完全按照随机始终,时间跟本地的提交消息有一点关联,数据多的时间快一些。

心跳: ZAB双向,Raft单向。

消息顺序: ZAB都有leader写入,并使用两阶段提交保证可见性,raft非两阶段,没有follower返回确认的阶段。

项目ZABRAFT
节点状态looking:选举状态,无主、leading、 following、 observing:不参与选举leader、 follower、 candidate:不认leader的node
选举机制默认FastLeaderElection: 节点启动直接投自己,然后开始给其他节点发请求,在每个朝代(epoch,raft里是term)中,节点先收到其他提案(proposal),然后本地battle(zxid, myid) 大小后再发出选票给所有node,一个朝代中每个节点可以发多次投票,一个节点收到半数以上选票则当选leader每个candidate具备随机时钟(election timeout),到时间了先投自己,然后发消息给其他所有node,收到消息的candidate变为follower并回复,当半数原则满足后leader确立,leader再通告所有节点你们的leader出现了,停下手里的针线活吧。但每个朝代一个节点只能投票一次,而且candidate只响应大于自己term的请求,否则保持选举状态。
选举机制优劣不存在分区、有利于选出有最新数据的nodebattle次数过多造成选举时间长、首次启动会有myid节点大概率成为leader选举速度快可能因为随机时钟差不多造成每个node的票数都没过半,发生投票分区,那只能进入下一个周期再选举
选主依据1. epoch选举朝代、 2.ZXID:64BIT正整数,高32为epoch,低32为顺序自增的事务ID、 3. 机器myid1. term朝代每一轮选举都增加、 2. 日志条目 3. election timeout
定时心跳双方检测。 leader向所有follower发送定期心跳,心跳返回不过半则导致leader退位。follower没有收到来自leader的心跳会导致进入looking状态单方检测。 follower定时没有接到心跳则变为candidate状态,自增朝代term并准备选举
新节点加入新节点启动先给所有node发消息,然后自己内部做选主依据信息battle直接接到leader的append entry消息,就知道谁是leader了
写消息流程两阶段:client请求followerA、follower发请求给leader,leader对众follower发送proposal,过半后返回后再发commit,当followerA commit后返回客户端。非两阶段:client请求follower,follower把消息转到leader后,leader写日志并向其他节点发AppendEntries,大多数返回后leader就向客户端返回。
消息一致性(线性顺序)zab利用client、leader、follower的多端努力,以自增的zxid为依据,保证写入强一致性(线性一致性)。若收到非顺序的zxid则禁止写入或节点退出。相同的 term 和 index的节点之前内容肯定一样。选举时candidate携带最新 (term, index),如果对家小于自己则拒绝投票,所以选出来的leader肯定是大多节点里最新的。外加,提交也要过半成功。两者组合实现了一致性
消息顺序性follower必须按顺序接收zxid+提交,否则退出进入恢复。leader每次都发当前的消息和上一条消息,如果follower找不到上一条消息就不复制,再要求leader发上一条消息,直到定位到缺失消息。
残留消息一致性(follower有较新的未提交消息)新leader上台后,leader尝试commit未提交的消息,没commit的proposal都会被丢弃STRONG LEADER,非持有uncommitted log的新leader,会强制follower复制自己的日志解决一致性。
脏读存在但几率低,leader 发proposal过半后再发commit,接收follower commit后才返回客户端存在,leader 发消息过半ack后就返回client请求了,可能follower没有commit就没了、或者leader没发现自己丧失领导权等
持久性WAL实现,zk将其优化为每个64MB的预占文件。snapshot压缩数据日志类似zab,也是WAL + snapshot committed log

两者相似点:

单M架构、两者都要先写入 leader 、都为CP。

  1. Gossip 协议(流行病算法)

最终一致性协议。例如DNS网络

比特币网络和许多重要分布式框架

类似于计算机网络的洪范法。去传播数据。

两个步骤

第一个步骤:

消息源会选择K个它链接的节点进行发送数据。

第二个步骤:

收到消息的节点,如果这个消息没有被接受过,那么就会把消息记录下来,并执行步骤一。

经过重复执行上面两个步骤,所有的节点都会有这个消息。

缺点:

1最终一致: 多个轮次的散播而到达全网的,必然节点间消息不一致

2无法准确地预计到需要多长时间才能达成全网一致

3不可避免的存在消息重复发送给同一节点的情况,加大带宽的压力

参考文章:

凤凰架构:icyfenix.cn/distributio…

ZAB好文:

zhuanlan.zhihu.com/p/543583983

zhuanlan.zhihu.com/p/438010804