Raft共识算法实现中出现单任期多Leader问题求助
Raft共识算法单任期多Leader异常排查求助
我在实现基础版Raft共识算法时,选举Leader环节出现单任期内存在多个Leader的异常情况,以下是相关代码、日志及集群状态,请求协助排查:
核心实现代码
RequestVote RPC 处理函数
func (rf *Raft) RequestVote(args *RequestVoteArgs, reply *RequestVoteReply) { rf.mu.Lock() defer rf.mu.Unlock() reply.Term = args.Term if rf.currentTerm >= args.Term { reply.VoteGranted = false return } if true { rf.convertToFollower(args.Term, args.CandidateId) DPrintf("term:%v, %v voted %v", args.Term, rf.me, args.CandidateId) reply.VoteGranted = true return } reply.VoteGranted = false }
AppendEntry(心跳)RPC 处理函数
func (rf *Raft) AppendEntry(args *AppendEntryArgs, reply *AppendEntryReply) { rf.mu.Lock() defer rf.mu.Unlock() reply.Term = args.Term if args.Term < rf.currentTerm { reply.Success = false return } if true { if (args.Term > rf.currentTerm) || (args.Term == rf.currentTerm && rf.state == candidate) { rf.convertToFollower(args.Term, args.LeaderId) } rf.lastAppendEntryTime = time.Now() reply.Success = true return } reply.Success = false }
选举启动逻辑
func (rf *Raft) KickStartElection() { rf.mu.Lock() rf.convertToCandidate() term := rf.currentTerm candidateId := rf.me rf.mu.Unlock() var mu sync.Mutex cond := sync.NewCond(&mu) peerDone := 1 peerLength := len(rf.peers) majority := peerLength/2 + 1 vote := 1 var votefrom []int for peer := range rf.peers { if peer == rf.me { continue } go func(peer int) { args := RequestVoteArgs{Term: term, CandidateId: candidateId} reply := RequestVoteReply{} rf.sendRequestVote(peer, &args, &reply) mu.Lock() peerDone++ if reply.VoteGranted { vote++ votefrom = append(votefrom, peer) } cond.Broadcast() mu.Unlock() }(peer) } mu.Lock() for { rf.mu.Lock() if rf.state != candidate { rf.mu.Unlock() break } else { rf.mu.Unlock() } if (peerLength - peerDone) < (majority - vote) { break } if vote >= majority { DPrintf("term:%v,leader:%v,%v", term, rf.me, votefrom) rf.convertToLeader() break } cond.Wait() } mu.Unlock() }
状态转换方法
func (rf *Raft) convertToCandidate() { rf.currentTerm++ rf.state = candidate rf.votedFor = rf.me } func (rf *Raft) convertToLeader() { rf.mu.Lock() rf.state = leader rf.mu.Unlock() rf.sendEntry() } func (rf *Raft) convertToFollower(term int, CandidateId int) { rf.state = follower rf.currentTerm = term rf.votedFor = CandidateId }
异常日志与集群状态
测试异常日志
Test (2A): multiple elections ... 2023/02/19 00:45:07 term:22,leader:4,[5 6 2] 2023/02/19 00:45:07 term:23, 5 voted 6 2023/02/19 00:45:07 term:23, 4 voted 6 2023/02/19 00:45:07 term:23, 2 voted 6 2023/02/19 00:45:07 term:23,leader:6,[5 4 2] 2023/02/19 00:45:07 term:24, 6 voted 2 2023/02/19 00:45:07 term:24, 5 voted 2 2023/02/19 00:45:07 term:24, 4 voted 2 2023/02/19 00:45:07 term:24,leader:2,[6 5 4] 2023/02/19 00:45:07 term:25, 6 voted 4 2023/02/19 00:45:07 term:25, 2 voted 4 2023/02/19 00:45:07 term:25, 5 voted 4 2023/02/19 00:45:07 term:25,leader:4,[6 2 5] --- FAIL: TestManyElections2A (5.52s) config.go:456: term 25 has 2 (>1) leaders [2,4]
任期25时的集群状态
{me: 0, term:11 votedFor:0 state:Candidate} {me: 1, term:14 votedFor:1 state:Candidate} {me: 2, term:25 votedFor:4 state:Leader} {me: 3, term:13 votedFor:3 state:Candidate} {me: 4, term:25 votedFor:4 state:Leader} {me: 5, term:25 votedFor:4 state:Follower} {me: 6, term:25 votedFor:4 state:Follower}
疑问点
从集群状态可见,任期25中,上一任Leader节点2已将票投给节点4,但并未切换为Follower状态。而convertToFollower方法中是先设置state = follower再更新任期和votedFor,逻辑上应该会切换状态。
内容的提问来源于stack exchange,提问作者Broly
相关产品推荐
相关产品推荐

