学习分布式一致性协议:自己实现一个Raft算法

本文介绍了如何学习MIT6.824课程中的lab2,即实现Raft算法。首先,作者强调了预备工作的重要性,包括阅读论文、理解Raft的基本概念和规则。接着,详细阐述了实现Raft的过程中遇到的问题,如加锁建议、定时器实现、等待RPC的方法,以及调试技巧。此外,还分享了实现日志复制和提交、优化建议以及Lab2C的挑战。最后,鼓励读者通过实践来深入理解分布式一致性协议。

前言

MIT6.824是麻省理工学院开设的一个很棒的分布式系统公开课程,课程的Schedule在这里 ,这门课程的学习方式主要是通过教授的 lecture 讲解、Paper阅读、FAQ答疑,以及实践lab来完成的,是一个学习理论知识,然后动手实践的过程,个人认为是很好的学习方式,而MIT6.824公开课让更多不是麻省理工的学生也能很好的学习分布式系统知识,免费学习MIT课程学到就是赚到!

MIT6.824主要围绕以下4个lab进行学习

  • lab1->MapReduce:实现一个MapReduce系统,其是一个具有Map和Reduce功能的分布式计算系统
  • lab2->Raft:实现Raft算法,其是一个分布式一致性协议,分为以下3个部分
    • 2A:Leader选举
    • 2B:日志复制
    • 2C:持久化数据
  • lab3->分布式容错的Key/Value存储服务:搭建一个容错的Key-Value分布式服务,其是建立在lab2-Raft的一个上层建筑,需要在lab2的基础上实现日志快照等功能,对外可以提供 K-V 存储服务
  • lab4->Shared Key/Value服务:一个分片的存储服务

而本篇文章讨论的是如何学习lab2的部分,也就是实现一个Raft算法,本文会指出学习方式,以及你需要做到的一些要点、常见的坑、资料等等。你可以将本文作为一个lab2的Guide来进行阅读。

如果读者对其他lab有兴趣,也可以参照本文差不多的方式进行其他lab的学习。

首先放一张lab2A、2B、3C,3pass图(做完还是有满满的成就感的)

在这里插入图片描述
前段时间花了一周左右的时间动手写代码完成了MIT6.824课程中的lab2,达到 bug-free 属实不易,在做的过程中踩过许多坑,发现做lab的时候交流、沟通代码中的一些问题很重要,交流会开拓了我们的思路、解决方法,如果没人交流,就比较容易出现一个疑难杂症会卡好几个小时甚至几天的情况,比较容易产生气馁、想放弃的情绪,我在做lab2C部分的最后一个具有挑战性的unreliable test的时候有一个bug硬找了快两天,中途有几次想过放弃,但意志力和对技术的热情驱使我不能将就,所以坚持下来,最终会找到解决方法的思路的。

学习MIT6.824课程,我们不像MIT学生那样,学生之间可以进行讨论,有问题可以询问助教、教授,我们在做的时候只是一个人,你最多可以找到MIT6.824的交流群,但群里真正能帮助你解决一些问题的人不多,最终靠自己的比重还是比较大的,所以一些学习资料就显得比较重要,这也是本文创作的初衷,想让更多人学习到MIT6.824这门课程,学习Raft算法不止是阅读paper和一些理论知识,没有什么比直接实现一个Raft还能够深刻学习分布式一致性协议的了。其次自己实现一个Raft,想想就很有意思。

学习lab2,我希望至少需要有CAP和分布式一致性相关知识基础,起码要了解他们,知道Raft是干嘛用的,为什么需要使用Raft。这里推荐自己的一篇文章,从CAP理论延伸来讲讲分布式一致性,点击查看

1. Lab前的预备工作

1.1 如何检验Raft算法的正确性

感觉这个是大多数人首先都比较关心的问题,这个Raft算法做出来之后我怎么知道它能work呢?lab中首先会给你一个代码大致骨架,骨架中附带了很多单元测试可以测试你的代码的正确性,所以按照一定规则去实现你的算法之后run一遍单元测试就行了。

1.2 编程语言

MIT6.824 中 lab 使用的语言均为Go语言,不会Go语言的同学不要就这么打退堂鼓了,我在做lab之前也不会Go语言,但这个语言简单高效,如果有Java或者C++的基础的话上手会非常快,实际做lab的话只用到了少数并发的Go库函数,所以库函数的学习成本也不会特别高,Go的语法与Java、C++类似,熟悉几天就能上手,关于IDE我个人使用的是GoLand 30天免费体验,也可以使用比较强大的 Vim -> vim使用文档,用熟练之后效率不亚于GoLand。

在Go中使用的一些特定的Go的库函数、一些比如定时器的做法在下面介绍lab的时候会具体涉猎

1.3 阅读论文

做lab之前,首当其冲的当然就是阅读Paper

  • Raft论文:https://raft.github.io/raft.pdf (英文版)
    • https://www.ulunwen.com/archives/229938 (中文版)
    • 有英文底子的都建议看英文版,因为难免英文原著有些意思翻译成中文会丢失了一些味道,直接看中文的话有的地方可能会有点疑惑

建议先读一遍paper,大概了解了解Raft算法的具体构思,看不懂的先跳过,第一遍不求甚解,有个大致思想即可。

1.4 Lecture

此时你大致已经对Raft有一定的想法了,相当于预习了一遍课程,这时候就可以开始上课了,如果只做lab2的话,你需要关注以下几个lecture:

  1. Lecture 5: Go, Threads, and Raft
  2. Lecture 6: Fault Tolerance: Raft (1)
  3. Lecture 7: Fault Tolerance: Raft (2)

其中第一个lecture讲的是在使用Go语言实现Raft时会出现的几个问题,有参考价值,第二个和第三个lecture讲的是Raft算法的一些细节,这几个lecture建议都要看,对实现lab有一定的帮助。

以下是我找到的有三个课程资源:

  • YouTube的全英文无字幕高端玩家版:https://www.youtube.com/channel/UC_7WrbZTCODu1o_kfUMq88g/videos
    • 这个比较适合英文特别好的,门槛比较高不是很推荐哈哈
  • simviso团队中文翻译版:https://www.simtoco.com/#/albums?id=1000019
    • 翻译的不错,但缺点是没翻译完,只翻译了Lecture5、6和Lecture7的前面一点点。不过也翻译了大部分了,前面大半部分可以参考这里
  • 机翻的中英文双字幕:https://www.bilibili.com/video/BV1qk4y197bB?p=7
    • 由于是机翻,很多翻译不到位,需要有一定的英文阅读水平,看英文字幕就可以了,结合上面的中文翻译版的这里就只需要从Lecture7开始看

1.5 回顾论文

可以动手做lab之前我认为有一个指标就是你至少需要懂论文中的Figure2中的每一个字的意思,知道为什么这样子设计,Raft算法由简单易懂著称,其只有两个RPC方法,一个是AppendEntries日志复制,一个是RequestVote请求投票,以及一系列的Raft属性都在Figure2中,同时有一系列Follower、Candidate、Leader、AllServer需要遵循的规则,理解这些规则并且做lab的时候一定要按照论文中的这些规则说的去做。

当你对某个Figure2中的规则产生疑惑,请多回顾多读几遍论文,这是做lab时bug-free的关键。做之前务必保证理解了Figure2。

1.6 参考资料

最后总结几个参考资料,做lab时应该能帮到你:

  • 助教的blog:Students’ Guide to Raft -> https://thesquareplanet.com/blog/students-guide-to-raft/
    • 课程的助教总结了几个做lab时需要注意的几个点,和一些bug经验,做之前可以参考参考
  • 教授写的Lock锁使用建议:http://nil.csail.mit.edu/6.824/2020/labs/raft-locking.txt
  • 教授写的Raft结构建议:http://nil.csail.mit.edu/6.824/2020/labs/raft-structure.txt
  • lecture的讲义:http://nil.csail.mit.edu/6.824/2020/notes/l-raft2.txt

2. 开始lab2实现Raft

课程主页

务必遵循paper中的Figure2的每条规则来实现你的lab

现在就开始着手做lab了,进入课程主页,左边的导航中进入lab2 ,开始动手之前务必保证读一遍教授说的话,以及仔细阅读每个Task下面的Hint提示(我做的时候进的是2018的网页,提示相当少,做完才发现有2020年的网页,提示变多了好几条)

2.1 Lab2A

首先是2A,实现Leader选举,刚开始2A里的两个测试个人认为是最简单的,因为leader选举在下面的2B、2C都会迎来更大的挑战,如果你能pass2A,并不能代表Leader选举的逻辑就一定ok,也就是说在2B、2C中如果出现BUG还是有可能因为你的Leader选举逻辑有问题导致的。

下面就提几个要点帮助你快速上手实现Raft

要点只会设计一些Raft算法无关的东西,比如语言这块,初衷是希望算法之外的东西不要浪费大家太多时间,更多关注算法的实现

2.1.1 加锁建议

一个原则,不要考虑锁性能(锁的粒度)问题,我们更关注的是算法的正确性,有可能data-race的时候请毫不犹豫加上一把大锁

可见性与原子性

由于算法中很多地方都需要并发编程,比如Candidate发起投票请求RPC,要同时给所有节点发送RPC,此时就开多个goroutine进行RPC,一旦涉及并发编程,就会有data-race、数据可见性的问题,参照Happen-before原则,在所有有data-race的地方都加一把锁,为了可见性也为了原子性。

func (rf *
掌握分布式mapreduce与raft算法分布式数据库MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算。概念Map(映射)和Reduce(归约),是它们的主要思想,都是从函数式编程语言里借来的,还有从矢量编程语言里借来的特性。它极大地方便了编程人员在不会分布式并行编程的情况下,将自己的程序运行在分布式系统上。 当前的软件实现是指定一个Map(映射)函数,用来把一组键值对映射成一组新的键值对,指定并发的Reduce(归约)函数,用来保证所有映射的键值对中的每一个共享相同的键组。MapReduce是面向大数据并行处理的计算模型、框架和平台,它隐含了以下三层含义:1)MapReduce是一个基于集群的高性能并行计算平台(Cluster Infrastructure)。它允许用市场上普通的商用服务器构成一个包含数十、数百至数千个节点的分布和并行计算集群。2)MapReduce是一个并行计算与运行软件框架(Software Framework)。它提供了一个庞大但设计精良的并行计算软件框架,能自动完成计算任务的并行化处理,自动划分计算数据和计算任务,在集群节点上自动分配和执行任务以及收集计算结果,将数据分布存储、数据通信、容错处理等并行计算涉及到的很多系统底层的复杂细节交由系统负责处理,大大减少了软件开发人员的负担。3)MapReduce是一个并行程序设计模型与方法(Programming Model & Methodology)。它借助于函数式程序设计语言Lisp的设计思想,提供了一种简便的并行程序设计方法,用Map和Reduce两个函数编程实现基本的并行计算任务,提供了抽象的操作和并行编程接口,以简单方便地完成大规模数据的编程和计算处理Raft 是一种为了管理复制日志的一致性算法。它提供了和 Paxos 算法相同的功能和性能,但是它的算法结构和 Paxos 不同,使得 Raft 算法更加容易理解并且更容易构建实际的系统。为了提升可理解性,Raft一致性算法分解成了几个关键模块,例如leader人选举、日志复制和安全性。同时它通过实施一个更强的一致性来减少需要考虑的状态的数量。从一个用户研究的结果可以证明,对于学生而言,Raft 算法Paxos 算法更加容易学习Raft 算法还包括一个新的机制来允许集群成员的动态改变,它利用重叠的大多数来保证安全性。 一致性算法允许一组机器像一个整体一样工作,即使其中一些机器出现故障也能够继续工作下去。正因为如此,一致性算法在构建可信赖的大规模软件系统中扮演着重要的角色。在过去的 10 年里,Paxos 算法统治着一致性算法这一领域:绝大多数的实现都是基于 Paxos 或者受其影响。同时 Paxos 也成为了教学领域里讲解一致性问题时的示例。 但是不幸的是,尽管有很多工作都在尝试降低它的复杂性,但是 Paxos 算法依然十分难以理解。并且,Paxos 自身的算法结构需要进行大幅的修改才能够应用到实际的系统中。这些都导致了工业界和学术界都对 Paxos 算法感到十分头疼。 和 Paxos 算法进行过努力之后,我们开始寻找一种新的一致性算法,可以为构建实际的系统和教学提供更好的基础。我们的做法是不寻常的,我们的首要目标是可理解性:我们是否可以在实际系统中定义一个一致性算法,并且能够比 Paxos 算法以一种更加容易的方式来学习。此外,我们希望该算法方便系统构建者的直觉的发展。不仅一个算法能够工作很重要,而且能够显而易见的知道为什么能工作也很重要。 Raft 一致性算法就是这些工作的结果。在设计 Raft 算法的时候,我们使用一些特别的技巧来提升它的可理解性,包括算法分解(Raft 主要被分成了leader人选举,日志复制和安全三个模块)和减少状态机的状态(相对于 PaxosRaft 减少了非确定性和服务器互相处于非一致性的方式)。一份针对两所大学 43 个学生的研究表明 Raft 明显比 Paxos 算法更加容易理解。在这些学生同时学习了这两种算法之后,和 Paxos 比起来,其中 33 个学生能够回答有关于 Raft 的问题。 Raft 算法在许多方面和现有的一致性算法都很相似(主要是 Oki 和 Liskov 的 Viewstamped Replication),但是它也有一些独特的特性: 强leader:和其他一致性算法相比,Raft 使用一种更强的leader能力形式。比如,日志条目只从leader发送给其他的服务器。这种方式简化了对复制日志的管理并且使得 Raft 算法更加易于理解。leader选举:Raft 算法使用一个随机计时器来选举leader。这种方式只是在任何一致性算法都必须实现的心跳机制上增加了一点机制。在解决冲突的时候会更加简单快捷。成员关系调整:Raft 使用一种共同一致的方法来处理集群成员变换的问
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值