经过调试发现,视频代码主要有几个问题:

  1. startReplication 落了一个返回值
  2. 日志打印有点问题
  3. GetState 函数没有实现。
  4. becomeCandidateLocked 没有调用 resetElectionTimerLocked(视频里没说)

Raft 的细节是非常多的,即使我实现过很多次,也很容易因为粗心或者忘记细节造成问题。所以有错不可怕,关键是掌握科学的调试方法,可以参考 0x02. [附录2分布式调试]。

实现关键点

下面我罗列一些 PartA 实现的关键点,如果出错,可能会造成测试通不过:

  1. 重置时钟本质上是认可对方权威,且承诺自己之后一段时间内不在发起选举。在代码中有两处:

    1. 接收到心跳 RPC,并且认可其为 Leader
    2. 接受到选举 RPC,并且给出自己的选票
  2. 在收到 RPC(回调函数)和收到 RPC 返回值时,第一件事就是要对齐 term。在 Raft 中,term 是一个非常关键的设定,只有在相同 term 内,一切对话才能展开。对齐 term 的逻辑就是:

    1. 你 term 大,我无条件转 Follower
    2. 你 term 小,不理会你的请求
  3. role 字段在 figure 2 是没有列的,但是实现时是需要的,而且很核心。

  4. 所有访问全局变量的逻辑都要加锁。

  5. 我们在新进入一个 term 时,逻辑可以归结为:

    1. 主动的:成为 Candidate,vote 给自己。具体来说,自己选举 timer 超时,增加 term ,转换为 Candidate

    2. 被动的:成为 Follower,vote 设置空。具体来说,通过 RPC 发现对方 term 高,转换为 Follower,follow 对方 term。

    3. 换种说法,角色状态机的转换往往和 term 的变化存在着联系。两个特例 :

      1. Candidate 当选 Leader 时,term 没有发生变化。
      2. Candidate 在发现同 term 的 Leader 时,变成 Follower,term 也不变。
  6. 写完之后,要对着状态机过一遍,主要就是看几个 become 函数的状态转换是否符合状态机,并在状态转换前做好了状态检查。

Q&A

  1. 为什么 tick 的 interval(也就是 sleep) 也是 random 的?不是仅仅 election timeout 需要 random 的吗?
    1. 因为如果 tick 的 interval 不 random 可能会造成,即使 electionTimeout 是 random 的,但由于 tick 是固定间隔导致最后不同 Peer 检测到选举超时的间隔仍然是固定的。