Raft协议示意-Golang版本

说明:受b站某视频中liwenzhou讲解启发,但懒得看别人的实现,就自己搞一个

 

  1 package main
  2 
  3 import (
  4     "fmt"
  5     "math/rand"
  6     "sync"
  7     "time"
  8 )
  9 
 10 func main() {
 11     wg := sync.WaitGroup{}
 12     wg.Add(1)
 13 
 14     //启动Leader
 15     L.Start()
 16 
 17     //新建节点
 18     now := time.Now()
 19     for i := 0; i < 3; i++ {
 20         M[i] = &Node{ID: i, Role: 0, HB: make(chan *HeartBeatMsg, 16), VoteFor: -1, ChangeAt: now}
 21     }
 22     //启动所有节点
 23     for _, v := range M {
 24         v.Start()
 25     }
 26 
 27     wg.Wait()
 28 }
 29 
 30 // Leader
 31 var L = &Leader{Node: nil, Term: -1, At: time.Now()}
 32 
 33 // 所有节点
 34 var M = map[int]*Node{}
 35 
 36 // 心跳内容
 37 const (
 38     ASK  = "ASK"
 39     OK   = "OK"
 40     NO   = "NO"
 41     PING = "PING"
 42     PONG = "PONG"
 43 )
 44 
 45 // 心跳间隔
 46 const HeartBeatInterval = time.Second * 2
 47 
 48 // Leader 领导者
 49 type Leader struct {
 50     Node *Node     //领导者节点
 51     Term int       //任期
 52     At   time.Time //任期开始时间
 53 }
 54 
 55 // Raft节点
 56 type Node struct {
 57     ID        int
 58     Role      int                //角色:0跟随者、1候选者、2领导者
 59     HB        chan *HeartBeatMsg //收到的心跳
 60     VoteFor   int                //站谁
 61     ChangeAt  time.Time          //角色变更时间
 62     VoteCount int                //收到的选票数量
 63     VetoCount int                //收到的拒绝票数量
 64     LastAt    time.Time          //上次收到消息的时间
 65 }
 66 
 67 // 心跳报文
 68 type HeartBeatMsg struct {
 69     From int       //发送方ID
 70     At   time.Time //发送时间
 71     Data string    //发送内容
 72 }
 73 
 74 // Leader的启动方法
 75 func (l *Leader) Start() {
 76     go func() {
 77         for {
 78             //领导没事就PING
 79             if l.Node == nil || M == nil || len(M) == 0 {
 80                 <-time.After(time.Second)
 81                 continue
 82             }
 83 
 84             now := time.Now()
 85             for _, n := range M {
 86                 if l.Node == n {
 87                     continue
 88                 }
 89                 fmt.Printf("leader%d send PING\n", l.Node.ID)
 90                 n.HB <- &HeartBeatMsg{From: l.Node.ID, At: now, Data: PING}
 91             }
 92             //每隔1秒PING一次
 93             <-time.After(HeartBeatInterval / 2) //FIXME 不能interval-1啊啊啊
 94 
 95         }
 96     }()
 97 }
 98 
 99 // Node的启动方法
100 func (n *Node) Start() {
101     go func() {
102         for {
103             //
104             select {
105             case <-time.After(HeartBeatInterval):
106                 fmt.Printf("Node%d got no msg in past 2 seconds\n", n.ID)
107                 //run for leader
108                 if L.Node == nil && n.VoteFor == -1 && n.Role == 0 {
109                     n.Role = 1
110                     n.VoteFor = n.ID
111                     n.VoteCount = 1
112                     d := rand.Intn(150) + 150
113                     <-time.After(time.Millisecond * time.Duration(d))
114                     n.ChangeAt = time.Now()
115                     n.sendHeartBeat(ASK, n.ChangeAt)
116                 }
117 
118             case hb := <-n.HB:
119                 fmt.Printf("hb %d @ %d\n", hb.From, n.ID)
120                 n.LastAt = hb.At //这个时间,是否有必要都更新?响应的
121                 n.handleHeartBeat(hb)
122 
123             }
124 
125         }
126     }()
127 }
128 
129 // Node发送心跳
130 func (n *Node) sendHeartBeat(data string, at time.Time) {
131     hb := &HeartBeatMsg{From: n.ID, At: at, Data: data}
132     for _, v := range M {
133         if v.ID == n.ID {
134             continue
135         }
136         v.HB <- hb
137     }
138 }
139 
140 // Node处理心跳
141 func (n *Node) handleHeartBeat(hb *HeartBeatMsg) {
142 
143     switch hb.Data {
144     case ASK:
145         if L.Node != nil {
146             fmt.Println("有领导,拒绝")
147             M[hb.From].HB <- &HeartBeatMsg{From: n.ID, Data: NO}
148         }
149         if n.Role == 0 {
150             if n.VoteFor == -1 {
151                 fmt.Printf("%d同意%d\n", n.ID, hb.From)
152                 n.VoteFor = hb.From
153                 M[hb.From].HB <- &HeartBeatMsg{From: n.ID, Data: OK}
154             } else {
155                 fmt.Printf("%d已同意别人,拒绝%d\n", n.ID, hb.From)
156                 M[hb.From].HB <- &HeartBeatMsg{From: n.ID, Data: NO}
157             }
158         } //是不是要判断下候选者的时间,以决定是否同意?
159         if n.Role == 1 {
160             if n.ChangeAt.After(hb.At) {
161                 fmt.Printf("%d同意%d,并将自身变回跟随者\n", n.ID, hb.From)
162                 n.VoteFor = hb.From
163                 n.Role = 0
164                 M[hb.From].HB <- &HeartBeatMsg{From: n.ID, Data: OK}
165             } else {
166                 fmt.Printf("%d不同意%d,%d更早\n", n.ID, hb.From, n.ID)
167                 M[hb.From].HB <- &HeartBeatMsg{From: n.ID, Data: NO}
168             }
169         }
170     case OK:
171         n.VoteCount++
172     case NO:
173         n.VetoCount++
174     case PING:
175         M[hb.From].HB <- &HeartBeatMsg{From: n.ID, Data: PONG}
176     case PONG:
177     }
178     // 其实当选后,应该清理所有的状态
179     if n.Role != 1 {
180         return
181     }
182     //判断是否当选,或者是否失败
183     if n.VetoCount+n.VoteCount == len(M) {
184         now := time.Now()
185         if n.VoteCount > len(M)/2 {
186             n.Role = 2
187             n.ChangeAt = now
188             n.VoteFor = -1
189             n.VetoCount = 0
190             n.VoteCount = 0
191             L.Node = n
192             L.Term++
193             L.At = now
194 
195             fmt.Println("!!!LEADER", L.Node.ID)
196         } else {
197             n.Role = 0
198             n.ChangeAt = now
199             n.VoteFor = -1
200             n.VetoCount = 0
201             n.VoteCount = 0
202         }
203     }
204 }

 

运行:

[Running] go run "c:\Users\Administrator\GoProjects\bilibili\raft\main.go"
Node2 got no msg in past 2 seconds
Node0 got no msg in past 2 seconds
Node1 got no msg in past 2 seconds
hb 1 @ 0
hb 0 @ 1
1不同意0,1更早
0同意1,并将自身变回跟随者
hb 1 @ 0
hb 0 @ 1
hb 1 @ 2
2同意1,并将自身变回跟随者
hb 2 @ 0
0已同意别人,拒绝2
hb 0 @ 2
2已同意别人,拒绝0
hb 2 @ 1
1不同意2,1更早
hb 2 @ 1
!!!LEADER 1
hb 2 @ 0
hb 0 @ 2
hb 1 @ 2
leader1 send PING
leader1 send PING
hb 1 @ 2
hb 2 @ 1
hb 1 @ 0
hb 0 @ 1
leader1 send PING
leader1 send PING
hb 1 @ 2
hb 2 @ 1
hb 1 @ 0
hb 0 @ 1

 

posted on 2022-09-27 20:23  LarryZeal  阅读(96)  评论(0编辑  收藏  举报

导航