分布式算法

IT知识
461
0
0
2022-04-11

分布式算法

拜占庭将军问题是最复杂的分布式故障场景,节点除了故障行为,还有恶意行为。必须使用拜占庭容错算法(BFT),比如在数字货币的区块链技术中。

拜占庭容错算法

1.口信消息型拜占庭问题之解

如果叛将人数为 m,将军人数不能少于 3m + 1 ,那么拜占庭 将军问题就能解决了。

这个算法有个前提,也就是叛将人数 m,或者说能容忍的叛将数 m,是已知的。在这个算法中,叛将数 m 决定递归循环的次数(也就是说,叛将数 m 决定将军们要进行多少轮作战信息协商),即 m+1 轮(所以,你看,只有楚是叛变的,那么就进行了两轮)。

2.签名消息型拜占庭问题之解

签名无法伪造,而且对他签名消息的内容进行任何更改都会被发现,这样的话也就会实现无论有多少忠诚的将军和多少叛 将,忠诚的将军们总能达成一致的作战计划,不过也需要进行m次协商。

3.PBFT 算 法

4.PoW 算法

非拜占庭容错算法

即故障容错算法(Crash Fault Tolerance,CFT),CFT 解决的是分布式的系统中存在故障,但不存在恶意节点的场景下 的共识问题。 也就是说,这个场景可能会丢失消息,或者有消息重复,但不存在错误消 息,或者伪造消息的情况。常见的算法有 Paxos 算法、Raft 算法、ZAB 协议。

Paxos 算法,最常用的一批共识算法都是基于它改进的。比如,Fast Paxos 算法、 Cheap Paxos 算法、Raft 算法、ZAB 协议等等。

Basic Paxos 算法

描述的是多节点之间如何就某个值(提案 Value)达成共识;

假设我们要实现一个分布式集群,这个集群是由节点 A、B、C 组成,客户端 1 试图创建值为 3 的 X,客户端 2 试图创建值为 7 的 X,这样要如何达成 共识,实现各节点上 X 值的一致呢?

Raft算法

从本质上说,Raft 算法是通过一切以领导者为准的方式,实现一系列值的共识和各节点日志的一致。这句话比较抽象,我来做个比喻,领导者就是 Raft 算法中的霸道总裁,通过霸道的“一切以我为准”的方式,决定了 日志中命令的值,也实现了各节点日志的一致。Raft 算法是强领导者模型,集群中只能有一个“霸道总裁”。

服务节点由三种身份状态

跟随者:就相当于普通群众,默默地接收和处理来自领导者的消息,当等待领导者心跳 信息超时的时候,就主动站出来,推荐自己当候选人。

候选人:候选人将向其他节点发送请求投票(RequestVote)RPC 消息,通知其他节点 来投票,如果赢得了大多数选票,就晋升当领导者。

领导者:蛮不讲理的霸道总裁,一切以我为准,平常的主要工作内容就是 3 部分,处理 写请求、管理日志复制和不断地发送心跳信息,通知其他节点“我是领导者,我还活 着,你们现在不要发起新的选举,找个新领导者来替代我。

领导者选举过程

每个节点都有一个随机的超时时间,超过这个时间没有收到领导者心跳信号,节点马上变为候选人,并向其他节点发送选举请求,让他们投票自己做领导者。获得投票过半的节点就是领导者,然后不断向其他节点发送心跳。

节点如何通讯?

在 Raft 算法中,服务器节点间的沟通联络采用的是远程过程调用(RPC),在领导者选举 中,需要用到这样两类的 RPC:

  1. 请求投票(RequestVote)RPC,是由候选人在选举期间发起,通知各节点进行投票;
  2. 日志复制(AppendEntries)RPC,是由领导者发起,用来复制日志和提供心跳消息。
  3. 我想强调的是,日志复制 RPC 只能由领导者发起,这是实现强领导者模型的关键之一,希 望你能注意这一点,后续能更好地理解日志复制,理解日志的一致是怎么实现的。

什么是任期?

1.跟随者在等待领导者心跳信息超时后,推举自己为候选人时,会增加自己的任期号,比 如节点 A 的当前任期编号为 0,那么在推举自己为候选人时,会将自己的任期编号增加 为 1。

2.如果一个服务器节点,发现自己的任期编号比其他节点小,那么它会更新自己的编号到 较大的编号值。比如节点 B 的任期编号是 0,当收到来自节点 A 的请求投票 RPC 消息 时,因为消息中包含了节点 A 的任期编号,且编号为 1,那么节点 B 将把自己的任期编 号更新为 1。

3.在 Raft 算法中约定,如果一个候选人或者领导者,发现自己的任期编号比其他节点小, 那么它会立即恢复成跟随者状态。比如分区错误恢复后,任期编号为 3 的领导者节点 B,收到来自新领导者的,包含任期编号为 4 的心跳消息,那么节点 B 将立即恢复成跟 随者状态。

4.还约定如果一个节点接收到一个包含较小的任期编号值的投票请求,那么它会直接拒绝这个请求。比如节点 C 的任期编号为 4,收到包含任期编号为 3 的请求投票 RPC 消息,那它将拒绝这个消息。

5.任期编号相同时,日志完整性高的跟随者(也就是最后一条日志项对应的任期编号值 更大,索引号更大),拒绝投票给日志完整性低的候选人。

随机超时时间

为了防止同一时间,多个节点同时发起选举,跟随者等待领导者心跳信息超时的时间间隔,是随机的。

当没有候选人赢得过半票数,选举无效了,这时需要等待一个随机时间间隔,也就是 说,等待选举超时的时间间隔,是随机的。

Raft的日志

道 Raft 除了能实现一系列值的共识之外,还能实现各节点日志的一致

日志是由日志项组成,日志项是一种数据格式,它主要包含用户指定的数据,也就是指令,比如set x=3, 还包含一些附加信息,比如索引值(Log index)、任期编号(Term)。

{1,set x=1,1} {2,set y=1,1} {3,set x=2,1} {4,set x=5,1} {5,set x=5,1} {6,set x=5,1} {7,set x=5,1} {8,set x=5,1}

指令:一条由客户端请求指定的、状态机需要执行的指令。你可以将指令理解成客户端 指定的数据。

索引值:日志项对应的整数索引值。它其实就是用来标识日志项的,是一个连续的、单 调递增的整数号码。

任期编号:创建这条日志项的领导者的任期编号。

如何复制日志?

优化后的二阶段提交

领导者接收到客户端命令,首先,领导者进入第一阶段,通过日志复制(AppendEntries)RPC 消息,将日志项复制到集群其他节点上。 接着,如果领导者接收到大多数的“复制成功”响应后,它将日志项提交到它的状态机,并返回成功给客户端。如果领导者没有接收到大多数的“复制成功”响应,那么就返回错误给客户端。

学到这里,有同学可能有这样的疑问了,领导者将日志项提交到它的状态机,怎么没通知跟随者提交日志项呢? 这是 Raft 中的一个优化,领导者不直接发送消息通知其他节点提交指定日志项。因为领导者的日志复制 RPC 消息或心跳消息,包含了当前最大的,将会被提交的日志项索引值。所以通过日志复制 RPC 消息或心跳消息,跟随者就可以知道领导者的日志提交位置信息。 因此,当其他节点接受领导者的心跳消息,或者新的日志复制 RPC 消息后,就会将这条日 志项提交到它的状态机。而这个优化,降低了处理客户端请求的延迟,将二阶段提交优化为 了一段提交,降低了一半的消息延迟

1.接收到客户端请求后,领导者基于客户端请求中的指令,创建一个新日志项,并附加到本地日志中

2.领导者通过日志复制 RPC,将新的日志项复制到其他的服务器。

3.当领导者将日志项,成功复制到大多数的服务器上的时候,领导者会将这条日志项提交到它的状态机中。

4.领导者将执行的结果返回给客户端。

5.当跟随者接收到心跳信息,或者新的日志复制 RPC 消息后,如果跟随者发现领导者已经提交了某条日志项,而它还没提交,那么跟随者就将这条日志项提交到本地的状态机中。

如何实现日志的一致?

如果某些节点出现宕机或者网络故障,日志就会出现不一致。

在 Raft 算法中,领导者通过强制跟随者直接复制自己的日志项,处理不一致日志。也就是 说,Raft 是通过以领导者的日志为准,来实现各节点日志的一致的。需要你注意的是,跟随者中的不一致日志项会被领导者的日志覆盖,而且领导者 从来不会覆盖或者删除自己的日志。

Raft成员变更

当往集群增加节点或者减少节点,节点数不同,选举结果可能会不同。