源码解读etcd heartbeat,election timeout之间的拉锯
2022/5/25 1:21:38
本文主要是介绍源码解读etcd heartbeat,election timeout之间的拉锯,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
转一个我在知乎上回答的有关raft election timeout/ heartbeat interval 的回答吧。
答:准确来讲: election是timeout,而heartbeat 是interval, 这样就很容易理解了。
heartbeat interval 是leader 安抚folower的时间,这个时间间隔是体现在leader上,是leader发送心跳的周期 (我xxxx ms 来一次)。
election timeout 是follower能容忍多久没收到心跳开始骚动的时间 (我等你xxxx ms,没来我就起义)。
为压制follower随时起义的骚动,heartbeat timeout 一般小于 election timeout。
楼主说两个配置超时,都会成为候选者,实际上,heartbeat interval/election timeout 是一个此消彼长的拉锯。
-
想象一个刚初始化的集群,大家都是follower,没有heartbeat压制, 各follower节点的election timeout之后开始骚动。
-
在一次选举周期没有选出leader,很可能是选票瓜分了, 需要发起新的选举; 为缓解选票瓜分的情况, 每个节点的election timeout骚动时间是随机的。
-
发生网络分区的时候, 少数派分区的follower收不到leader 的安抚,是不是又要起义,这个时候election timeout也起作用了。
我们结合etcd的默认配置和源码理解:
目前etcd默认heartbeat = 100ms, election = 1000ms
https://github.com/etcd-io/etcd/blob/5fd69102ce785136aeb3168c56adce7957b99e2d/raft/raft.go#L1718
raft 为节点定义了以下状态:
const ( StateFollower StateType = iota StateCandidate StateLeader StatePreCandidate numStates )
becomeLeader 注册了定期发送心跳的动作 r.tick = r.tickHeartbeat
;
becomeFollower becomeCandidate becomePreCandidate 都注册了(没收到安抚而)起义的动作 r.tick = r.tickElection
;
我们以follower节点为例:
func (r *raft) becomeFollower(term uint64, lead uint64) { r.step = stepFollower r.reset(term) r.tick = r.tickElection r.lead = lead r.state = StateFollower r.logger.Infof("%x became follower at term %d", r.id, r.Term) }
r.reset(term)==> r.resetRandomizedElectionTimeout()
会接受传播过来的term,并计算随机选举超时时间。
func (r *raft) resetRandomizedElectionTimeout() { r.randomizedElectionTimeout = r.electionTimeout + globalRand.Intn(r.electionTimeout) }
从上面源码看出,etcd默认配置产生的节点随机超时时间是 [1000,2000]ms。
r.tickElection
会判断:如果当前经历的时间electionElapsed
大于随机超时时间,就开始起义,并重置electionElapsed
时间。
func (r *raft) tickElection() { r.electionElapsed++ if r.promotable() && r.pastElectionTimeout() { r.electionElapsed = 0 if err := r.Step(pb.Message{From: r.id, Type: pb.MsgHup}); err != nil { r.logger.Debugf("error occurred during election: %v", err) } } } func (r *raft) pastElectionTimeout() bool { return r.electionElapsed >= r.randomizedElectionTimeout }
becomePreCandidate 没有r.reset(term)动作,这是一个预投票状态,也称prevote
,这也是etcd的常见面试题。
prevote 是论文作者为解决“分区少数派重新加入集群,因为高term导致集群瞬间不稳定”的提出的方案,etcd 默认加入prevote机制, 在成为真正意义的候选者之前不自增term,先预投票,因为其他节点一直收到心跳,并不会起义,故该节点预投票拿不到多数投票,等到该节点收到leader心跳,自行降为follower,term和Leader一致, 现在这一机制已经插入到每次follower-->Candidate之间。
switch m.Type { case pb.MsgHup: if r.preVote { r.hup(campaignPreElection) } else { r.hup(campaignElection) }
- https://www.jianshu.com/p/1496228df9a9
- https://github.com/etcd-io/etcd
这篇关于源码解读etcd heartbeat,election timeout之间的拉锯的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-15PingCAP 黄东旭参与 CCF 秀湖会议,共探开源教育未来
- 2024-05-13PingCAP 戴涛:构建面向未来的金融核心系统
- 2024-05-09flutter3.x_macos桌面os实战
- 2024-05-09Rust中的并发性:Sync 和 Send Traits
- 2024-05-08使用Ollama和OpenWebUI在CPU上玩转Meta Llama3-8B
- 2024-05-08完工标准(DoD)与验收条件(AC)究竟有什么不同?
- 2024-05-084万 star 的 NocoDB 在 sealos 上一键起,轻松把数据库编程智能表格
- 2024-05-08Mac 版Stable Diffusion WebUI的安装
- 2024-05-08解锁CodeGeeX智能问答中3项独有的隐藏技能
- 2024-05-08RAG算法优化+新增代码仓库支持,CodeGeeX的@repo功能效果提升