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.pswp.cn/news/213118.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/213118.shtml
英文地址,請注明出處:http://en.pswp.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;一種是…

xtu oj 1271 color

題目描述 Alice在玩一個游戲&#xff0c;她在一個mn的格子里&#xff0c;隨機涂黑k個格子。然后她每次可以把一行或者一列的格子染成紅色&#xff0c;但是這一行中不能有黑色的格子。 請問她最多能把多少個格子涂成紅色&#xff1f; 輸入 第一行是一個整數T(T≤100)&#xf…

華為OD機試 - 數的分解(Java JS Python C)

題目描述 給定一個正整數 n,如果能夠分解為 m(m > 1)個連續正整數之和,請輸出所有分解中,m最小的分解。 如果給定整數無法分解為連續正整數,則輸出字符串"N"。 輸入描述 輸入數據為一整數,范圍為 (1, 2^30] 輸出描述 比如輸入為: 21 輸出: 21=10+11 …

SSD數據在寫入NAND之前為何要隨機化?-Part1

SSD的存儲介質是什么&#xff0c;它就是NAND閃存。那你知道NAND閃存是怎么工作的嗎&#xff1f;其實&#xff0c;它就是由很多個晶體管組成的。這些晶體管里面存儲著電荷&#xff0c;代表著我們的二進制數據&#xff0c;要么是“0”&#xff0c;要么是“1”。NAND閃存原理上是一…

唯創知音WT588F02B語音芯片在電子針療儀中的聲音播放提示應用

在醫療技術領域&#xff0c;電子針療儀作為一種非侵入性的治療設備&#xff0c;被廣泛應用于各種疼痛管理和康復治療。然而&#xff0c;操作電子針療儀需要一定的專業知識和經驗&#xff0c;以確保安全有效的治療。為了解決這一難題&#xff0c;唯創知音WT588F02B語音芯片被應用…

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…

Memcached學習

一、概念 Memcached是一個開源的&#xff0c;高性能的內存緩存軟件&#xff0c;從名稱上看Mem就是內存&#xff0c;二cache是緩存。作用通過在事先規劃好的內存空間中臨時緩存數據庫中的各類數據&#xff0c;以達到減少業務對數據庫的直接高并發訪問&#xff0c;從而達到提升數…

【密碼學基礎】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/ 詳細參數…