理解Raft协议

最近在学习mit 6.824课程,重新阅读了一些论文,拿本博客记录一下自己的学习。

大名鼎鼎的Paxos算法不少人都听说过,据说世界上有两种一致性算法,一种是Paxos算法,一类的Paxos算法变种。但由于Paxos的晦涩难懂和作者本人一样出名,也非常难以实习。斯坦福的两位教授(Diego Ongaro 和 John Ousterhout)设计了一个效果和Paxos相同但更易理解的算法,它就是Raft算法。想了解算法可以阅读原论文"In search of an Understandable Consensus Algorithm",网上有原文和作者的讲解视频:In Search of an Understandable Consensus Algorithm

Raft 算法概述

raft的首要目标就是容易理解(Understandable), 这从论文的标题就可以看出来。同时在保证这个大前提的下算法的可靠性、可用性和性能不输Paxos算法。

Raft more understandable than Paxos and also provides a better foundation for building practical systems.

为了达成这个这个目标,Raft主要做了两件事情:

  • 问题分解
  • 状态简化

问题分解是把一个主要问题分解成了若干个子问题包括: Leader election, log replication,safety,membership changes;而状态简化是把角色的状态简化为三个: Leader ,Follower,Candidate。

Raft相比Paxos有很多相似之处,但是有这么几个新特性:

  • Strong leader:使用strong leader可以简化管理。例如log entries只从leader流向其他server.
  • Leader election:使用randomized timer来简化选举过程。相比其他共识算法增加了heartbeat机制
  • Membership changes:Raft变更服务器集群的使用了一种新的方法,保证了服务器的配置变更也能继续运行。

Leader election

相比Paxos复杂的角色划分,Raft算法只有三种角色分类:Follower、Candidate和Leader。所有的Server都会在这三种角色中相互转换,转换流程如下:

states.png
fig2.png
  1. 所有节点启动时都是follower状态;
  2. 在一段时间内如果没有收到来自leader的心跳,从follower切换到candidate,发起选举;
  3. 如果收到过半票(含自己的一票)则切换到leader状态;如果发现其他节点日志比自己更新,则主动切换到follower。

系统中最多只有一个Leader,如果在一段时间里发现没有Leader,则大家通过选举-投票选出Leader。Leader会不停的给follower发心跳消息,表明自己的存活状态。如果Leader故障,那么follower会转换成candidate,重新选出Leader。

Term

term.png

Term以选举(election)开始,然后就是一段或长或短的稳定工作期(Normal operation)。从上图可以看到,任期是递增的,这就充当了逻辑时钟的作用;另外,term 3展示了一种情况,就是说没有选举出leader就结束了,然后会发起新的选举,后面会解释这种split vote的情况。

选举启动条件

Follower在Election timeout内没有收到来自leader的心跳,(也许此时还没有选出leader,大家都在等;也许Leader炸了;也许只是leader与该follower之间网线被老鼠咬断了),则会主动发起选举。
步骤

  1. 增加节点本地的 current term ,切换到candidate状态
  2. 投自己一票
  3. 并行给其他节点发送 RequestVote RPCs
  4. 等待其他节点的回复

出现结果

  1. 收到majority的投票(含自己的一票),则赢得选举,成为leader
  2. 被告知别人已当选,那么自行切换到follower
  3. 一段时间内没有收到majority投票,则保持candidate状态,重新发出选举

投票限制

  1. 在任一任期内,单个节点最多只能投一票
  2. 候选人知道的信息不能比自己的少
  3. first-come-first-served 先来先得
election1.png
fig3.png

若有三个节点A B C(上图)。A B同时发起选举,而A的选举消息先到达C,C给A投了一票,当B的消息到达C时,已经不能满足上面提到的第一个约束,即C不会给B投票,而A和B显然都不会给对方投票。A胜出之后,会给B,C发心跳消息,节点B发现节点A的term不低于自己的term,知道有已经有Leader了,于是转换成follower。

election2.png

若没有任何节点获得过半投票,比如上图。则等待超时,引入randomized election timeouts奇数个节点避免

Log replication

Replicated state machines

fig1.png
fig4.png

共识算法基于Replicated state machines来实现,即相同的初识状态 + 相同的输入 = 相同的结束状态

Leader将客户端请求(command)封装到一个个log entry,将这些log entries复制(replicate)到所有follower节点,然后大家按相同顺序应用(apply)log entry中的command,则最终状态肯定是一致的。

fig5.png

请求完整流程

  1. leader append log entry

  2. leader issue AppendEntries RPC in parallel

  3. leader wait for majority response

  4. leader apply entry to state machine

  5. leader reply to client

  6. leader notify follower apply log

由于是远程请求,各个节点的操作都经过RPC实现

Log matching

每个log entry不仅包含client的command还包含log entry的leader term,每个节点不要求完全一致,只求最终一致。未达到最终一致的时候,leader会不断尝试给follower发log entry,直到完全一致

fig8.png

由于server的连接可能出现问题,每个server的log entries都有可能不同,根据下图的情况可以进行分类做log matching:

fig9.png
  • 出现follower的log index比master少或者term比当前term小,则进行额外的log commit
  • log index大于当前index或者term高于当前log entries的,进行log删除
  • log term小于或者不同于当前的term的,进行log覆盖

Safety

Raft通过上面几个属性保障在各类异常情况下仍然正常工作(数据中心被炸不算)

safety.png
fig10.png
fig11.png

Log Compaction

由于Log只执行追加操作,而不进行删除和覆盖,Raft需要定期执行log compaction。snapshot可以分以下情况以提升性能。

compaction.png
  • 定期做日志 snapshot,可使用copy-on-write技术

  • 可以直接保留最新的log index和term

  • Leader执行AppendEntries RPC时,节点log entry落后太多也可以直接发送snapshot

总结

Raft 主要包括两个独立的子问题,Leader election和log replication。流程就是先选举出Leader,然后由Leader负责复制和提交log。
为了保证算法的safety属性,Raft对其子问题加上了诸多约束:

Election restriction:

  • 每个任期的节点在进行投票都只能投一票,原则是先来先到
  • 选举人的信息必须比自己了解的多(term, log replication)

Log replication

  • 一个log可以被复制到大多数节点(committed),且不能被回滚;
  • Leader 一定包含最新的committed log,因此log只会追加而不会覆盖删除;
  • 不同节点,某个位置上日志相同,那么这个位置之前的所有日志一定是相同的;
  • Raft 不能够提交上个任期的log entries。

本文是自己阅读论文和其他博客写的总结。不能全面,假如只是对Raft做一些基本了解。可以看这个演示动画帮助理解,假如想详细了解Raft算法还是需要阅读原文,阅读一下现有的Raft实现。

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

推荐阅读更多精彩内容