MIT6.5840-2023-Lab2B: Raft-Log

2023-12-13 05:12
文章标签 2023 log raft mit6.5840 lab2b

本文主要是介绍MIT6.5840-2023-Lab2B: Raft-Log,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前置知识

见上一篇 Lab2A。

实验内容

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

实验环境

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

Part 2B: log

这部分主要实现添加新的 log。

日志匹配特性(Log Matching Property)

  • 如果在不同的日志中的两个条目拥有相同的索引和任期号,那么他们存储了相同的指令。
  • 如果在不同的日志中的两个条目拥有相同的索引和任期号,那么他们之前的所有日志条目也全部相同。

第一个特性来自这样的一个事实,领导人最多在一个任期里在指定的一个日志索引位置创建一条日志条目,同时日志条目在日志中的位置也从来不会改变。第二个特性由附加日志 RPC 的一个简单的一致性检查所保证。在发送附加日志 RPC 的时候,领导人会把新的日志条目前紧挨着的条目的索引位置和任期号包含在日志内。如果跟随者在它的日志中找不到包含相同索引位置和任期号的条目,那么他就会拒绝接收新的日志条目。一致性检查就像一个归纳步骤:一开始空的日志状态肯定是满足日志匹配特性的,然后一致性检查在日志扩展的时候保护了日志匹配特性。因此,每当附加日志 RPC 返回成功时,领导人就知道跟随者的日志一定是和自己相同的了。

Start:
向 leader 添加log;

客户端的每一个请求都包含一条被复制状态机执行的指令。领导人把这条指令作为一条新的日志条目附加到日志中去(此时请求返回指令在日志中的 index,但不保证指令被提交;Start 函数返回了,随着时间的推移,对应于这个客户端请求的 ApplyMsg 从applyCh channel 中出现在了 key-value 层。只有在那个时候,key-value 层才会执行这个请求,并返回响应给客户端),然后并行地发起 AppendEntries RPCs 给其他的服务器,让他们复制这条日志条目。当这条日志条目被安全地复制,领导人会应用这条日志条目到它的状态机中然后把执行的结果返回给客户端。如果跟随者崩溃或者运行缓慢,再或者网络丢包,领导人会不断的重复尝试 AppendEntries RPCs (尽管已经回复了客户端)直到所有的跟随者都最终存储了所有的日志条目。

func (rf *Raft) Start(command interface{}) (int, int, bool) {index := -1term := -1isLeader := true// Your code here (2B).rf.mu.Lock()term = rf.currentTermisLeader = rf.state == Leaderif !isLeader {rf.mu.Unlock()return index, term, isLeader}log.Println(rf.me, "Start", "rf.currentTerm", rf.currentTerm, "command", command, "len(rf.log)", len(rf.log))rf.log = append(rf.log, Entry{Command: command,Term:    term,})rf.nextIndex[rf.me] = len(rf.log)rf.matchIndex[rf.me] = len(rf.log) - 1rf.persist()index = len(rf.log) - 1rf.mu.Unlock()go rf.replicateLog() // replicate log to followerreturn index, term, isLeader
}

commit:
更新 commitIndex。

领导人知道一条当前任期内的日志记录是可以被提交的,只要它被存储到了大多数的服务器上。Raft 永远不会通过计算副本数目的方式去提交一个之前任期内的日志条目。只有领导人当前任期里的日志条目通过计算副本数目可以被提交;一旦当前任期的日志条目以这种方式被提交,那么由于日志匹配特性,之前的日志条目也都会被间接的提交。

func (rf *Raft) commit() {rf.mu.Lock()defer rf.mu.Unlock()if rf.state != Leader {return}for N := len(rf.log) - 1; N > rf.commitIndex; N-- {if rf.log[N].Term != rf.currentTerm {return}num := 0for i := 0; i < len(rf.matchIndex); i++ {if rf.matchIndex[i] >= N {num++}}if num > len(rf.peers)/2 {rf.commitIndex = Nlog.Println(rf.me, "commit", "rf.commitIndex", rf.commitIndex, "len(rf.log)", len(rf.log))return}}
}

apply:
当 commitIndex 落后 lastApplied,向 applyCh 传输 command。

func (rf *Raft) apply() {for rf.killed() == false {rf.mu.Lock()if rf.commitIndex > rf.lastApplied {savedLastApplied := rf.lastAppliedlogEntries := rf.log[rf.lastApplied+1 : rf.commitIndex+1]rf.lastApplied = rf.commitIndexfor i, entry := range logEntries {log.Println(rf.me, "apply", "rf.commitIndex", rf.commitIndex, "rf.lastApplied", rf.lastApplied, "command", entry.Command)rf.applyCh <- ApplyMsg{CommandValid: true,Command:      entry.Command,CommandIndex: savedLastApplied + i + 1,}}}// if rf.commitIndex > rf.lastApplied {// 	log.Println(rf.me, "apply", "rf.commitIndex", rf.commitIndex, "rf.lastApplied", rf.lastApplied, "command", rf.log[rf.lastApplied+1].Command)// 	rf.lastApplied++// 	rf.applyCh <- ApplyMsg{// 		CommandValid: true,// 		Command:      rf.log[rf.lastApplied].Command,// 		CommandIndex: rf.lastApplied,// 	}// }rf.mu.Unlock()time.Sleep(time.Duration(10) * time.Millisecond)}
}

这篇关于MIT6.5840-2023-Lab2B: Raft-Log的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

如何自定义一个log适配器starter

《如何自定义一个log适配器starter》:本文主要介绍如何自定义一个log适配器starter的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求Starter 项目目录结构pom.XML 配置LogInitializer实现MDCInterceptor

Nacos日志与Raft的数据清理指南

《Nacos日志与Raft的数据清理指南》随着运行时间的增长,Nacos的日志文件(logs/)和Raft持久化数据(data/protocol/raft/)可能会占用大量磁盘空间,影响系统稳定性,本... 目录引言1. Nacos 日志文件(logs/ 目录)清理1.1 日志文件的作用1.2 是否可以删除

SQL中redo log 刷⼊磁盘的常见方法

《SQL中redolog刷⼊磁盘的常见方法》本文主要介绍了SQL中redolog刷⼊磁盘的常见方法,将redolog刷入磁盘的方法确保了数据的持久性和一致性,下面就来具体介绍一下,感兴趣的可以了解... 目录Redo Log 刷入磁盘的方法Redo Log 刷入磁盘的过程代码示例(伪代码)在数据库系统中,r

golang 日志log与logrus示例详解

《golang日志log与logrus示例详解》log是Go语言标准库中一个简单的日志库,本文给大家介绍golang日志log与logrus示例详解,感兴趣的朋友一起看看吧... 目录一、Go 标准库 log 详解1. 功能特点2. 常用函数3. 示例代码4. 优势和局限二、第三方库 logrus 详解1.

使用@Slf4j注解,log.info()无法使用问题

《使用@Slf4j注解,log.info()无法使用问题》在使用Lombok的@Slf4j注解打印日志时遇到问题,通过降低Lombok版本(从1.18.x降至1.16.10)解决了问题... 目录@Slf4androidj注解,log.info()无法使用问题最后解决总结@Slf4j注解,log.info(

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

HNU-2023电路与电子学-实验3

写在前面: 一、实验目的 1.了解简易模型机的内部结构和工作原理。 2.分析模型机的功能,设计 8 重 3-1 多路复用器。 3.分析模型机的功能,设计 8 重 2-1 多路复用器。 4.分析模型机的工作原理,设计模型机控制信号产生逻辑。 二、实验内容 1.用 VERILOG 语言设计模型机的 8 重 3-1 多路复用器; 2.用 VERILOG 语言设计模型机的 8 重 2-1 多

ImportError: cannot import name ‘print_log‘ from ‘logging‘

mmcv升级到2.+后删除了很多 解决 查FAQ文档,找到 添加到mmcv.utils下即可

DAY16:什么是慢查询,导致的原因,优化方法 | undo log、redo log、binlog的用处 | MySQL有哪些锁

目录 什么是慢查询,导致的原因,优化方法 undo log、redo log、binlog的用处  MySQL有哪些锁   什么是慢查询,导致的原因,优化方法 数据库查询的执行时间超过指定的超时时间时,就被称为慢查询。 导致的原因: 查询语句比较复杂:查询涉及多个表,包含复杂的连接和子查询,可能导致执行时间较长。查询数据量大:当查询的数据量庞大时,即使查询本身并不复杂,也可能导致