参考:http://www.infoq.com/cn/articles/raft-paper#
领导选举:
当服务器启动时,它们会初始化为追随者。
追随者服务器会一直保持追随者的状态只要它们能够收到来自领导人或者候选人的有效 RPC。
领导人会向所有追随者周期性发送心跳(heartbeat,不带有任何日志条目的 AppendEntries RPC)来保证它们的领导人地位。
如果一个追随者在一个周期内没有收到心跳信息,就叫做选举超时(election timeout),然后它就会假定没有可用的领导人并且开始一次选举来选出一个新的领导人。
为了开始选举,一个追随者会自增它的当前任期并且转换状态为候选人。然后,它会给自己投票并且给集群中的其他服务器发送 RequestVote RPC。
一个候选人会一直处于该状态,直到下列三种情形之一发生:
- 它赢得了选举;
- 另一台服务器赢得了选举;
- 一段时间后没有任何一台服务器赢得了选举
情况1:一个候选人如果在一个任期内收到了来自集群中大多数服务器的投票就会赢得选举。按照先到先服务原则,一台服务器最多能给一个候选人投票。一旦有一个候选人赢得了选举,它就会成为领导人。然后它会像其他服务器发送心跳信息来建立自己的领导地位并且组织新的选举。
情况2:当一个候选人等待别人的选票时,它有可能会收到来自其他服务器发来的声明其为领导人的 AppendEntries RPC。如果这个领导人的任期(包含在它的 RPC 中)比当前候选人的当前任期要大,则候选人认为该领导人合法,并且转换自己的状态为追随者。如果在这个 RPC 中的任期小于候选人的当前任期,则候选人会拒绝此次 RPC, 继续保持候选人状态。
情形3:是一个候选人既没有赢得选举也没有输掉选举:如果许多追随者在同一时刻都成为了候选人,选票会被分散,可能没有候选人能获得大多数的选票。当这种情形发生时,每一个候选人都会超时,并且通过自增任期号和发起另一轮 RequestVote RPC 来开始新的选举。然而,如果没有其它手段来分配选票的话,这种情形可能会无限的重复下去。
每一个候选人在开始一次选举的时候会重置一个随机的选举超时时间,在超时进行下一次选举之前一直等待。
选举是一个理解性引导我们设计替代算法的一个例子。最开始时,我们计划使用一种排名系统:给每一个候选人分配一个唯一的排名,用于在竞争的候选人之中选择领导人。如果一个候选人发现了另一个比它排名高的候选人,那么它会回到追随者的状态,这样排名高的候选人会很容易地赢得选举。但是我们发现这种方法在可用性方面有一点问题(一个低排名的服务器在高排名的服务器宕机后,需要等待超时才能再次成为候选人,但是如果它这么做的太快,它能重置选举领带人的过程)。我们对这个算法做了多次调整,但是每次调整后都会出现一些新的问题。最终我们认为随机重试的方法是更明确并且更易于理解的。
日志复制
一旦选出了领导人,它就开始接收客户端的请求。每一个客户端请求都包含一条需要被复制状态机(replicated state machine)执行的命令。领导人把这条命令作为新的日志条目加入到它的日志中去,然后并行的向其他服务器发起 AppendEntries RPC ,要求其它服务器复制这个条目。当这个条目被安全的复制之后(下面的部分会详细阐述),领导人会将这个条目应用到它的状态机中,并且会向客户端返回执行结果。如果追随者崩溃了或者运行缓慢或者是网络丢包了,领导人会无限的重试 AppendEntries RPC(甚至在它向客户端响应之后)直到所有的追随者最终存储了所有的日志条目。
参考:http://blog.csdn.net/dapangzi88/article/details/54866422
Raft 的目标是将日志完整地复制到集群内的所有服务器,这些复制的日志会被状态机所使用。假设我们希望程序或应用能可靠地执行,能够实现的一种方式是保证集群中所有服务器内的状态机都能按照相同的方式执行命令,这就是状态机复制同步的目的,这里的状态机通常指的是一个输入输出程序或应用。日志可以保证状态机执行相同的命令。下面介绍它的运作机制。
如果系统的客户端将要执行的命令传递给集群中的一台服务器,假设命令是 X ,那么它会被该台服务器记录,然后命令会被发送到其他服务器,并被其他服务器上的日志所记录。一旦命令被安全的复制到日志中,那么它们就能被发送到状态机供执行。当其中的一台状态机完成了命令的执行,结果会被返回给客户端。可以注意到只要各个服务器上的日志是相同的,各个服务器上的状态机就能以相同的顺序执行相同的命令,这样它们执行的结果也都是一样的。所以共识性模块的任务就是管理这些日志,并保证它们正确的在集群内复制并且决定何时将命令传送给状态机才是安全的。
普通操作比较简单,客户端将命令发送给领导者,领导者首先将命令写入它自己的日志中,然后向所有其他的跟随者发送 AppendEntries 的远程调用。通常这些调用的消息会被同时发送所有服务器,以并行的方式执行,并等待这些消息的响应。一旦领导者收到足够多的响应,可以它认为该条命令已经在多数服务器上处于已提交状态时,那么该条命令就可以被执行。领导者这时会将命令发送给状态机,当执行结束后,它会将结果返回给客户端。不仅如此,一旦服务器知道某个记录已经处于提交状态,它就会通过后续的 AppendEntries 远程调用告知其他的服务器。所以最终,每个跟随者都会知道该记录已提交,并且将该命令发送至自己本地的状态机执行。如果跟随者崩溃了或处于慢响应状态,领导者会反复重试这个调用,直到跟随者恢复后,领导者就能重试成功。但是领导者并不需要等待每个跟随者的响应,它只需要等到足够数量的响应,保证记录已被大多数服务器存储即可。所以这样就能在一般情况下获得很好的性能提升。也就是说,在通常情况下,只需要获得大多数最快的服务器的应答,领导者就可以立即执行命令,并将结果返回至客户端。例如,如果某个服务器很慢,这并不能影响客户端获得响应的速度,因为领导者并不需要一直等待该台服务器。
领导选举时leader crash时?
参考:https://www.cnblogs.com/mindwind/p/5231986.html
Raft 要求 RPC 请求实现幂等性,也就是要实现内部去重机制。