raft协议学习笔记

此文为自己学习笔记,结构很凌乱。如果大家想学习具体的细节,可以到本文引用的网址下进行学习。

初学者可以先看一下这个博客,理解起来比较轻松。但是细节讲的不深刻。

然后能够翻墙,英语ok的话,强烈推荐Youtube的一个视频

看完这个视频,可能还有一些疑问,在看一下一个很详细的学习笔记,这时候读起来应该轻松很多很多了。

 

正文是对YouTube视频的学习笔记

一、Leader Election

首先,每个server都有一个唯一状态,follower,candidate,leader

raft将时间分段,每个时间段是一个term,里面有一个term number唯一标示。

 

 

这里说明一下,Leader有一个broadcast time,来广播log entry(或 heartbeat)以维护自己的统治地位。

RPC有三种:

1.  RequestVote RPC:候选人在选举期间发起

2.  AppendEntries RPC:领导人发起的一种心跳机制,复制日志也在该命令中完成

3.  InstallSnapshot RPC: 领导者使用该RPC来发送快照给太落后的追随者。

超时设置:

1.  BroadcastTime : 领导者的心跳超时时间

2.  Election Timeout: 追随者设置的候选超时时间

3.  MTBT :指的是单个服务器发生故障的间隔时间的平均数

Raft协议对物理是时钟一致性没有要求,不需要通过原子钟NTP来校准时间,但是对于超时时间的设置有要求,具体规则如下:

BroadcastTime << ElectionTimeout << MTBF

两个原则:

    1. BroadcastTime应该比ElectionTimeout小一个数量级,为的是使领导人能够持续发送心跳信息(heartbeat)来阻止追随者们开始选举;
    1. ElectionTimeout也要比MTBF小几个数量级,为的是使得系统稳定运行。

一般BroadcastTime大约为0.5毫秒到20毫秒,ElectionTimeout一般在10ms到500ms之间。大多数服务器的MTBF都在几个月甚至更长。

所以在这里,如果一个follower,在Election Timeout时间段内多没有接到leader的RPC,也没有接到其他candidate的voteRequestRPC,他就会苏醒,然后变成candidate状态,希望成为leader,如果在一个term中,没有竞选出leader,那么为了下一个term一定能竞选出leader,他们会变换自己的Election Timeout,使得自己在不同时候苏醒竞争leader,这样苏醒早的就有竞争优势。同时,一个follower在为其他人投票以后,会把自己的投票状态记录在disk中,这样即使,一段时间以后这个server挂了,然后苏醒过来,也会发现自己的已投票状态,不会为其他请求投票。这样就严格保证了,每个server只能投一票。

这一步的作用是为了保证log的一致性,所以在新加一个log时,必须检查leader发过来的log的前一条是否和自己是一致的,如果是一致的,那么就添加。如果不是的话,需要拒绝,然后leader逐个向前递推,直到找到正确的log。

 

这里出现了一个问题,如果一个lead在committed了一个log以后,如果这个leader crash掉了 ,然后选举了一个新的leader,这时候可能这个leader并没有commit这个log,也就不满足raft条件了。

例子如下:

在Raft算法中,当一个日志被安全的复制到绝大多数的机器上面,即AppendEntries RPC在绝大多数服务器正确返回了,那么这个日志就是被提交了,然后领导者会更新commit index。

image.png

详细解释如下:

a场景:s1是leader,此时处于term2,并且将index为2的entry复制到s2上

b场景:s1挂了,s5利用s3,s4,s5当选为leader,处于term3,s5在index为2的位置上接收到了新的entry

c场景:s5挂了,s1当选为leader,处于term4,s1将index为2,term为2的entry复制到了s3上,此时已经满足过半数了

重点就在这里:此时处于term4,但是之前处于term2的entry达到过半数了,s1是提交该entry呢还是不提交呢?

  • 假如s1提交的话,则index为2,term为2的entry就被应用到状态机中了,是不可改变了,此时s1如果挂了,来到term5,s5是可以被选为leader的,因为按照之前的log比对策略来说,s5的最后一个log的term是3比s2 s3 s4的最后一个log的term都大。一旦s5被选举为leader,即d场景,s5会复制index为2,term为3的entry到上述机器上,这时候就会造成之前s1已经提交的index为2的位置被重新覆盖,因此违背了一致性。

  • 假如s1不提交,而是等到term4中有过半的entry了,然后再将之前的term的entry一起提交(这就是所谓的间接提交,即使满足过半,但是必须要等到当前term中有过半的entry才能跟着一起提交),即处于e场景,s1此时挂的话,s5就不能被选为leader了,因为s2 s3的最后一个log的term为4比s5的3大,所以s5获取不到投票,进而s5就不可能去覆盖上述的提交

从这个案例中我们得到的一个新约束就是:

当前term的leader不能“直接”提交之前term的entries 必须要等到当前term有entry过半了,才顺便一起将之前term的entries进行提交

所以raft靠着这2个约束来进一步保证一致性问题。

再来仔细分析这个案例,其问题就是出在:上述leader选举上,s1如果在c场景下将index为2、term为2的entry提交了,此时s5也就不包含所有的commitLog了,但是s5按照log最新的比较方法还是能当选leader。

那就是说log最新的比较方法并不能保证2中的选举约束即
被选举出来的leader必须要包含所有已经提交的entries
所以可以理解为:正是由于上述选举约束实现上的简单实现并不靠谱, 才导致又加了这么一个不能直接提交之前term的entries的约束。

 

如果一个leader宕机以后又恢复了,但是这时已经有了一个新的leader了怎么办?

 

Client行为

如果leader commit了一条指令,但是未来得及回复client就宕机了,client会再次发送同一个command,这是如何保证command只执行一次?

 

集群成员变更

集群成员的变更和成员的宕机与重启不同,因为前者会修改成员个数进而影响到领导者的选取和决议过程,因为在分布式系统这对于majority这个集群中成员大多数的概念是极为重要的。

简单的做法是,运维人员将系统临时下线,修改配置,重新上线。但是这种做法存在两个缺点:

1.  更改时集群不可用

2.  人为操作失误风险

直接从一种配置转到新的配置是十分不安全的

如下图所示:

因为各个机器可能在任何的时候进行转换。在这个例子中,集群配额从 3 台机器变成了 5 台。不幸的是,存在这样的一个时间点,两个不同的领导人在同一个任期里都可以被选举成功。一个是通过旧的配置,一个通过新的配置。

两阶段方法保证安全性:

  • 在 Raft 中,集群先切换到一个过渡的配置,我们称之为共同一致(joint consensus)
    一旦共同一致已经被提交了,那么系统就切换到新的配置上。共同一致是老配置和新配置的结合。

  • 共同一致允许独立的服务器在不影响安全性的前提下,在不同的时间进行配置转换过程。此外,共同一致可以让集群在配置转换的过程中依然响应服务器请求。

一个领导人接收到一个改变配置从 C-old 到 C-new 的请求,他会为了共同一致存储配置(图中的 C-old,new),以前面描述的日志条目和副本的形式。一旦一个服务器将新的配置日志条目增加到它的日志中,他就会用这个配置来做出未来所有的决定。领导人完全特性保证了只有拥有 C-old,new 日志条目的服务器才有可能被选举为领导人。当C-old,new日志条目被提交以后,领导人在使用相同的策略提交C-new,如下图所示,C-old 和 C-new 没有任何机会同时做出单方面的决定,这就保证了安全性。

 

一个配置切换的时间线。虚线表示已经被创建但是还没有被提交的条目,实线表示最后被提交的日志条目。领导人首先创建了 C-old,new 的配置条目在自己的日志中,并提交到 C-old,new 中(C-old,new 的大多数和 C-new 的大多数)。然后他创建 C-new 条目并提交到 C-new 中的大多数。这样就不存在 C-new 和 C-old 可以同时做出决定的时间点。

为什么需要弄这样一个两阶段协议,而不能直接从Cold切换至Cnew?

这是因为,如果直接这么简单粗暴的来做的话,可能会产生多主。简单说明下:

假设Cold为拓扑为(S1, S2, S3),且S1为当前的Leader,如下图:

假如此时变更了系统配置,将集群范围扩大为5个,新增了S4和S5两个服务节点,这个消息被分别推送至S2和S3,但是假如只有S3收到了消息并处理,S2尚未得到该消息

这时在S2的眼里,拓扑依然是<S1, S2, S3>,而在S3的眼里拓扑则变成了<S1, S2, S3, S4, S5>。假如此时由于某种原因触发了一次新的选主,S2和S3分别发起选主的请求:

最终,候选者S2获得了S1和S2自己的赞成票,那么在它眼里,它就变成了Leader,而S3获得了S4、S5和S3自己的赞成票,在它眼里S3也变成了Leader,那么多Leader的问题就产生了。而产生该问题的最根本原因是S2和S3的系统视图不一致。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值