raft 学习笔记(6.824 Lab 2)

raft 学习笔记

最近在学习 6.824 的分布式课程.
学习到 Raft 算法. 写篇文章作为记录.

什么是 Raft

Raft 是一个用于管理分布式副本一致性的算法, 设计的目的是为了使分布式一致性更加容易理解和实现.

算法细节

目前实现的 Raft 算法主要包含两个部分, 一个是领导者选举, 另外一个是日志复制.

领导者选举

在 Raft 算法中存在三种角色, 领导者/候选人/跟随者. 有两个时间的概念, 心跳时间(固定时间)/选举超时时间(随机时间).
在初始状态下, 所有的角色都是候选人, 等到选举超时时间到的时候发起选举投票, 如果得到半数以上的选票则变为领导者.

当角色变成领导者之后要立即对所有的成员发起心跳请求, 以巩固领导者的地位(阻止其他成员继续发起投票请求). 如果一个
成员收到了心跳请求, 则变成跟随者角色, 并作出响应.

日志复制

日志复制的的请求使伴随在心跳请求中的, 也就是说如果存在没有同步给其他成员的日志, 则在心跳的时候附带上这些日志.
对于客户端的请求, 只有复制到大多数成员的时候才认为这个请求使可提交的状态, 领导者提交之后也要通知其他成员提交.

Raft 算法实现

在 6.824 的课程当中提供了一个骨架以及一些测试用例, 目标是实现提供的接口, 最终通过所有的测试. 下面是论文中的实现方式.

所有服务器都需要存储的状态

在回复 RPCs 的响应之前保存到磁盘

  1. currentTerm 服务器所经历的最后一届领导人 (初始化为 0, 单调递增)
  2. votedFor 当前任期(上面的currentTerm)获取投票的候选人ID
  3. log[] log队列, 每个log实体包含一个给状态机的命令和领导人收到时的任期号(第一个索引号为1)

所有服务器变化的状态

  1. commitIndex 服务器知道的最高的应该提交的log实体编号(初始化为 0, 单调递增).
  2. lastApplied 服务器应用到状态机的log实体最高编号(初始化为0, 单调递增)

领导人经常变化的状态

赢得选举之后需要重新初始化.

  1. nextIndex[] 维护每个服务器下一个需要发送的log实体的编号(初始化为领导人最新的log实体编号 加 1).
  2. matchIndex[] 维护每个服务器得到确认的最大log实体编号.

所有成员需要实现的接口(RPC)

请求选举的 RPC

用于候选人调用获得选票

参数列表
  1. term 候选人的任期号
  2. candidateId 候选人ID
  3. lastLogIndex 候选人的最新log实体的编号.
  4. lastLogTerm 候选人的最新log实体的任期号
返回值
  1. term 当前任期号(currentTerm), 用于候选人更新自己
  2. voteGranted true 表示投票给该候选人
接受者的实现
  1. 如果 term < currentTerm 返回 false.
  2. 如果 votedFor 状态为空, 或者为请求中的 candidateId, 并且候选人的 log 至少跟接受者的日志一样新, 则投出选票 true, 否则 false.

复制 log 的 RPC

用于领导人调用来复制log实体. 也用于维持心跳.

参数列表
  1. term 领导人的任期号
  2. leaderId 领导人 ID, 用于跟随者可以转发请求
  3. prevLogIndex 上一个 log 的索引号.
  4. prevLogTerm 上一个 log 的任期号.
  5. entries[] 需要存储的 log (心跳的这个字段为空; 为了提高效率可能会发送多个)
  6. leaderCommit 领导人的 commitIndex
返回值
  1. term 当前任期(currentTerm), 用于领导人更新自己
  2. success 如果接受者存在与 prevLogIndex 和 prevLogTerm 匹配的日志则返回 true
接收者实现
  1. 如果 term < currentTerm 返回 false.
  2. 如果接收者的log队列中不包含与 prevLogIndex 和 prevLogTerm 匹配的日志, 返回 false.
  3. 如果接收者存在一个 log 与发来的 log prevLogIndex 匹配但是 prevLogTerm 不匹配, 则删掉这个 log 及之后所有的 log.
  4. 把所有不存在于 log 队列中的 log, 添加到队列中
  5. 如果 leaderCommit > commitIndex, 则 commitIndex = min(leaderCommit, 新发来的 log 的 index)

所有服务器都应该遵守的规则

所有服务器

  1. 如果 commitIndex > lastApplied, 增加 lastApplid, 应用 log[lastapplied] 到状态机中
  2. 如果 RPC 请求或者响应当中包含的任期 T > currentTerm, 则 currentTerm = T, 并且自己转换到跟随者状态.

跟随者

  1. 响应来自候选人和领导人的 RPC.
  2. 如果选举时间超时, 并且没有收到附加日志(或者心跳)的 RPC, 也没用收到选举请求, 则自己转变为候选人

候选人

  1. 当转变为候选人的时候, 开始选举:
    1. 增加currentTerm
    2. 给自己投票
    3. 重置选举超时计时器
    4. 发送 RequestVote RPC 给所有服务器
  2. 如果收到大多数服务器的支持选票则变为领导人
  3. 如果收到了一个新的领导人的附加日志的RPC 或者 心跳, 则转变为跟随者
  4. 如果选举超时, 开始一轮新的选举(跳转到步骤 1)

领导人

  1. 赢得选举之后不断发送心跳给所有的服务器, 防止超时
  2. 如果收到客户端命令: 首先添加到本地的日志队列, 在应用到状态机之后应答客户端.
  3. 如果最新的log编号>= 跟随者的 nextIndex 编号: 从 nextIndex 索引号开始发送附加log的 RPC.
    1. 如果成功: 更新跟随者的 nextIndex 和 matchIndex
    2. 如果因为 log 不匹配而失败: 减小 nextIndex 的值并且重试.
  4. 如果存在一个 N, 这个 N 满足: N > commitIndex, 并且 大多数跟随者的 matchIndex[i] >= N, 并且 log[N].term == currentTerm, 那么就让 commitIndex = N.

现在只实现了选举和日志复制两部分内容, 关于集群的变更等内容后续会继续实现, 课程中后续还会基于这个实现的基础上
来实现一个分布式的 KV存储.

最后附上代码地址: https://gist.github.com/icodinglife/910869da89a2e62a1b4deae994fb8d0b

由于刚刚接触 golang, 对于一些用法还不是太熟悉, 代码中有一些比较丑陋或者错误的设计和用法, 后续随着不断熟悉和深入
会慢慢重构掉. 欢迎大家讨论拍砖提意见 : )

欢迎打赏, 鼓励我坚持下去~~~ : )

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容