MIT6.5840-2023-Lab2A: Raft-leader election

前置知识

raft-图1.jpg

什么是一致性算法?

  • 安全性保证,绝对不会返回一个错误的结果;
  • 可用性,容忍集群部分节点失败;
  • 不依赖时序来保证一致性;
  • 一条指令可以尽可能快的在集群中大多数节点响应一轮远程过程调用时完成。小部分比较慢的节点不会影响系统整体的性能;

Raft

总结:
image.png
服务器状态转移:
跟随者只响应来自其他服务器的请求。如果跟随者接收不到消息,那么他就会变成候选人并发起一次选举。获得集群中大多数选票的候选人将成为领导人。在一个任期内,领导人一直都会是领导人,直到自己宕机了。
raft-图4.jpg
避免脑裂:奇数个服务器,在任何时候为了完成任何操作,必须凑够过半的服务器来批准相应的操作。

例如,当一个Raft Leader竞选成功,那么这个Leader必然凑够了过半服务器的选票,而这组过半服务器中,必然与旧Leader的过半服务器有重叠。所以,新的Leader必然知道旧Leader使用的任期号(term number),因为新Leader的过半服务器必然与旧Leader的过半服务器有重叠,而旧Leader的过半服务器中的每一个必然都知道旧Leader的任期号。类似的,任何旧Leader提交的操作,必然存在于过半的Raft服务器中,而任何新Leader的过半服务器中,必然有至少一个服务器包含了旧Leader的所有操作。这是Raft能正确运行的一个重要因素。

应用程序代码和 Raft 库:应用程序代码接收 RPC 或者其他客户端请求;不同节点的 Raft 库之间相互合作,来维护多副本之间的操作同步。
Log 是 Leader 用来对操作排序的一种手段。Log 与其他很多事物,共同构成了 Leader 对接收到的客户端操作分配顺序的机制。还有就是能够向丢失了相应操作的副本重传,也需要存储在 Leader 的 Log 中。而对于 Follower 来说,Log 是用来存放临时操作的地方。Follower 收到了这些临时的操作,但是还不确定这些操作是否被 commit 了,这些操作可能会被丢弃。对所有节点而言,Log 帮助重启的服务器恢复状态
避免分割选票:为选举定时器随机地选择超时时间。

broadcastTime ≪ electionTimeout ≪ MTBF(mean time between failures)

RAFT 与应用程序交互:
image.png

实验内容

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

实验环境

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

踩过的坑

  • 死锁:if语句提前return,未释放锁;
  • 发rpc前后都要check状态是否已经改变;
  • 开启进程过多,导致程序运行缓慢,leader election时间延长,从而导致多次选举;这也就是为什么论文要求broadcastTime ≪ electionTimeout ≪ MTBF;这种情况主要每几千次测试发生一次;
  • 多次测试!最好测试1w次;
  • 代码后续更新在:https://github.com/BeGifted/MIT6.5840-2023

Part 2A: leader election

这部分主要实现选出一位领导人,如果没有失败,该领导人将继续担任领导人;如果旧领导人 fail 或往来于旧领导人的 rpc 丢失,则由新领导人接任。同时实现心跳定时发送。

raft、rpc格式

后续lab会增加内容。

type Raft struct {mu        sync.Mutex          // Lock to protect shared access to this peer's statepeers     []*labrpc.ClientEnd // RPC end points of all peerspersister *Persister          // Object to hold this peer's persisted stateme        int                 // this peer's index into peers[]dead      int32               // set by Kill()// Your data here (2A, 2B, 2C).// Look at the paper's Figure 2 for a description of what// state a Raft server must maintain.state int // follower\candidate\leadercurrentTerm int     // last term server has seenvotedFor    int     // candidateId that received votelog         []Entry // log entriescommitIndex int // index of highest entry committedlastApplied int // index of highest entry applied to state machinenextIndex  []intmatchIndex []inttimeout    time.DurationexpiryTime time.Time
}type RequestVoteArgs struct {// Your data here (2A, 2B).Term         int //candidate termCandidateId  intLastLogIndex intLastLogTerm  int
}type RequestVoteReply struct {// Your data here (2A).Term        int // currentTermVoteGranted bool
}type AppendEntriesArgs struct {Term         int //leader termLeaderId     intPrevLogIndex intPrevLogTerm  intEntries      []EntryLeaderCommit int // leader commitIndex
}type AppendEntriesReply struct {Term    int // currentTermSuccess bool
}

RequestVote

  • follower 一段时间未收到心跳发送 RequestVote,转为 candidate;
  • candidate 一段时间未收到赞成票发送 RequestVote,维持 candidate;
  • 接收 RequestVote 的 server:
    • T < currentTerm:reply false;
    • T >= currentTerm && votedFor is nil or candidateId && 日志较旧:reply true;转为 follower;
    • else:reply false;
  • RequestVoteReply:看返回的 term 如果比 currentTerm 大,转为 follower;否则计算投票数。

AppendEntries

  • 心跳,不带 entries,维持 leader;
  • 日志复制,在 last log index ≥ nextIndex[i] 时触发;
  • 接收 AppendEntries 的server:
    • term < currentTerm || prevLogIndex 上 entry 的 term 与 prevLogTerm 不匹配:reply false;
    • 删除冲突的 entries,添加 new entries;
    • leaderCommit > commitIndex:commitIndex = min(leaderCommit, index of last new entry);
  • AppendEntries 返回:
    • 成功:更新 nextIndex[i]、matchIndex[i];
    • 失败:减少 nextIndex[i],retry;

ticker

用于当某个 follower 一段时间未收到 AppendEntries 时,开启竞选 leader。

func (rf *Raft) ticker() {for rf.killed() == false {// Your code here (2A)// Check if a leader election should be started.if rf.state != Leader && time.Now().After(rf.expiryTime) {go func() { // leader selectionrf.mu.Lock()rf.state = Candidaterf.votedFor = rf.merf.currentTerm++timeout := time.Duration(250+rand.Intn(300)) * time.Millisecondrf.expiryTime = time.Now().Add(timeout)rf.persist()numGrantVote := 1 // self grantargs := RequestVoteArgs{Term:         rf.currentTerm,CandidateId:  rf.me,LastLogIndex: len(rf.log) - 1,LastLogTerm:  rf.log[len(rf.log)-1].Term,}rf.mu.Unlock()for i := 0; i < len(rf.peers); i++ {if i == rf.me {continue}go func(i int) {reply := RequestVoteReply{}if ok := rf.sendRequestVote(i, &args, &reply); ok {rf.mu.Lock()if rf.state != Candidate || args.Term != reply.Term || args.Term != rf.currentTerm || reply.Term < rf.currentTerm {rf.mu.Unlock()return}if reply.Term > rf.currentTerm {rf.state = Followerrf.currentTerm = reply.Termrf.votedFor = -1rf.persist()} else if reply.VoteGranted {numGrantVote++if numGrantVote > len(rf.peers)/2 {rf.mu.Unlock()rf.toLeader()return}}rf.mu.Unlock()}}(i)}}()}// pause for a random amount of time between 50 and 350// milliseconds.ms := 50 + (rand.Int63() % 30)time.Sleep(time.Duration(ms) * time.Millisecond)}
}

heart beat

func (rf *Raft) heartBeat() {for rf.killed() == false {rf.mu.Lock()if rf.state != Leader {rf.mu.Unlock()return}rf.mu.Unlock()for i := 0; i < len(rf.peers); i++ {if i == rf.me {continue}go func(i int) {rf.mu.Lock()if rf.state != Leader {rf.mu.Unlock()return}log.Println(i, "rf.nextIndex[i]", rf.nextIndex[i], "len", len(rf.log))args := AppendEntriesArgs{Term:         rf.currentTerm,LeaderId:     rf.me,PrevLogIndex: rf.nextIndex[i] - 1,PrevLogTerm:  rf.log[rf.nextIndex[i]-1].Term,Entries:      []Entry{},LeaderCommit: rf.commitIndex,}reply := AppendEntriesReply{}rf.mu.Unlock()var o boolif ok := rf.sendAppendEntries(i, &args, &reply); ok {rf.mu.Lock()o = okif rf.state != Leader || args.Term != reply.Term || args.Term != rf.currentTerm || reply.Term < rf.currentTerm {rf.mu.Unlock()return}if reply.Term > rf.currentTerm {rf.state = Followerrf.currentTerm = reply.Termrf.votedFor = -1rf.persist()rf.mu.Unlock()return}if reply.Success {rf.nextIndex[i] = args.PrevLogIndex + len(args.Entries) + 1rf.matchIndex[i] = args.PrevLogIndex + len(args.Entries)} else {rf.nextIndex[i] = args.PrevLogIndex}rf.mu.Unlock()}log.Println(rf.me, "send AppendEntries to", i, o, ": currentTerm=", rf.currentTerm, "reply.Term=", reply.Term, "reply.Success", reply.Success)}(i)}time.Sleep(time.Duration(50) * time.Millisecond)}
}

实验结果

测试10000次:
在这里插入图片描述

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

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

相关文章

uniapp实战 —— 可滚动区域 scroll-view (自适配高度,下拉刷新)

自适配高度 自定义的顶部导航栏&#xff0c;可参考博文 https://blog.csdn.net/weixin_41192489/article/details/134852124 如图可见&#xff0c;在页面滚动过程中&#xff0c;顶部导航栏和底栏未动&#xff0c;仅中间的内容区域可滚动。 整个页面的高度设置为 100%&#xf…

鸿蒙开发—学习声明式UI

基本UI描述 ArkTS通过装饰器Component和Entry装饰struct关键字声明的数据结构&#xff0c;构成一个自定义组件。自定义组件中提供了一个build函数&#xff0c;开发者需在该函数内以链式调用的方式进行基本的UI描述&#xff0c;UI描述的方法请参考UI描述规范。 基本概念 stru…

GZ029 智能电子产品设计与开发赛题第4套

2023年全国职业院校技能大赛高职组 “GZ029智能电子产品设计与开发”赛项赛卷四 题目&#xff1a;模拟工业传送带物品检测系统的设计与开发 1 竞赛任务 在智能电视机上播放工业传送带传输物品视频&#xff0c;模拟工业传送带物品检测系统&#xff08;以下简称物品检测系统&…

DALI1.0学习——BIT解码

最近在学习DALI调光相关知识并下载了Microchip提供的基于ATMega88PA的软件工程及硬件设计参考方案。写这些文章的目的就是把自己对知识的理解作一些梳理。 芯片厂果然专业&#xff0c;考虑得相当周到&#xff0c;为了芯片销量连软件和硬件方案全都提供了。芯片厂关于DALI1.0实…

【unity小技巧】实现枪武器随镜头手臂摇摆效果

文章目录 前言方法一、改变武器位置方法二、改变武器旋转结语完结 前言 如果我们视角移动转向&#xff0c;武器如果不跟着进行摇摆&#xff0c;会感觉我们的动作很生硬&#xff0c;特别是射击类游戏&#xff0c;如下 实现武器摇摆这里主要分享两种实现方法&#xff0c;一种是…

SSD数据在写入NAND之前为何要随机化?-Part1

SSD的存储介质是什么&#xff0c;它就是NAND闪存。那你知道NAND闪存是怎么工作的吗&#xff1f;其实&#xff0c;它就是由很多个晶体管组成的。这些晶体管里面存储着电荷&#xff0c;代表着我们的二进制数据&#xff0c;要么是“0”&#xff0c;要么是“1”。NAND闪存原理上是一…

0基础学java-day14-(集合)

一、集合 前面我们保存多个数据使用的是数组&#xff0c;那么数组有不足的地方&#xff0c;我们分析一下 1.数组 2 集合 数据类型也可以不一样 3.集合的框架体系 Java 的集合类很多&#xff0c;主要分为两大类&#xff0c;如图 &#xff1a;[背下来] package com.hspedu.c…

设计模式之GoF23介绍

深入探讨设计模式&#xff1a;构建可维护、可扩展的软件架构 一、设计模式的背景1.1 什么是设计模式1.2 设计模式的历史 二、设计模式的分类2.1 创建型模式2.2 结构型模式2.3 行为型模式 三、七大设计原则四、设计模式关系结论 :rocket: :rocket: :rocket: 在软件开发领域&…

算法:爬楼梯(迭代和动态规划)

迭代 时间复杂度 O(n) 空间复杂度 O(1) /*** param {number} n* return {number}*/ var climbStairs function(n) {let l 0, r 0 , sum 1for(let i1; i<n; i){l rr sumsum l r}return sum }; 动态规划 时间复杂度 O(n) 空间复杂度 O(n) /*** param {number} n* r…

【密码学基础】Diffie-Hellman密钥交换协议

DH介绍 Diffie-Hellman密钥协议算法是一种确保共享密钥安全穿越不安全网络的方法。 这个机制的巧妙在于需要安全通信的双方可以用这个方法确定对称密钥&#xff0c;然后可以用这个密钥进行加密和解密。 但是注意&#xff0c;这个密钥交换协议 只能用于密钥的交换&#xff0c;而…

Java面试题(每天10题)-------连载(45)

Dubbo篇 1、Dubbo的服务调用流程 2、Dubbo支持那种协议&#xff0c;每种协议的应用场景&#xff0c;优缺点&#xff1f; dubbo&#xff1a; 单一长连接和 NIO 异步通讯&#xff0c;适合大并发小数据量的服务调用&#xff0c;以及消费者远大于提供者。传输协议 TCP&#xff0c;…

Proteus仿真--射击小游戏仿真设计

本文介绍基于proteus射击小游戏仿真设计&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真图如下 K1-K4为4个按键&#xff0c;用于上移、下移、确认等&#xff0c;模拟单机游戏 仿真运行视频 Proteus仿真--射击小游戏仿真设计 附完整Proteus仿真资料代码资料 …

ArcGIS界面显示分辨率调整

因为电脑显示分辨率的问题呢&#xff0c;ArcGIS的界面显示会字体显示不合适&#xff0c;出现模糊情况&#xff0c;这时候只需要做个简单的操作设置一下便可以解决&#xff01; 1、右键ArcMap的快捷启动方式。 2、对应选择兼容性——>更高DPI设置——>勾选替代DPI缩放行为…

体系化学习运筹学基础算法的实践和总结

文章目录 引言目标设计目标实践文章汇总经验总结一则预告 引言 眨眼间已经12月了&#xff0c;眼看着2023年马上要过完了。 女朋友最近总说&#xff0c;工作以后感觉时间过的好快。事实上&#xff0c;我也是这么认为的。年纪越大&#xff0c;越会担心35岁危机的降临。所以&…

Xubuntu16.04系统中使用EDIMAX EW-7822UAC无线网卡开启5G自发AP

目录 1.关于 EDIMAX EW-7822UAC2.驱动安装3.查看无线网卡信息3.通过create_ap配置5G自发AP 1.关于 EDIMAX EW-7822UAC 官网介绍 https://www.edimax.com/edimax/merchandise/merchandise_detail/data/edimax/global/wireless_adapters_ac1200_dual-band/ew-7822uac/ 详细参数…

Python开发运维:Python项目发布到K8S集群

目录 一、实验 1.Python项目发布到K8S集群 一、实验 1.Python项目发布到K8S集群 &#xff08;1&#xff09;获取应用程序代码 #把hello-python.tar.gz压缩包上传到k8s控制节点master1的root下&#xff0c;手动解压 tar zxvf hello-python.tar.gz &#xff08;2&#xff0…

【Linux】进程周边001之进程概念

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.基本概念 2.描述进程-PCB…

LeetCode5.最长回文子串

昨天和之前打比赛的队友聊天&#xff0c;他说他面百度面到这道算法题&#xff0c;然后他用暴力法解的&#xff0c;面试官让他优化他没优化出来&#xff0c;这道题我之前没写过&#xff0c;我就想看看我能不能用效率高一点的方法把它做出来&#xff0c;我一开始就在想用递归或者…

设计CPU功能的数字电路

实验目的(1)熟悉Multisim 电路仿真软件的操作界面和功能; (2)掌握逻辑电路综合设计,并采用仿真软件进行仿真。 实验内容1.试设计一个简易CPU功能的数字电路,实验至少要求采用4个74HC/HCT194作为4个存储单元(可以预先对存储单元存储数据),74HC283作为计算单元。请实现…

多维时序 | MATLAB实现RIME-CNN-LSTM-Multihead-Attention多头注意力机制多变量时间序列预测

多维时序 | MATLAB实现RIME-CNN-LSTM-Multihead-Attention多头注意力机制多变量时间序列预测 目录 多维时序 | MATLAB实现RIME-CNN-LSTM-Multihead-Attention多头注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现RIME-CNN-…