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