6.824 Raft lesson4 2020(一)
生活随笔
收集整理的這篇文章主要介紹了
6.824 Raft lesson4 2020(一)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
raft實現
距離上一篇文章一個月,因為6.824的課程看不懂,基礎知識薄弱。現在了解一點Raft算法(自己動手實現一遍)還需要其他分布式相關的基礎知識(實現一個分布式對象存儲系統),然后再去繼續學習。總結一下,如果直接就去學習6.824的課程收效甚微,一定要有一定基礎知識儲備才可以!
這塊代碼是網上開源的代碼,閱讀之后還是發現很多問題。但是值得借鑒學習
Raft算法簡單實現。
package mainimport ("fmt""log""math/rand""net/http""net/rpc""sync""time" )const raftCount = 5//聲明leader對象 type Leader struct {//任期Term int//領導編號LeaderId int }//創建存儲leader的對象 //最初任期為0,-1代表沒編號 var leader = Leader{0, -1}//聲明raft節點類型 type Raft struct {//鎖mu sync.Mutex//節點編號me int//當前任期currentTerm int//為哪個節點投票votedFor int//當前節點狀態//0 follower 1 candidate 2 leaderstate int//發送最后一條消息的時間lastMessageTime int64//當前節點的領導currentLeader int//消息通道message chan bool//選舉通道electCh chan bool//心跳信號heartBeat chan bool//返回心跳信號hearbeatRe chan bool//超時時間timeout int }func main() {for i := 0; i < raftCount; i++ {//定義Make() 創建節點Make(i)}//對raft結構體實現rpc注冊rpc.Register(new(Raft))rpc.HandleHTTP()err := http.ListenAndServe(":8080", nil)if err != nil {log.Fatal(err)}for {;} }//創建節點 func Make(me int) *Raft {rf := &Raft{}//編號rf.me = me//給0 1 2三個節點投票,給誰都不投rf.votedFor = -1//0 followerrf.state = 0rf.timeout = 0//最初沒有領導rf.currentLeader = -1//設置任期rf.setTerm(0)//通道rf.electCh = make(chan bool)rf.message = make(chan bool)rf.heartBeat = make(chan bool)rf.hearbeatRe = make(chan bool)rf.lastMessageTime = 0rf.currentTerm = 0//隨機種子rand.Seed(time.Now().UnixNano())//選舉的邏輯實現go rf.election()//心跳檢查go rf.sendLeaderHeartBeat()return rf }func (rf *Raft) setTerm(term int) {rf.currentTerm = term }func (rf *Raft) election() {var result boolfor {timeout := randRange(150, 300)rf.lastMessageTime = millisecond()select {case <-time.After(time.Duration(timeout) * time.Millisecond):fmt.Println("當前節點狀態為:", rf.state)}result = falsefor !result {result = rf.election_one_rand(&leader)}} }func randRange(min, max int64) int64 {//用于心跳信號的時間等return rand.Int63n(max-min) + min }func millisecond() int64 {return time.Now().UnixNano() / int64(time.Millisecond) }//選leader func (rf *Raft) election_one_rand(leader *Leader) bool {var timeout int64timeout = 100var vote intvar triggerHeartbeat boollast := millisecond()success := false//首先,要成為candidate狀態rf.mu.Lock()rf.becomeCandidate()rf.mu.Unlock()//開始選fmt.Println("start electing leader")for {for i := 0; i < raftCount; i++ {if i != rf.me {go func() {if leader.LeaderId < 0 {rf.electCh <- true}}()}}vote = 0triggerHeartbeat = falsefor i := 0; i < raftCount; i++ {select {case ok := <-rf.electCh:if ok {vote ++success = vote > raftCount/2if success && !triggerHeartbeat {triggerHeartbeat = truerf.mu.Lock()//真正的成為leaderrf.becomeLeader()rf.mu.Unlock()rf.heartBeat <- truefmt.Println(rf.me, "號節點成為了leader") //, "任期:", leader.Term)fmt.Println("leader發送心跳信號")}}}}//間隔時間小于100毫秒左右//若不超時,且票數大于一半,且當前有領導if (timeout+last < millisecond() || (vote >= raftCount/2 || rf.currentLeader > -1)) {break} else {select {case <-time.After(time.Duration(10) * time.Millisecond):}}}return success }//修改節點為candidate狀態 func (rf *Raft) becomeCandidate() {//將節點狀態變為1rf.state = 1//節點任期加1rf.setTerm(rf.currentTerm + 1)//設置為哪個節點投票rf.votedFor = rf.me//當前沒有領導rf.currentLeader = -1 }// 允許節點進行成為leader的競爭,哪一個先獲得多數選票,哪一個就是leader func (rf *Raft) becomeLeader() {//節點狀態變為2,代表leaderrf.state = 2rf.currentLeader = rf.me }func (rf *Raft) sendLeaderHeartBeat() {for {select {case <-rf.heartBeat:rf.sendAppendEntriesImpl()}} }//返回給leader的確認信號 func (rf *Raft) sendAppendEntriesImpl() {if rf.currentLeader == rf.me {var success_count = 0for i := 0; i < raftCount; i++ {if i != rf.me {go func() {rp, err := rpc.DialHTTP("tcp", "127.0.0.1:8080")if err != nil {log.Fatal(err)}var ok = falseer := rp.Call("Raft.Communication", Param{"hello"}, &ok)if er != nil {log.Fatal(err)}if ok {rf.hearbeatRe <- true}}()}}//計算返回確認信號的子節點,若子節點個數>raftCount/2,則校驗成功for i := 0; i < raftCount; i++ {select {case ok := <-rf.hearbeatRe:if ok {success_count++fmt.Println(rf.me, "獲得了", success_count, "選票")if success_count > raftCount/2 {fmt.Println("投票選舉成功,校驗心跳信號成功")defer func() {fmt.Println("Leader is:", rf.me)}()panic("The End")}}}}} }type Param struct {Msg string }func (r *Raft) Communication(p Param, a *bool) error {fmt.Println(p.Msg)*a = truereturn nil }Result
運行結果1
當前節點狀態為: 0 start electing leader 3 號節點成為了leader leader發送心跳信號 hello hello hello hello 3 獲得了 1 選票 3 獲得了 2 選票 3 獲得了 3 選票 投票選舉成功,校驗心跳信號成功 Leader is: 3 panic: The End運行結果2
當前節點狀態為: 0 start electing leader 當前領導是: -1 當前領導是: -1 當前領導是: -1 當前領導是x: 4 4 號節點成為了leader leader發送心跳信號 當前領導是: 4 當前領導是: 4 hello hello hello hello 4 獲得了 1 選票 4 獲得了 2 選票 4 獲得了 3 選票 投票選舉成功,校驗心跳信號成功, Leader是: 4 2020/04/22 14:21:26 The end運行結果3
當前節點狀態為: 0 start electing leader 當前節點狀態為: 0 start electing leader 當前節點狀態為: 0 start electing leader 當前領導是: -1 當前領導是: -1 當前領導是: -1 當前領導是x: 3 3 號節點成為了leader leader發送心跳信號 當前領導是: 3 當前領導是: 3 當前領導是: -1 當前領導是: -1 當前領導是: -1 當前領導是x: 0 0 號節點成為了leader leader發送心跳信號 當前領導是: 0 當前領導是: 0 當前領導是: -1 當前領導是: -1 當前領導是: -1 當前領導是x: 1 1 號節點成為了leader leader發送心跳信號 當前領導是: 1 當前領導是: 1 hello hello hello hello 3 獲得了 1 選票 0 獲得了 1 選票 hello 3 獲得了 2 選票 hello 1 獲得了 1 選票 3 獲得了 3 選票 投票選舉成功,校驗心跳信號成功, Leader是: 3 hello hello 0 獲得了 2 選票 hello hello 1 獲得了 2 選票 0 獲得了 3 選票 投票選舉成功,校驗心跳信號成功, Leader是: 0 hello 1 獲得了 3 選票 投票選舉成功,校驗心跳信號成功, Leader是: 1 hello結果4
leader3 發送了4個hello投票包,這個時候選舉已經成功了。但是node4這個時候,運行到了
//選舉的邏輯實現
go rf.election()
開始了新的選舉。也選舉成功了。
結果5
如果每次隨機的時間不一樣,那么每個都有選舉的機會,就是每個都選舉一次。這是錯的
正確應該是一個進行選舉,其他收到心跳包后就停止leader選舉進程
總結
上面代碼存在的問題:
總結
以上是生活随笔為你收集整理的6.824 Raft lesson4 2020(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 50w买3天遗忘契约是不是每个号只能买一
- 下一篇: 1190. 反转每对括号间的子串 gol