转一个我在知乎上回答的有关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 是一个此消彼长的拉锯。

  1. 想象一个刚初始化的集群,大家都是follower,没有heartbeat压制, 各follower节点的election timeout之后开始骚动。

  2. 在一次选举周期没有选出leader,很可能是选票瓜分了, 需要发起新的选举; 为缓解选票瓜分的情况, 每个节点的election timeout骚动时间是随机的。

  3. 发生网络分区的时候, 少数派分区的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)
}

最新文章

  1. android视频播放器
  2. 给iOS开发新手送点福利,简述文本属性Attributes的用法
  3. 如何使用命令行编译以及运行java文件
  4. springmvc+mybatis用多选框批量删除的功能Java代码
  5. 读懂Java中的Socket编程
  6. 【数学】HDU 5753 Permutation Bo
  7. Java面试题之Struts优缺点
  8. HttpWebRequest 基础连接已经关闭: 接收时发生错误
  9. Ioc容器BeanPostProcessor-Spring 源码系列(3)
  10. spring+mybatis事务不起作用的原因
  11. 工程师倾情奉献-Win7 ISO 精简操作说明
  12. HDU 6034---Balala Power!(搜索+贪心)
  13. 配置HAProxy支持https协议
  14. 小程序 - swiper除了左右切换还有上下滚动超出屏幕的内容
  15. (一〇九)UIButton的使用技巧 -imageView、titleLabel、圆角等
  16. Flask中Mysql数据库的常见操作
  17. MySQL导出数据字典
  18. 《剑指offer》第六十三题(股票的最大利润)
  19. Lucene 4.0 正式版发布,亮点特性中文解读[转]
  20. 吴裕雄 python oracle操作数据库(4)

热门文章

  1. 单页应用SPA开发最佳实践
  2. 关于Css的垂直居中的一些方法
  3. H5本地存储:sessionStorage和localStorage
  4. animate.css使用
  5. nodejs全局对象简析
  6. Windows中Nginx配置nginx.conf不生效解决方法(路径映射)
  7. win11拖动窗口造成崩溃的问题
  8. Java当中的HashSet
  9. Spring基于注解自动装配
  10. AcWing 1027. 方格取数(线性DP)