理解raft(2) 日志复制

Raft保证的safety

Leader Append-Only:leader从来不覆写或者删除日志,只会追加新日志。

Log Matching:如果两个主机的副本上的日志文件中,包含一条相同term和log id的entry,那么,这两个日志文件在这条日志之前的内容都是相同的(字节流级别的一致)。

Leader Completeness:如果一条日志已经commit了,那么这条日志一定会出现在term最大的leader的日志文件中。

State Machine Safety:如果一个主机应用了一条日志,那么,其他主机不可能应用一条相同log id而内容却不同的日志。

初选Leader后的日志同步

当一个新的Leader被选出来时,它的日志和其它的Follower的日志可能不一样,这个时候,就需要一个机制来保证日志的一致性。

主备不一致可能有如下几种情况:少了一些日志(term可能相同或者少了);多了一些未commit的日志(term可能多了也可能少了);某些term多了一些日志且某些term少了一些日志。Raft中如何解决这些不一致呢?leader强制让follower的日志文件复制leader的日志文件,即follower上不一致的日志文件内容被覆写

首先记住一个前提, raft选举保证选出来得leader拥有最新最多commit的日志。

因此leader只需要知道follower缺哪些日志(确定最后一条相同的日志),就可以主动给follower同步所缺的日志,follower只要覆盖掉不一致的部分即可。

如何确定不一致的点?

leader维护一个log id,初始为leader本地最大的log id,然后发送AppendEntries RPC到follower,follower在收到AppendEntries之后,检查RPC中携带的term和log id(leader上被追加的这条日志的前面一条日志的term和log id),如果follower本地没有这条日志,就拒绝此次AppendEntriesRPC,leader就能知道follower的同步点更靠前,逐渐就能知道同步点的位置。当然,实际实现时,会使用更有效率的方法。

例如,当附加日志 RPC 的请求被拒绝的时候,跟随者可以包含冲突的条目的任期号和自己存储的那个任期的最早的索引地址。借助这些信息,领导人可以减小 nextIndex 越过所有那个任期冲突的所有日志条目;这样就变成每个任期需要一次附加条目 RPC 而不是每个条目一次。在实践中,我们十分怀疑这种优化是否是必要的,因为失败是很少发生的并且也不大可能会有这么多不一致的日志。

image
  1. 在阶段a,term为2,S1是Leader,且S1写入日志(term, index)为(2, 2),并且日志被同步写入了S2;

  2. 在阶段b,S1离线,触发一次新的选主,此时S5被选为新的Leader,此时系统term为3,且写入了日志(term, index)为(3, 2);

  3. S5尚未将日志推送到Followers变离线了,进而触发了一次新的选主,而之前离线的S1经过重新上线后被选中变成Leader,此时系统term为4,此时S1会将自己的日志同步到Followers,按照上图就是将日志(2, 2)同步到了S3,而此时由于该日志已经被同步到了多数节点(S1, S2, S3),因此,此时日志(2,2)可以被commit了(即更新到状态机);

  4. 在阶段d,S1又很不幸地下线了,系统触发一次选主,而S5有可能被选为新的Leader(这是因为S5可以满足作为主的一切条件:1. term = 3 > 2, 2. 最新的日志index为2,比大多数节点(如S2/S3/S4的日志都新),然后S5会将自己的日志更新到Followers,于是S2、S3中已经被提交的日志(2,2)被截断了,这是致命性的错误,因为一致性协议中不允许出现已经应用到状态机中的日志被截断。(论文描述)

这个问题的本质是,S1上的term=2,log id=2的日志,在进行复制时,使用的term仍然是term=2,而不是S1最新的term(4)。在本地term较大的时候去复制term小的日志,这个是不合理的。但是为了维持Leader Append-Only的性质,只能想办法解决。

为了避免这种致命错误,需要对协议进行一个微调:

只允许主节点提交包含当前term的日志

针对上述情况就是:即使日志(2,2)已经被大多数节点(S1、S2、S3)确认了,但是它不能被Commit,因为它是来自之前term(2)的日志,直到S1在当前term(4)产生的日志(4, 3)被大多数Follower确认,S1方可Commit(4,3)这条日志.

commit的时候并不需要发给followers,commit就是回复client。 leader只允许commit当前term的entry,其实是指积压着之前已经被majority认可的entry,直到当前term也被majority认可,然后统一commit。

日志压缩与快照

在实际的系统中,不能让日志无限增长,否则系统重启时需要花很长的时间进行回放,从而影响availability。Raft采用对整个系统进行snapshot来处理,snapshot之前的日志都可以丢弃。Snapshot技术在Chubby和ZooKeeper系统中都有采用。

Raft使用的方案是:每个副本独立的对自己的系统状态进行Snapshot,并且只能对已经提交的日志记录(已经应用到状态机)进行snapshot。

Snapshot中包含以下内容:

  • 日志元数据,最后一条commited log entry的 (log index, last_included_term)。这两个值在Snapshot之后的第一条log entry的AppendEntriesRPC的consistency check的时候会被用上,之前讲过。一旦这个server做完了snapshot,就可以把这条记录的最后一条log index及其之前的所有的log entry都删掉。

  • 系统状态机:存储系统当前状态(这是怎么生成的呢?)

snapshot的缺点就是不是增量的,即使内存中某个值没有变,下次做snapshot的时候同样会被dump到磁盘。当leader需要发给某个follower的log entry被丢弃了(因为leader做了snapshot),leader会将snapshot发给落后太多的follower。或者当新加进一台机器时,也会发送snapshot给它。发送snapshot使用新的RPC,InstalledSnapshot。

做snapshot有一些需要注意的性能点,1. 不要做太频繁,否则消耗磁盘带宽。 2. 不要做的太不频繁,否则一旦节点重启需要回放大量日志,影响可用性。系统推荐当日志达到某个固定的大小做一次snapshot。3. 做一次snapshot可能耗时过长,会影响正常log entry的replicate。这个可以通过使用copy-on-write的技术来避免snapshot过程影响正常log entry的replicate。

客户端命令执行过程

  1. 当Leader被选出来后,即可接受客户端发来的请求,每个请求包含一条需要被状态机执行的命令。leader会把它作为一个log entry append到日志中,然后给其它的server发AppendEntriesRPC请求。

  2. 当Leader确定一个log entry被safely replicated了(大多数副本已经将该命令写入日志当中),就apply这条log entry到状态机中然后返回结果给客户端。

  3. 如果某个Follower宕机了或者运行的很慢,或者网络丢包了,则会一直给这个Follower发AppendEntriesRPC直到日志一致。

当一条日志是commited时,Leader才可以将它应用到状态机中。Raft保证一条commited的log entry已经持久化了并且会被所有的节点执行。

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

推荐阅读更多精彩内容

  • 最近看了Ongaro在2014年的博士论文《CONSENSUS: BRIDGING THEORY AND PRAC...
    山本聪阅读 4,572评论 3 11
  • Raft是一种为了管理日志复制的一致性算法。它提供了和Paxos算法相同的功能和性能,但是它的算法结构和Paxos...
    WithLin阅读 782评论 0 1
  • 1 整体描述 在Raft被提出来之前,Paxos协议是第一个被证明的一致性算法,但是Paxos的论文非常难懂,导致...
    船_长阅读 7,181评论 0 7
  • 前言 这是一篇学习raft论文的总结,主要是对看论文过程中难以理解的几个问题的记录。系统性的讲解还是得看raft论...
    asmer阅读 14,371评论 3 38
  • 这篇文章实际上并不是我在阅读etcd中跟Raft相关的部分之后得出的,而是我在读了ZooKeeper中Zab的实现...
    AlstonWilliams阅读 1,487评论 0 1