美文网首页
Raft学习笔记

Raft学习笔记

作者: 周群力 | 来源:发表于2021-09-03 08:48 被阅读0次

1. 学习资料

个人觉得不错的阅读顺序是:作者的演讲视频+算法可视化工具 > 大学课程(mit/剑桥) > 论文
光看论文看字不好懂,学算法时visualization很重要

Videos

论文作者(推荐。但没讲成员变更,下面的视频作为补充):
https://www.youtube.com/watch?v=vYp4LYbnnW8

论文拿来做对比试验的Raft教学视频:
https://www.youtube.com/watch?v=YbZ3zDzDnrw

以及Mit 6.824的课程讲解
https://www.zhihu.com/column/c_1273718607160393728

剑桥(我没看)
https://www.youtube.com/watch?v=IPnesACYRck&list=PLeKd45zvjcDFUEv_ohr_HdUFe97RItdiB&index=18

Visualization

https://raft.github.io/raftscope/index.html

2. 用自己的话解释算法

先选主,选完主之后主从复制,但是复制策略是过半2pc(不是普通的主从同步或异步复制)。
而paxos是每个log都先选主再过半2pc

2.1. 一些影响理解的、论文没提的前提假设

  • 每个节点事先知道整个集群的成员列表(membership list)。共识算法不管你一开始怎么同步成员列表(算法假设你已经同步好了),但是算法会管你运行时动态变更成员列表,因为你变更的时候不小心可能影响算法的正确性

例如etcd每个节点启动的时候要配成员列表

  • 允许leader批量(并发)写,即使前一个写没commit,leader接收到新的写请求也可以直接做主从复制
    所以才会出现Server 5这种情况,222222,一堆2但是很多没commit
    image.png
    这其实是一种性能优化,提高并发度,并且刷盘时能批量刷盘、减少刷盘次数。见https://zhuanlan.zhihu.com/p/203485444

2.2. 复制的细节

2.2.1. 过半2pc(我自己起的名字)

主从复制本质上是过半2pc,但是单独的commit请求被省掉了,随着下次写操作一起带上。(感觉这种piggyback的思想在分布式算法里很常见?SWIM也有这种策略)
如果新的log没commit时leader fail,会有不确定
算法设计上要想办法“一旦commit、被state machine执行了,将来的leader一定得有这条log”


image.png image.png

2.2.2. 怎么保证“一旦commit、被state machine执行了,将来的leader一定得有这条log”

选举约束(只选拥有所有commit log的节点当leader)
+leader强势复制(选举成功后,leader强制让follower的log和自己一样)

选举约束

https://zhuanlan.zhihu.com/p/201199555

复制时leader强势让follower日志和自己一样

复制时,Leader“线性退避”试验follower和自己相同的最新log槽位
https://zhuanlan.zhihu.com/p/201198000

2.2.3. 既然允许leader并发批量写,如果follower落后很多的话,会不会导致复制特别慢?

正常情况follower不会落后很多,还好。
异常情况会落后很多,比如机器刚重启要重放所有log,比如新加了一台机器,这种情况follower会落后很多,所以raft算法设计了一套日志压缩和快照机制,就是把某个时刻的所有内存状态作为一个log,那么之前的log就可以忽略
可以看下https://zhuanlan.zhihu.com/p/208393872

2.2.4. 反思:为啥raft不是单纯的给每个log递增id、选举时候比哪个副本的log id最大,为啥还要单独加个任期id?

其实还是会出现脑裂,只不过脑裂的时候少数派leader没法过半写,少数派leader可能自high式的写了很多新log id,和多数派leader的log id重复
所以如果是协调服务+主从复制的架构,不会出现脑裂,那么选举时候比较log id就行了

2.3. 如何处理成员变更(Membership change)

2.3.1. 可能存在的问题

如果是朴素做法,同一时间可能有不同成员配置,可能导致脑裂(两个majority)


image.png

2.3.2. 怎么解决

论文给出的思路:2pc

加一个中间阶段(混合共识),保证全old和全new不可能重叠


image.png
Etcd的实现

https://doczhcn.gitbook.io/etcd/index/index-1/clustering/runtime-reconf-design
思想也是2pc,但是具体细节和论文不一样,很巧妙:
第一阶段保证新节点没启动,是fail状态,写配置变更,直到commit
第二阶段启动新成员

这样就避免了上文提到的、在新配置uncommitted时出现脑裂的问题

2.4. 如何避免"client明明请求失败了,数据还是写进去了?"

从上面描述可以看出来,假设一个复制还没过半时发生了网络分区,旧leader怎么都没法复制过半,而新leader可能有本来没复制过半的log(没commit的log),但最终还是提交了,这对client来说可能会很困惑
因此个人理解,raft leader如果复制过不了半,不应该返回fail给client,因为可能client重试时发现其实已经提交了。

补充:问了下开发Raft的技术同学,复制没过半的话Leader会无限重试、不响应client,client自己超时停止

2.5. 怎么响应读操作

2.5.1. 方案

听课的理解是两种风格,一种是读请求只访问leader,而且leader要做一个空写
Q: 为什么空写,为什么不能直接读已commit的log?
A: 因为leader可能已经不是leader了,但不自知。raft可能在分区时有两个节点自以为是leader,只不过少数派leader没法写

另一种是quorum读

2.5.2. 能否优化读性能

提高性能的优化有:

  • 读leader,leader空写,但是不进日志(不持久化);包括leader接收到读请求后做一次心跳,看看自己是不是还是leader。论文有写这种优化

  • 读leader,leader使用租约,这样leader只要租约还在就不用去确认自己是不是leader。记得把时间设置小于选举超时时间。spanner的paxos扩展算法是这种思想。但是这种方案的问题是时钟不可靠,spanner可以这么做是以为TrueTime API保证时钟可靠
    https://www.zhihu.com/question/485919606

  • 读任意副本,通过一套时间戳机制保证线性一致。参考spanner设计,要有TrueTime API

  • 能否读任意副本,但是不用TrueTime API?比如搞一套能保证因果一致的版本号

3. 业界实现

3.1. Examples

3.2. 实现原理

3.2.1. 如何基于全序广播实现线性一致性存储?尤其是,如何实现读线性一致?

  • zk咋做的?让用户显示用sync,其实就是写一个log,等到能读到这个log
    直觉上,这相当于线性读请求也依赖主节点,主节点成为读写操作的单点瓶颈,一点都不scale,zk server机器越多性能越差

  • etcd咋做的?

  • SOFA-JRaft咋做的

  • DDIA怎么说

  • Multi Group

  • 实现上的优化?

3.2.2. 咋管理成员列表

Etcd:提前配好

不管是启动时配置,还是启动时借助naming服务,本质上都是提前配好membership list
然后允许运行时动态修改

image.png
https://doczhcn.gitbook.io/etcd/index/index-1/clustering
https://etcd.io/docs/v3.5/op-guide/clustering/
SOFA-JRaft

提前配好


image.png

https://www.sofastack.tech/projects/sofa-jraft/jraft-user-guide/
https://www.sofastack.tech/projects/sofa-jraft/counter-example/

4. 工程优化

4.1. 课程说 raft snapshot太大,不适合kv数据库等海量数据场景。是不是可以优化raft算法、解决这个问题?

a. 论文有写,让每个服务器独立创建快照,快照压缩事件不写进log。压缩后的日志只在发生节点落后、需要快照复制的时候才用上

但是这里其实还是有问题,网络抖动/节点重启等导致节点落后时,可能会发生快照传输,但其实没落后那么多、用不到那么多
解决的思路课程有提,设计一套协议,leader维护follower进度,压缩不能超过follower进度。不过比较复杂

b. 个人理解,把快照异步复制到一个备份存储里,新节点先基于备份存储重建
c. 分块压缩,类似LSM tree思想

5. 遗留问题

  • 怎么解raft的一个edge case,选主抖动问题?

http://www.zhihu.com/question/483967518

  • Leader“线性退避”去试follower的log位置,这个会不会导致消息复杂度太高(消息太多),感觉可以优化一下?
    很多优化思路,比如让follower给出更多的信息(我有哪些log提交了),以及这些信息是不是可以piggyback(比如之前选举投票的时候就带上这些信息)
    或者二分/倍增?
    论文提了一种优化思路,follower多带一些信息,让Leader按任期做批量回退。见https://zhuanlan.zhihu.com/p/203483680
    教授也说这方面其实有很多优化思路可以做,只不过论文没做展开。
    可以看看工程实现中怎么优化的、有没有更好的办法,能不能给这些实现提pull request做优化
  • 选举时有可能重试很多次,感觉可以用确定性算法做优化,加快选举速度?

相关文章

  • raft 学习笔记(6.824 Lab 2)

    raft 学习笔记 最近在学习 6.824 的分布式课程.学习到 Raft 算法. 写篇文章作为记录. 什么是 R...

  • etcd-raft 库源码阅读【WIP】

    Etcd 源码阅读 本文是 etcd-raft 库源码的阅读笔记。希望通过阅读 etcd-raft 库的源码,学习...

  • raft 学习笔记

    测试

  • Raft学习笔记

    To be continued ... References The Raft Consensus Algorit...

  • Raft学习笔记

    1. 学习资料 个人觉得不错的阅读顺序是:作者的演讲视频+算法可视化工具 > 大学课程(mit/剑桥) > 论文光...

  • Raft 协议学习笔记

    好久没有更新博客了,最近研究了Raft 协议,谈谈自己对 Raft 协议的理解。希望这篇文章能够帮助大家理解 Ra...

  • Raft 协议学习笔记

    最好先通读一遍 raft 论文。 学习思路:先读一遍论文;然后熟悉协议的基本规则和哲学;最后深入研究协议对于异常情...

  • Paxos Raft学习笔记

    最近在学习zk,因而顺道学习一下paxos和raft,没有看英文论文,直接看的书和网上的译文,看的一塌糊涂,pax...

  • RocketMQ主从切换

    本文主要是记录raft协议的学习过程,包括如下几个方面 raft协议一些基本概念 raft协议场景 raft协议在...

  • 学习Raft算法的笔记

    Raft是一种为了管理日志复制的一致性算法。它提供了和Paxos算法相同的功能和性能,但是它的算法结构和Paxos...

网友评论

      本文标题:Raft学习笔记

      本文链接:https://www.haomeiwen.com/subject/ofkdiltx.html