Files
MIT6.824/lecture-06-raft1/6.7-leader-xuan-ju-leader-election.md
2022-01-25 02:41:31 +00:00

8.3 KiB
Raw Permalink Blame History

6.7 Leader选举Leader Election

这一部分我们来看一下Leader选举。这里有个问题为什么Raft系统会有个Leader为什么我们需要一个Leader

答案是你可以不用Leader就构建一个类似的系统。实际上有可能不引入任何指定的Leader通过一组服务器来共同认可Log的顺序进而构建一个一致系统。实际上Raft论文中引用的Paxos系统就没有Leader所以这是有可能的。

有很多原因导致了Raft系统有一个Leader其中一个最主要的是通常情况下如果服务器不出现故障有一个Leader的存在会使得整个系统更加高效。因为有了一个大家都知道的指定的Leader对于一个请求你可以只通过一轮消息就获得过半服务器的认可。对于一个无Leader的系统通常需要一轮消息来确认一个临时的Leader之后第二轮消息才能确认请求。所以使用一个Leader可以提升系统性能至2倍。同时有一个Leader可以更好的理解Raft系统是如何工作的。

Raft生命周期中可能会有不同的Leader它使用任期号term number来区分不同的Leader。Followers非Leader副本节点不需要知道Leader的ID它们只需要知道当前的任期号。每一个任期最多有一个Leader这是一个很关键的特性。对于每个任期来说或许没有Leader或许有一个Leader但是不可能有两个Leader出现在同一个任期中。每个任期必然最多只有一个Leader。

那Leader是如何创建出来的呢每个Raft节点都有一个选举定时器Election Timer如果在这个定时器时间耗尽之前当前节点没有收到任何当前Leader的消息这个节点会认为Leader已经下线并开始一次选举。所以我们这里有了这个选举定时器当它的时间耗尽时当前节点会开始一次选举。

开始一次选举的意思是当前服务器会增加任期号term number因为它想成为一个新的Leader。而你知道的一个任期内不能有超过一个Leader所以为了成为一个新的Leader这里需要开启一个新的任期。 之后当前服务器会发出请求投票RequestVoteRPC这个消息会发给所有的Raft节点。其实只需要发送到N-1个节点因为Raft规定了Leader的候选人总是会在选举时投票给自己。

这里需要注意的一点是并不是说如果Leader没有故障就不会有选举。但是如果Leader的确出现了故障那么一定会有新的选举。这个选举的前提是其他服务器还在运行因为选举需要其他服务器的选举定时器超时了才会触发。另一方面如果Leader没有故障我们仍然有可能会有一次新的选举。比如如果网络很慢丢了几个心跳或者其他原因这时尽管Leader还在健康运行我们可能会有某个选举定时器超时了进而开启一次新的选举。在考虑正确性的时候我们需要记住这点。所以这意味着如果有一场新的选举有可能之前的Leader仍然在运行并认为自己还是Leader。例如当出现网络分区时旧Leader始终在一个小的分区中运行而较大的分区会进行新的选举最终成功选出一个新的Leader。这一切旧的Leader完全不知道。所以我们也需要关心在不知道有新的选举时旧的Leader会有什么样的行为

下面这一段实际在Lec 06的65-67分钟出现与这一篇前后的内容在时间上不连续但是因为内容相关就放到这里来了

假设网线故障了旧的Leader在一个网络分区中这个网络分区中有一些客户端和少数未过半的服务器。在网络的另一个分区中有着过半的服务器这些服务器选出了一个新的Leader。旧的Leader会怎样或者说为什么旧的Leader不会执行错误的操作这里看起来有两个潜在的问题。第一个问题是如果一个Leader在一个网络分区中并且这个网络分区没有过半的服务器。那么下次客户端发送请求时这个在少数分区的Leader它会发出AppendEntries消息。但是因为它在少数分区即使包括它自己它也凑不齐过半服务器所以它永远不会commit这个客户端请求它永远不会执行这个请求它也永远不会响应客户端并告诉客户端它已经执行了这个请求。所以如果一个旧的Leader在一个不同的网络分区中客户端或许会发送一个请求给这个旧的Leader但是客户端永远也不能从这个Leader获得响应。所以没有客户端会认为这个旧的Leader执行了任何操作。另一个更奇怪的问题是有可能Leader在向一部分Followers发完AppendEntries消息之后就故障了所以这个Leader还没决定commit这个请求。这是一个非常有趣的问题我将会再花45分钟下一节课来讲。

学生提问有没有可能出现极端的情况导致单向的网络出现故障进而使得Raft系统不能工作

Robert教授我认为是有可能的。例如如果当前Leader的网络单边出现故障Leader可以发出心跳但是又不能收到任何客户端请求。它发出的心跳被送达了因为它的出方向网络是正常的那么它的心跳会抑制其他服务器开始一次新的选举。但是它的入方向网络是故障的这会阻止它接收或者执行任何客户端请求。这个场景是Raft并没有考虑的众多极端的网络故障场景之一。

我认为这个问题是可修复的。我们可以通过一个双向的心跳来解决这里的问题。在这个双向的心跳中Leader发出心跳但是这时Followers需要以某种形式响应这个心跳。如果Leader一段时间没有收到自己发出心跳的响应Leader会决定卸任这样我认为可以解决这个特定的问题和一些其他的问题。

你是对的网络中可能发生非常奇怪的事情而Raft协议没有考虑到这些场景。

所以我们这里有Leader选举我们需要确保每个任期最多只有一个Leader。Raft是如何做到这一点的呢

为了能够当选Raft要求一个候选人从过半服务器中获得认可投票。每个Raft节点只会在一个任期内投出一个认可选票。这意味着在任意一个任期内每一个节点只会对一个候选人投一次票。这样就不可能有两个候选人同时获得过半的选票因为每个节点只会投票一次。所以这里是过半原则导致了最多只能有一个胜出的候选人这样我们在每个任期会有最多一个选举出的候选人。

同时也是非常重要的一点过半原则意味着即使一些节点已经故障了你仍然可以赢得选举。如果少数服务器故障了或者出现了网络问题我们仍然可以选举出Leader。如果超过一半的节点故障了不可用了或者在另一个网络分区那么系统会不断地额尝试选举Leader并永远也不能选出一个Leader因为没有过半的服务器在运行。

如果一次选举成功了整个集群的节点是如何知道的呢当一个服务器赢得了一次选举这个服务器会收到过半的认可投票这个服务器会直接知道自己是新的Leader因为它收到了过半的投票。但是其他的服务器并不能直接知道谁赢得了选举其他服务器甚至都不知道是否有人赢得了选举。这时赢得了选举的候选人会通过心跳通知其他服务器。Raft论文的图2规定了如果你赢得了选举你需要立刻发送一条AppendEntries消息给其他所有的服务器。这条代表心跳的AppendEntries并不会直接说我赢得了选举我就是任期23的Leader。这里的表达会更隐晦一些。Raft规定除非是当前任期的Leader没人可以发出AppendEntries消息。所以假设我是一个服务器我发现对于任期19有一次选举过了一会我收到了一条AppendEntries消息这个消息的任期号就是19。那么这条消息告诉我我不知道的某个节点赢得了任期19的选举。所以其他服务器通过接收特定任期号的AppendEntries来知道选举成功了。