一本正经地聊聊raft

cde · · 872 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

笔者很久以前就了解过raft了,它相比paxos实现跟逻辑简单了许多,因此市场上有很多的分布式系统都是使用raft协议来保证数据的一致性的。不过第一个实际接触到的raft应用倒是mongo的副本集了。

所以今天就从mongo的副本集说起。通常有多少个副本集,就保存有多少份数据。多份数据,就需要通过复制的手段来实现。

这里复制的目的并不是为了读写分离,而是提高了数据的高可用。多份数据为了保证最终一致性,mongo底层是用一种变型的raft来实现的。

一、raft的介绍

1.1 问题所在

如果是单节点,客户端修改某个值,成功的话整个系统都变为某个值:

ok!一个节点,我自己跟自己达成共识即可。

如果像mongo副本集,有多个节点存储同份数据,那就麻烦了:

同一个客户端同时向两个节点发送更新数据的命令,结果节点1成功执行命令,节点2因为网络隔离无法正确执行:

这个时候,节点1的值为1,节点2的值还是未设置。那么读的时候,我们根本无法知道哪个节点上的值才是真正的值。

当当当,这时候raft出现了。

它能提供一种解决这种多个节点数据不一致的问题。

1.2、解决之道

怎么样让两个节点上面的数据是一致的?

如果两个节点初始状态一致,然后在两个节点上面执行一样的操作,最终两个节点的数据肯定是一致的。因此:

一样的初始状态+同样的操作=数据一致

让所有节点的初始状态一致并不困难。困难在于如何执行一样的操作。raft的出现就是为了保证多个节点能够执行同样的操作。

raft的实现就是从多个节点中选举出一个leader,由这个leader来指挥,让其他所有的节点做一样的操作。

1.3、选举

选举的目的,是从所有可用节点中选举出一个master节点来为client提供服务的。

raft假定节点有三种角色:follower、candidate和leader。

follower:leader执行什么,我就执行什么,所以叫做follower。

candidate:准备当leader的follower,只有当candidate获得大多数人的投票。它才能从candidate晋升为leader。

在最开始的时候,所有节点都是follower状态。

follower时时刻刻跟leader保持一个心跳链接。当一次心跳到达的时候,follower就重置定时器,将失联的时间设置为x+随机毫秒时间后。这个时间也称之为超时时间。

因为在初始状态下,所有节点都是follower,没有leader。这个时候,所有的follower在接下来的随机毫秒时间内,都会进入失联状态。

一旦follower进入失联状态,这个follower立马推动选举。因为之前没有任何选举存在,因此这是第一个选举,它默默记下1并且给自己投了一票,然后邀请其他所有的follower来投票。

这个时候,剩下两个follower因为随机定时,可能还没有进去失联状态。所以它们就会给第一个节点投票。因此第一个节点得到3票,超过大多数票(2),它成功晋升为leader了。

成为leader之后,客户端所有的操作都得先经过leader节点。

至此,选举完成。

而选举的发动时机通常是:

Follower在一段时间内(选举超时election timeout)收不到Leader发送的心跳消息

Leader在一段时间内(心跳超时heartbeat timeout)联系不上大多数的Follower

1.4、日志复制

现在,这个leader是负责接收client的请求,请求改变的命令会记到节点的日志中,这个时候这个命令是未提交的,不会更改到系统实际上的值。

接着这个日志就会复制到另外几个节点中,然后leader会等收到大多数节点回复,表示都写到他们的日志中。

然后这个日志就会在leader上提交,然后就通知follower节点也可以提交。

这样他们就达成了共识了。

只要大多数节点都commit成功,那么这个写操作就表示ok了。

至此,大多数节点的值都为1了。达成了共识。

1.5、脑裂情况

如果有5个节点,因为网络分区的原因。导致分成两个区,一个三个节点,一个两个节点。这两个区会分别选举出一个leader出来。

不过当日志提交的时候需要得到大多数节点的提交,因此其中一个是无法提交的。因此raft也是能够解决脑裂的问题。

1.6、常见问题

raft vs paxos

相对来说,raft比paxos实现跟逻辑上要简单许多。下次有时间讲讲paxos,再来详细对比一下。

raft VS 2PC、3PC

目的不一样。raft、paxos这类通常是用来保证数据的一致性的。而2PC、3PC是为了保证操作的原子性。都是分布式的一种技术实现。

1.7、总而言之言而总之

上面的介绍只能说是raft的入门,实现一个raft其实还是有很多细节需要处理的。比如选举的规则,日志的存储,日志的同步是push还是pull,心跳的实现,操作回滚等等。如果是做应用层的,我个人感觉raft入个门应该就ok,如果是做分布式基础服务的,最好就能做出个玩具raft。


更多php+golang文章,欢迎关注公众号:编程说。



有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:cde

查看原文:一本正经地聊聊raft

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

872 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传