raft 系列解读(4) 之 etcd-raft学习

好的实现,看看别人怎么写的,github

大多数Raft的实现都是整体设计,包括存储处理,消息序列化和网络传输,但是本raft库在实现的时候只实现了最核心的算法,换来了灵活性和性能,网络和disk IO部分都由使用者实现,使用者需要实现自己的消息传送层,同时,需要自己实现持久化部分来存储Raft log和state。
为了实现Raft库的可测性,库在实现的时候将Raft建模为一个状态机,输入是消息,可能是本地时间的更新或者网络消息,状态机的输出是一个3元组:{[]Messages, []LogEntries, NextState}。

第一步是使用,怎么使用raft来搭建自己的key-value系统

etcd-raft代码走读

node-run

上面是raft中一个node做的事,Node代表raft集群中的一个节点,刚开始node是follower,然后随着tickc的进行,开始进入选举,raft在变为follower的时候做了下面几件事:
becomeFollower

初始化了tick函数tickElection,用来开始选举,做判断后,调用Step
选举函数

判断消息类型为MsgHup,于是进入campaign
进行选举

选举函数中做的事情
选举

转换成candidate时,开始一个选举:

  1. 递增currentTerm;投票给自己;
  2. 重置election timer;
  3. 向所有的服务器发送 RequestVote RPC请求

成为candidate

接着看下send函数
raft.send

send函数中将消息存储了msgs中,在哪儿消费呢?通过读取newReady来返回Ready
图片

此时又返回到node.run中,此时因为会进入case readyc <- rd分支
图片

在里面做的事情
图片

msgs因为已经读取过了,设置为空,并且会赋值advancec,进行到这readyc中已经有一个数据, 而此channel会在函数Ready中返回给外面,下面接着看谁会去读Ready

func (n *node) Ready() <-chan Ready { return n.readyc }

读取Ready的是应用程序,看下Ready()函数的说明

//=> 读取到当前状态,当从Ready()取出状态后,需要调用 Advance
//=> 注意:只有当所有提交的entries都应用后,才会调用下一个 Ready 的状态

我们回到之前的选举上,读取到的Ready里面包含了Vote消息,我们会调用网络层发送消息出去,并且调用Advance(),而此时其他Node接收到网络层消息后,会调用Step()函数,在成为candidate的时候,我们设置了step函数为stepCandidate

stepCandidate

自后调用了node的send函数,此时是拒绝的,因为已经是candidate状态了,而如果是follower,其处理函数是stepFollower,
stepFollower

其规则就是之前说到的:

如果本地的voteFor为空或者为candidateId,并且候选者的日志至少与接受者的日志一样新,则投给其选票

进行到这,我们看到了follower在收到vote rpc后的处理,下面是candidate的处理了。

回到之前调用Ready(),接着应该调用Advance,

Advance

里面会设置advancec,好了,运行到这,我们又要回到node.run中了

此时的状态是:candidate,advancec中有数据,接着来看candidate在发送出vote rpc,接收到响应的处理,网络层的Send函数是:

Transport.Send

Send会调用Peer.send,函数注释说:此函数是非阻塞的,不保证请求一定能被peer收到
Peer.send

一般常理我们发送后,等待响应后再处理,但是找了很久也没找到常理函数,这个时候,我们再去看下follower对于投票的处理
send.MsgVoteResp

发现在响应上也是通过发送一个消息来响应的,因此我们此时可以看到peer之间的交互不是传统意义上的request-response模型了。

我们去看对于MsgVoteResp的处理,其入口都是通过调用node.Step函数,此时如果得到大多数票选,则成为leader

MsgVoteResp处理

看becomeLeader函数
becomeLeader

在leader函数中,最重要的就是发送命令了,我们看看这个过程

这是通过node.Propose函数实现的

node.Propose

到最后又是通过step函数
stepLeader

里面挨个调用send函数

func (r *raft) bcastAppend() {
    for id := range r.prs {
        if id == r.id {
            continue
        }
        r.sendAppend(id)
    }
}

sendAppend

看完发送端,接着看follower的接收端处理
handleAppendEntries

细看handleAppendEntries函数,就是去做raft协议中规定的操作了
图片

maybeAppend中,会去尝试更新committed index,然后接着看AppendResp的处理
AppendResp

去检查各个peer的matchIndex,然后尝试更新commitIndex

下一个问题,接着去看commitIndex > lastAppied后,在哪儿去应用log到状态机的
这是通过node.runreadycadvancec来实现的

node.run

上面就是etcd中raft的大致流程,有一个机遇raft实现的简单key-value系统,github地址:https://github.com/zhuanxuhit/distributed-system/tree/master/etcd-raft

读完代码后,最大的一个感受是整个node在实现的时候都是无锁的,其技巧是通过go的channel将所有请求串行化,然后另一个特点是根据不同的状态,设置不同的处理函数,整个实现非常的清晰,因为每个状态针对每个请求的处理都是非常明确的。

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

推荐阅读更多精彩内容