白话Raft算法

能PK Paxos算法的Raft算法,综合了业界常见的设计思路


引子

一致性算法在分布式节点时代是基础算法之一,由于Paxos历史悠久且难以理解,所以standford的两位大佬忍不下去攒出了个Raft,嗯,目前业界常见的一些设计思路的综合体吧。
要理解算法最简单就是知道要解决啥问题,分布式一致性要解决的问题无非就是:这儿有一堆节点,上面有数据,一起存储数据并提供服务,这时

  • 客户端访问到其中一个节点,然后这节点怎么处理请求呢?
  • 节点要是down掉咋弄?服务停不停了?数据还丢不丢了?突然又起来了大家怎么看它?
  • 突然网络分区了,节点之间又是啥关系?服务停不停了?节点之间分歧了,当分区恢复了,节点又是啥关系,大家的数据怎么保证一致呢?

基本设计

某个节点内部:

白话Raft算法_第1张图片
叫Replicated state machine,其实就是内存中有个状态机,从本地磁盘中读日志执行,只要每个节点日志一样,那么所有节点最后own的数据都一样,那怎么保证一样呢?就是那个Consensus模块来保证每个节点一致了,由于日志不怕down机,所以节点挂了重启一样的,关键就是维护日志一样了

节点之间关系与角色、沟通

嗯,为了简单,有些一致性算法有多主,这样不好搞,太复杂。Raft就一主多从只有Leader才代表集群与客户端通信啦,Follow只和集群内部节点通信或接受Leader的同步,客户端联系Follow,请求也会被转发给Leader。当然,开始大家平等的,通过选举产生leader,且有任期term,选举过程中大家都是candidate,所以一共有三种角色:

  • Leader
  • Follower
  • Candidate
    并且每个节点在线一定是其中一种角色,互相转换
    白话Raft算法_第2张图片
    节点间的交流是通过RPC进行的。只需要实现两种RPC就能构建一个基本的Raft集群:
  • RequestVote RPC:它由选举过程中的candidate发起,用于拉取选票
  • AppendEntries RPC:它由leader发起,用于复制日志或者发送心跳信号
    白话Raft算法_第3张图片
    白话Raft算法_第4张图片
    最后还有一种压缩日志RPC
    白话Raft算法_第5张图片
  • term任期:
    白话Raft算法_第6张图片
    Raft算法的整个周期就是一轮轮的任期时间,能保证每个任期内有且只有一个Leader存在,我理解任期结束一般都是因为Leader挂了
选举过程

其实设计和黑帮一样:一群节点,每个节点拥有的log和term数就是每个节点的资质/实力,只有一个老大,老大才有对外话语权,跟班们就同步老大的动作,而每个跟班都见势想成为老大,平时老大只能压着他们,并让他们同步自己的动作,老大挂了,跟班们就开始拉选票,快的先下手为强收集最多选票的成为老大,继续压着跟班们,如果分家了(分区),集群就产生不同的老大,合并了,老大比一比自己的资质,PK出新老大,旧老大下台…这只是大概过程,其中算法具体细节其实在人类群体中都能对应上

来看看具体细节吧
有个前提是网络开始大家内存里都有彼此的通信地址,并且正常情况节点之间网络传输速度肯定有点差异

开始大家都是Follower,任期数都是0,然后每个节点设置随机150ms~300ms的Election Timeouts定时器,如果到点了就开始转变为Candidate,重启定时器、自己任期数先加1、投自己一票,然后向每个节点发送RequestVote RPC拉选票
Raft规定每个节点只要收到选票,如果没投过且自己的任期数不大于选票中的任期数且自己的日志标记不比选票中日志标记新,就接受选票,回同意,自己变成follower

最后这么就会出现两种情况:

  • 理想状况是当然早下手的和网络好的节点肯定最先收集到过半(集群中大部分节点)的选票,然后就从Candidate变成了Leader,其他同意的节点就老老实实当follower了。并且任期数和拥有最新日志代表了这个Candidate的资质,超过了集群中大部分节点,当Leader完全没问题。然后Leader开始发送空内容的AppendEntries RPC,压制不服的节点,强制同步自己的日志,并在任期内扼杀节点从Follower变成Candidate的可能
  • 实际情况可能会出现,选票被瓜分,没有一个节点拿到超过半数的选票,那就在这个任期内(这里term就是没有人当leader)所有没转变的Candidate都等待超时,到点了开始下一轮选举(为了防止下一次选票还被瓜分,必须采取一些额外的措施, raft采用随机election timeout的机制防止选票被持续瓜分.通过将timeout随机设为一段区间上的某个值, 因此很大概率会有某个candidate率先超时然后赢得大部分选票.)

最后在某个任期内总会有leader产生,其他节点都被压制为follower

日志复制过程

Leader选举好后,就可以对客户端提供服务了。
设计类似于2PC,但是略有不同

客户端提交每一条命令都会被按顺序记录到Leader的日志中,每一条命令都包含term编号和顺序索引,然后向其他节点并行发送AppendEntries RPC用以复制命令(如果命令丢失会不断重发),当复制成功也就是大多数节点成功复制后,leader就会提交命令到本地,将日志写入磁盘并且将执行结果返回客户端,然后Leader才让Follower们提交自己的提交。leader会保存有当前已经提交的最高日志编号。
顺序性确保了相同日志索引处的命令是相同的,而且之前的命令也是相同的。当发送AppendEntries RPC时,会包含leader上一条刚处理过的命令,接收节点如果发现上一条命令不匹配,就会拒绝执行。

原论文https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf

http://thesecretlivesofdata.com/raft/动画能帮助理解

待续…
码博文好累啊,还有很多异常情况和设计细节,先写到这儿了

你可能感兴趣的:(白话Raft算法)