MIT6.5840-2023-Lab2C: Raft-Persistence

前置知识

见上一篇 Lab2A。

实验内容

实现 RAFT,分为四个 part:leader election、log、persistence、log compaction。

实验环境

OS:WSL-Ubuntu-18.04
golang:go1.17.6 linux/amd64

Part 2C: persistence

大部分的bug都与这张图有关。如果前两次lab通过了千次以上测试,这边应该问题不大。注意rpc前后的状态判断。
在这里插入图片描述

实现持久化,重启后能快速恢复。真正的实现将在每次更改时在磁盘写下 raft 的持久状态,并在重新启动后从磁盘中读取状态。lab 实现时在 Persister 中存储和恢复。currentTerm、votedFor、log[]
persist 和 readPersist:通过 labgob实现。

// save Raft's persistent state to stable storage,
// where it can later be retrieved after a crash and restart.
// see paper's Figure 2 for a description of what should be persistent.
// before you've implemented snapshots, you should pass nil as the
// second argument to persister.Save().
// after you've implemented snapshots, pass the current snapshot
// (or nil if there's not yet a snapshot).
func (rf *Raft) persist() {// Your code here (2C).// Example:w := new(bytes.Buffer)e := labgob.NewEncoder(w)e.Encode(rf.currentTerm)e.Encode(rf.votedFor)e.Encode(rf.log)raftstate := w.Bytes()rf.persister.Save(raftstate, nil)
}// restore previously persisted state.
func (rf *Raft) readPersist(data []byte) {if data == nil || len(data) < 1 { // bootstrap without any state?return}// Your code here (2C).// Example:r := bytes.NewBuffer(data)d := labgob.NewDecoder(r)var currentTerm, votedFor intvar logs []Entryif d.Decode(&currentTerm) != nil ||d.Decode(&votedFor) != nil ||d.Decode(&logs) != nil {log.Println("decode fail")} else {rf.currentTerm = currentTermrf.votedFor = votedForrf.log = logslog.Println("restore success")}
}

优化:避免 leader 每次只往前移动一位;若日志很长的话在一段时间内无法达到冲突位置。若 leader 发送心跳时接收到的回复是 false,leader 会减小发送的 AppendEntriesArgs 中的 rf.nextIndex,但是这种每次仅减小 1 的方案无法在有限的时间内确定跟其他服务器发生冲突的下标位置。

func (rf *Raft) AppendEntries(args *AppendEntriesArgs, reply *AppendEntriesReply) {// Your code here (2A, 2B).rf.mu.Lock()defer rf.mu.Unlock()if args.Term > rf.currentTerm { // all serverrf.state = Followerrf.currentTerm = args.Termrf.votedFor = -1rf.persist()}if args.Term < rf.currentTerm {reply.Success = falsereply.Term = rf.currentTerm} else if len(rf.log)-1 < args.PrevLogIndex ||rf.log[args.PrevLogIndex].Term != args.PrevLogTerm {log.Println(rf.me, "mismatch", "len(rf.log)", len(rf.log), "args.PrevLogIndex", args.PrevLogIndex)reply.Success = falsereply.Term = rf.currentTermtimeout := time.Duration(250+rand.Intn(300)) * time.Millisecondrf.expiryTime = time.Now().Add(timeout)if args.PrevLogIndex > len(rf.log)-1 {reply.ConflictIndex = len(rf.log)reply.ConflictTerm = -1} else {reply.ConflictTerm = rf.log[args.PrevLogIndex].Termreply.ConflictIndex = 1for i := args.PrevLogIndex - 1; i >= 0; i-- {if rf.log[i].Term != reply.ConflictTerm {reply.ConflictIndex += ibreak}}}} else {reply.Success = truereply.Term = rf.currentTermtimeout := time.Duration(250+rand.Intn(300)) * time.Millisecondrf.expiryTime = time.Now().Add(timeout)// // delete// rf.log = rf.log[:args.PrevLogIndex+1]// // append// rf.log = append(rf.log, args.Entries...)insertIndex := args.PrevLogIndex + 1argsLogIndex := 0for {if insertIndex >= len(rf.log) ||argsLogIndex >= len(args.Entries) ||rf.log[insertIndex].Term != args.Entries[argsLogIndex].Term {break}insertIndex++argsLogIndex++}// for _, e := range rf.log {// 	log.Print(e)// }// for _, e := range args.Entries {// 	log.Print(e)// }if argsLogIndex < len(args.Entries) {rf.log = append(rf.log[:insertIndex], args.Entries[argsLogIndex:]...)rf.persist()}if args.LeaderCommit > rf.commitIndex {rf.commitIndex = int(math.Min(float64(args.LeaderCommit), float64(len(rf.log)-1)))log.Println(rf.me, "follower update commitIndex", "args.LeaderCommit", args.LeaderCommit, "len(rf.log)", len(rf.log), "rf.commitIndex", rf.commitIndex)}}}
// 修改前
// if args.PrevLogIndex > 0 {
// 	rf.nextIndex[i] = args.PrevLogIndex
// }
// 修改后if reply.ConflictTerm >= 0 {lastIndex := -1for i := len(rf.log) - 1; i >= 0; i-- {if rf.log[i].Term == reply.ConflictTerm {lastIndex = ibreak}}if lastIndex >= 0 {rf.nextIndex[i] = lastIndex + 1} else {rf.nextIndex[i] = reply.ConflictIndex}} else {rf.nextIndex[i] = reply.ConflictIndex}

实验结果

在这里插入图片描述

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

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

相关文章

八、Seata的XA模式

目录 八、Seata的XA模式8.3 XA模式多数据源场景1 环境搭建2、使⽤XA模式解决事务 八、Seata的XA模式 8.3 XA模式多数据源场景 1 环境搭建 建库建表 代码的db.sql中 创建工程 添加依赖 <dependency><groupId>org.springframework.boot</groupId><ar…

C语言 字符串处理相关函数大汇总之(1~5)

1&#xff0c;strcpy函数 将一个字符串复制到另一个字符串。它的原型是&#xff1a; char *strcpy(char *dest, const char *src); 这个函数接受两个参数&#xff1a; (1)&#xff0c;dest&#xff1a;目标字符串。它必须是一个足够大的字符数组&#xff0c;以容纳源字符串的…

VBA技术资料MF96:单字段多条件高级筛选

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

华三交换机基础配置

文章目录 配置远程Telnet/SSH账号其他基本配置维护设备常用 当配置华三交换机时&#xff0c;以下是一些基本配置步骤和命令。将介绍如何配置远程Telnet/SSH账号以及其他一些常见的配置。 配置远程Telnet/SSH账号 要配置远程Telnet/SSH账号&#xff0c;可以按照以下步骤进行操作…

玩转Docker(四):容器指令、生命周期、资源限制、容器化支持、常用命令

文章目录 一、容器指令1.运行2.启动/停止/重启3.暂停/恢复4.删除 二、生命周期三、资源限制1.内存限额2.CPU限额3.磁盘读写带宽限额 四、cgroup和namespace五、常用命令 一、容器指令 1.运行 按用途容器大致可分为两类&#xff1a;服务类容器和工具类的容器。 服务类容器&am…

Ribbon使用

Ribbon &#xff1a;处理客户端负载均衡和容错的解决方案 配置Ribbon的负载均衡 Rule接口&#xff1a; 定义客户端负载均衡的规则 RandomRule :随机选择RoundRobinRuleZoneAvoidanceRule 配置ribbon的负载均衡策略 在配置文件中配置 user-center:ribbon:NFLoadBalancerRul…

视频号小店运营思路详解!

我是电商珠珠 视频号小店的热度在今年下半年开始逐步升高&#xff0c;这就如同20年的抖音小店一样。 对于商家来说&#xff0c;新平台寓意着新的机会。不少人想要入驻&#xff0c;但是却不知道怎么做。 其实&#xff0c;视频号小店的运营方式和抖音小店相差无几&#xff0c;…

bug 记录

ks-jenkins 出现内存不足错误 起初想在jenkins 中进行配置 发现找不到自动删除历史构建选项&#xff0c;看了kubesphere 文档也没找到选择git 仓库时配置历史构建保留时间&#xff0c;但是不选择git 仓库时是有的。 最终在jenkins 下系统管理下 工具中编写命令脚本进行手动删…

如何通俗易懂的理解Redis分布式锁

一、前言 首先我们先考虑以下这个问题&#xff1a; 在多线程并发的情况下&#xff0c;我们如何保证一个代码块在同一时间只能由一个线程访问呢&#xff1f; 答案&#xff1a;通常来说&#xff0c;我们可以用锁来保证。比如java的synchronized用法以及ReentrantLock等等。这样…

Python:解决with打开文件错误UnicodeDecodeError

简介&#xff1a;在使用with打开部分编码不是utf-8和gbk时&#xff0c;可能出现报错UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0xff in position 0: illegal multibyte sequence. UnicodeDecodeError 是一个很常见的错误&#xff0c;它通常在你试图解码一个特定编…

三阶魔方七步解法-最后还原顶层顶角(不是顶棱)

主要区别&#xff0c;最后一步是 顶层十字棱角已经还原&#xff0c;四个顶角的位置正确&#xff0c;但四个顶角的颜色没有对应。 因为现在基本都是6步还原法&#xff08;找什么小鱼&#xff0c;眼睛&#xff09;&#xff0c;是先还原顶层使颜色一致&#xff0c;最后还原顶棱。但…

云原生之深入解析使用Telepresence轻松在本地调试和开发Kubernetes应用程序

一、 准备 telepresence 下载&#xff1a;https://www.telepresence.io/docs/latest/install/kubectl 下载&#xff1a;https://kubernetes.io/docs/tasks/tools/ 二、版本检测 $telepresence version Client: v2.5.3 (api v3) Root Daemon: not running User Daemon: not r…

leetcode面试经典二分系列刷题心得

闲来无事巩固算法基础&#xff0c;发现自己的二分几乎从来没系统刷过题&#xff0c;基础很是薄弱。 二分法不愧称为新人杀手&#xff0c;刷起来很是吃力&#xff0c;感觉明明学了几套二分模板&#xff0c;但是却不知道如何去运用&#xff0c;很多读者在初次尝试刷二分题时候&a…

陆[6],函数hommat2didentity/HomMat2dRotate/HomMat2dScale/HomMat2dTranslate/

函数hommat2didentity 函数功能 生成一个初始矩阵[1,0,0,0,1,0] C形式 LIntExport void HomMat2dIdentity( HTuple* HomMat2DIdentity);//参数1:输出初始矩阵 C#形式 public static void HomMat2dIdentity( out HTuple homMat2DIdentity); 函数HomMat2dRotate 函数功能…

计算机网络 internet应用 (水

ARPA net ---Internet 前身 发展史: ARPA net 第一个主干网..美国军方NSFnet 美国国家科学基金会NSFANSnet 美国全国 (internet 叫法开始出现) 第二代互联网(现在() IP地址 IP地址 最高管理机构 - InterNIC IPV4 32位 IPV6 128位 域名 起名 解析 domain name sys…

24款奔驰C260L升级C63包围 典型的花小钱办大事

今天店里来了一台24款奔驰C260L 一提车就过来升级 我们公司还有包上牌服务 车主说 升级完包围 帮忙安排一下 原车的包围 没有那么霸气 特别是后杠 光溜溜的 升级后 四出尾喉 尾翼 直接牌面就起来了 星骏汇小许Xjh15863

Android12-RK3588_s-开机动画

目录 一、实现自定义开机动画 步骤一&#xff1a;准备 bootanimation.zip 步骤二&#xff1a;将 bootanimation.zip 放到 /system/media/bootanimation.zip下 步骤三&#xff1a;重启即可 二、注意事项 2.1 bootanimation.zip 压缩 2.2 bootanimation.zip 存放 2.3 boo…

打印机设置发票收据打印

由于各种打印机型号不一样&#xff0c;设置方式打印效果出入也很大&#xff0c;存在打印不全问题&#xff0c;发票右侧小数点后面的数字打印不出来、位置靠上下左右登问题&#xff0c;比较通用的设置方式如下&#xff1a; 首先找到控制面板&#xff0c;找到设备和打印机 进入到…

Git使用无法拉取

错误提示&#xff1a; error setting certificate verify locations: CAfile: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt CApath: none 问题原因&#xff1a; 这个问题是因为git配置里crt证书的路径不正确导致的 解决办法&#xff1a; 这个路径配置是在C:\Pro…

【C语言】printf()函数详解,手把手教你,保姆级!!!

目录 基本用法 printf()函数--占位符 占位符大全 printf()函数--限定宽度 printf()函数--正负--限定小数 printf()函数--输出部分字符串 总结 【C语言】printf()函数详解&#xff0c;手把手教你&#xff0c;保姆级&#xff01;&#xff01;&#xff01; 基本用法 printf()…