Lab3 记录

news/2024/9/24 23:43:01/文章来源:https://www.cnblogs.com/INnoVationv2/p/18430335

Part 3A: leader election

1.选举主要流程

  1. 新服务器加入集群

服务器在启动时状态是Follower。只要持续接收到Leader或Candidate的心跳信息,就继续保持Follower状态。

  1. 开始选举

每个Server都有一个随机的选举超时时间,选举超时在一个固定区间内随机选择(例如,150-300毫秒)

如果Follower在选举超时时间内未收到有效的心跳信息,就认为当前没有有效Leader,转换自己为Candidate,发起选举。

心跳消息:一般是不包含日志条目的AppendEntries RPC

  1. 投票规则

服务器收到RequestVote RPC时,根据以下规则进行投票:

服务器以先到先得的方式投票,且每个任期只能投一票。

  • 如果收到的RPC的任期小于服务器当前的任期,拒绝投票
  • 如果服务器已经为当前任期投过票,或收到的RPC中的日志不如自己的日志新(最后一个条目的任期较旧或者任期相同但是编号较小),拒绝投票。
  • 如果以上情况都不满足,服务器会为Candidate投票,并重置自己的选举超时时间。
  1. 选举过程
  • 若选举过程中,Candidate收到其他Leader的心跳信息,且该Leader的任期大于等于候选人的任期,那么Candidate会承认新Leader并转回Follower状态;反之继续进行选举。
  1. 选举结果
  • 若Candidate获得的选票超过半数(3/5),则赢得选举,成为新Leader。同时向所有Server发送心跳消息,以防止新的选举。
  • 若选举超时,没有选出Leader,即没人获得多数票,一般是因为同时有多个Follower成为了Candidate。这种情况下,Candidate会等待一个随机的选举超时时间,增加任期,重新开始新一轮选举。

2.各组件逻辑

  1. 各组件都要遵守的规则

    任意RPC中包含的term大于自身term,则更新自己的term,并将自己转为follower状态,本节主要是心跳RPC和RequestVote RPC

  2. 随机超时检测ticker()

    功能:检测是否需要进行选举,使用Goroutine并行运行

    • role == Leader:跳过所有检测

    • role != Leader:

      若未收到心跳消息或未投票给任何人,举行选举

  3. 接收到心跳消息

    1. 如果心跳Term<当前Term,拒绝心跳,直接返回

      心跳TermTerm==当前Term心跳TermTerm>当前Term,则重置超时检测

    2. role==Candidaterole==Leader&&心跳Term>当前Term

      • 转回Follower

      • 更新当前Term为心跳Term

      • 更新LeaderID为心跳发送方

      • 更新VoteFor为心跳发送方

  4. 接收到投票请求

    说明已经有人开始选举,因此重置超时检测器,推迟自身可能要开始的选举

    1. 如果请求投票RPC Term<当前Term,拒绝

    2. 如果请求投票RPC Term>当前Term,投票

      更新自身Term

      如果当前Role!=Follower,转回Follower

    3. 如果请求投票RPC Term==当前Term,且当前Term没有投过票,投票

  5. 接收心跳超时,开始选举

    1. 配置自身角色

      1. Role切换为Candidate
      2. 投票给自己
      3. 当前Term+1
    2. 向其他Server请求投票

      票数过半,当选Leader

      1. 切换Role为Leader
      2. 更新LeaderID为自己
      3. 启动心跳发送程序

3.结果

测试6K次

image-20240901184324743

单次用时

image-20240924012301525

代码地址:https://github.com/INnoVationv2/6.5840/tree/Lab-3A-Dev/src/raft

go test -run 3A -count 1000 -failfast -timeout 3000m -race

Part 3B: log

  1. 完善结构体,将图2中State、AppendEntries RPC、RequestVote RPC的所有参数都写进代码

  2. 先从5.3节开始,实现不出错情况下Raft的处理逻辑,从Leader当选后开始

    当Leader收到客户端提交的命令时

    1. 根据客户端命令创建新的日志条目,日志条目由命令和任期编号组成。
    2. 向所有Follower并行发送AppendEntries RPC,其中包含待复制的旧条目、新条目、前一个日志条目的索引任期
    3. Follower收到AppendEntries RPC后,先检查其中的前一个日志条目的索引任期是否与自己的日志匹配。若匹配,则添加新条目并回复成功。若不匹配,则拒绝并回复失败。
    4. 当Leader收到包括Leader在内超过半数Follower的确认后,日志条目就被认为是safely replicated
    5. 之后,Leader执行条目到自己的状态机,然后将已执行的最大日志目录编号Index记录下来,下次与Follower通信时,会将其附上,这样Follower就知道Index之前的条目都已执行,然后Follower就也会执行这些条目到自己状态机。
    6. 将日志条目执行到状态机后,返回操作结果给客户端。
  3. 接下来实现日志修复逻辑

    Leader发生崩溃时,可能会导致日志不一致,旧Leader可能没有完全复制日志到其他服务器,Follower可能缺少leader的条目、也可能有Leader没有的条目。

    在Raft中,Leader会强制Follower复制自己的日志以保持一致。Follower日志中的冲突条目会被Leader日志覆盖。

    日志冲突处理步骤:

    image-20230425175616580
    1. Leader为每个Follower维护一个nextIndex,这是Leader下一次给Follower发生日志条目的起始编号
    2. Leader首次当选时,将所有nextIndex值初始化为日志中最后一个值之后的索引(图7中的11)。如果Follower与Leader的日志不一致,下一次AppendEntries RPC肯定会失败。失败后,Leader减少nextIndex并重试AppendEntries RPC。最终,nextIndex将达到和Follower日志匹配的点。
    3. 成功匹配后,AppendEntries将成功,Follower将删除日志中的所有冲突条目,并从Leader日志中追加条目。一旦AppendEntries成功,Follower与Leader的日志将一致,并且在该Term内始终保持一致。
  4. 继续实现论文中,为保证Raft正确性所做的一系列限制

    1. 选举限制

      防止未包含所有已提交条目的Candidate赢得选举

      收到投票请求时,投票人会将Candidate日志和自己的日志进行对比,

      • 如果Candidate的日志和投票人的至少一样新,投票
      • 如果投票人的日志比Candidate更新,不投票

      日志的定义:通过比较日志中最后一个条目的Index和Term来确定。

    2. 前一个Term的日志项

      对前一个Term的日志,不通过计算副本数规则提交,只对当前Term的日志项通过计算副本数提交,因为根据Log Matching属性,所有之前的条目都会被间接提交。

注:最近进行过日志发送或正在进行日志发送的话,本轮发送心跳暂停

一些坑

  1. 当发送非心跳消息到Follower超时时,若还是Leader,且term未变,需要持续重试

  2. Follower在接收到AppendEntries时,更新CommitIndex同样要遵循只提交当前任期日志项的原则

  3. Leader发送成功,更新NextIndex和MatchIndex时,先比较大小再更新,因为发的早的消息可能回复的比发的晚的消息更早

    如下两条消息

    {PrevLogIndex:5 PrevLogTerm:2 LeaderCommit:5 Len:4}
    {PrevLogIndex:5 PrevLogTerm:2 LeaderCommit:5 Len:5}
    

    第一条回来,NextIndex应该更新为10,第二条回来,NextIndex应该更新为11

    但是第二条如果回来的比第一条晚,NextIndex就会->11->10,从而出错

  4. 创建AppendEntries时,使用Copy,而不是切片引用,会出现DataRace

结果

3B测试100次

image-20240923161109298

单次用时

image-20240924012653056

Part 3C: persistence

这章就是在Persistent state发生改变时,及时持久化

如果测试报错,99%都是前两节没有写好

结果

3C测试100次

image-20240924012047002

单次用时

image-20240924012711612

Part 3D: log compaction

  1. Snapshot的定义:snapshot中保存的是已Commited日志的压缩,比如x+2 x-1,则Snapshot只需要存储x=1

  2. 当接收到Snapshot时,可以直接将其发送给tester,无需等待CommitIndex的确认,因为Leader的CommitIndex一定大于Snapshot

  3. Snapshot中保存的是已Commited日志,所以和Commit日志一样,只能向前推进,不能后退

    关于这一点有一种情况需要处理

    三个Server

    Leader最大Log Index为140,snapshop包含Index135之前的日志

    Follower1 和Leader同步

    Follower2 最大Log Index也是140,但是Snapshot只包含Index 120之前的日志

    之后Leader失效,Follower2当选Leader,发送snapshot给Follower1,Follower2已经有了更新的snapshot,所以没有更新

    Follower2将nextIndex[1]更新为121,下次发送日志prevLogIndex就是120,此时Follower会发现找不到Index 为120的日志

结果

测试100次

image-20240924231617401

单次用时

image-20240924232051965

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/803116.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件工程课程第三次作业

软件工程 https://edu.cnblogs.com/campus/fzu/SE2024作业要求 https://edu.cnblogs.com/campus/fzu/SE2024/homework/13261作业目标 分析学生们的需求,设计一个app原型解决他们的问题学号 072208130合作伙伴 052205144张诗悦使用figma设计原型,原型链接:https://www.figma.…

大文件去重

若文件存的字符如下图,要求进行去重可将数据存入HashSet,如下,但如果文件很大,大于虚拟机内存的话,会报异常java.lang.OutOfMemoryError: Java heap spaceHashSet set = new HashSet();File file = new File("E:\\aa.txt");BufferedReader reader = new Buffere…

9月13日关于数组存储数据

在题目中要求建立数组来存储项目信息,储存的内容包括String、int、boolean、double等各种不同类型,刚开始我还处于建立普通数组要不是int【】要不是string【】,越琢磨越不对劲这样并不能存储不同类型的数据,但是数据又需要统一存取,网上又没有这么简单的讲解,也是被这个简…

9.24日总结

今日上学配置了Node.JS的环境变量,并应用VScode进行JavaScript的相关学习应用 其中

9月11日toString重载方法的使用

在编辑过程中我经常会写一部分调试一部分,至少知道哪里有错能够及时改正,在编写时发现studentManger中的打印出来的是地址,而不是自己想要的内容,经过查询是需要写toString来重载输出利用这样的方法,一是可以正常打印出自己想要的内容,而是可以根据一个参数打印出所有的信…

软件工程作业——结对项目

这个作业属于哪个课程 22级计科12班这个作业要求在哪 作业要求这个作业的目标 实现一个自动生成小学四则运算题目的命令行程序成员姓名 学号 GitHub地址吕宏鸿 3122004446 结对项目宋观瑞 3122004402 结对项目1.PSP表格PSP2.1 预估耗时(分钟) 实际耗时(分钟)计划 10 5* 估计…

9月10日循环条件的结束

在测试编程中涉及到输入错误要重新返回UI界面,但是我写的总是输入不管是对还是错都会直接结束程序,完全不符合要求,经过整理思路,查询代码结构,此处应该设计为双层循环外部为while,内部为witch case语句,当输入为1时执行case==1;经应该是执行生产计划类然后跳出witch条…

IDEA更改远程git仓库地址

前言 我们在使用IDEA开发时,一般会配置好对应的git仓库,这样就比较容易对代码进行控制以及协同开发。但有时候,我们远程的仓库地址由于这样那样的原因,需要迁移(这在爱折腾的企业是常有的事情)。那么,我们该如何在IDEA中更新远程仓库地址呢? 如何设置 首先,我们点击上…

vue3开发中易遗漏的常见知识点

组件样式的特性 Scoped CSS之局部样式的泄露 示例(vue3): 父组件: <template><h4>App Title</h4><hello-world></hello-world> </template> <script> import HelloWorld from ./HelloWorld.vue;export default {name: App,compo…

PasteForm最佳CRUD实践,实际案例PasteTemplate详解(一)

本文将介绍soft.pastecode.cn出品的PasteForm,PasteForm是贴代码使用Dto思想实现的CRUD的一个组件,或者说输出一个思想! 为啥我觉得是最佳的CRUD呢?先结合你的实际项目解答下以下问题: 1.如果有一个系统,有100个表,你的管理端需要多少页面?别和我说100个表很多,需求复…

RTE大会报名丨 重塑语音交互:音频技术和 Voice AI,RTE2024 技术专场第一弹!

Voice AI 实现 human-like 的最后一步是什么?AI 视频爆炸增长,新一代编解码技术将面临何种挑战?当大模型进化到实时多模态,又将诞生什么样的新场景和玩法?所有 AI Infra 都在探寻规格和性能的最佳平衡,如何构建高可用的云边端协同架构?AI 加持下,空间计算和新硬件也迎来…

彻底搞懂回溯算法

1.回溯算法的核心思想 回溯算法的核心思想是:尝试+记录+回退。 先尝试一种选项,在选择该选项的前提下继续寻解,如果最后寻解成功,则记录这个解,否则不用记录,然后再回退到选择该选项前的状态,改为尝试其它选项再继续寻解,判断其它选项是不是解。 2.回溯算法的关键点 回溯…