You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:02:51