源码解读etcd heartbeat,election timeout之间的拉锯

发布时间 - 2025-07-11 00:00:00    点击率:

以下是你在知乎上的回答的伪原创版本,保持了原意和图片位置不变:



答:准确来说:election是timeout,而heartbeat 是interval,这样理解起来就很清晰了。

heartbeat interval 是leader安抚follower的时间,这个时间间隔在leader上体现,是leader发送心跳的周期(我每xxxx ms 进行一次心跳)。

election timeout 是follower能够容忍多久没有收到心跳而开始骚动的时间(我等你xxxx ms,如果你没来,我就起义)。

为了压制follower随时起义的骚动,heartbeat interval 通常设置得小于 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://www./link/70a3e3e59bc61c8eb7acfbba1073980c

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 是论文作者为了解决“分区后少数派leader重新加入集群,因为高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)
    }
}

Prevote是一个典型的2PC协议,第一阶段先征求其他节点是否同意选举,如果同意选举则发起真正的选举操作,否则降为Follower角色。这样就避免了网络分区节点重新加入集群,触发不必要的选举操作。

https://www./link/14318e2a43a225fc24ab55f3c0122cf0https://www./link/9154498493d8e734d9c7489c2b6b26d7


# git  # ai  # switch  # red  # github  # etcd  # https  # 是一个  # 降为  # 都是  # 我就  # 这一  # 如果你  # 你在  # 这是一个  # 又要  # 很可能 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Linux系统运维自动化项目教程_Ansible批量管理实战  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  香港服务器部署网站为何提示未备案?  Laravel如何使用.env文件管理环境变量?(最佳实践)  Laravel如何获取当前用户信息_Laravel Auth门面获取用户ID  Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践  Laravel如何使用Service Container和依赖注入?(代码示例)  Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理  高防服务器:AI智能防御DDoS攻击与数据安全保障  Laravel怎么创建控制器Controller_Laravel路由绑定与控制器逻辑编写【指南】  今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】  jquery插件bootstrapValidator表单验证详解  微信公众帐号开发教程之图文消息全攻略  如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)  Laravel Eloquent关联是什么_Laravel模型一对一与一对多关系精讲  原生JS实现图片轮播切换效果  如何用AWS免费套餐快速搭建高效网站?  家族网站制作贴纸教程视频,用豆子做粘帖画怎么制作?  Laravel如何配置中间件Middleware_Laravel自定义中间件拦截请求与权限校验【步骤】  Laravel Eloquent性能优化技巧_Laravel N+1查询问题解决  如何挑选最适合建站的高性能VPS主机?  Laravel如何实现用户密码重置功能?(完整流程代码)  如何在沈阳梯子盘古建站优化SEO排名与功能模块?  海南网站制作公司有哪些,海口网是哪家的?  如何在阿里云虚拟服务器快速搭建网站?  如何在自有机房高效搭建专业网站?  jQuery 常见小例汇总  ChatGPT怎么生成Excel公式_ChatGPT公式生成方法【指南】  宙斯浏览器怎么屏蔽图片浏览 节省手机流量使用设置方法  Laravel API资源类怎么用_Laravel API Resource数据转换  Gemini怎么用新功能实时问答_Gemini实时问答使用【步骤】  谷歌Google入口永久地址_Google搜索引擎官网首页永久入口  如何为不同团队 ID 动态生成多个独立按钮  Laravel怎么连接多个数据库_Laravel多数据库连接配置  大连网站制作公司哪家好一点,大连买房网站哪个好?  手机软键盘弹出时影响布局的解决方法  如何在建站宝盒中设置产品搜索功能?  Laravel事件和监听器如何实现_Laravel Events & Listeners解耦应用的实战教程  香港服务器租用每月最低只需15元?  微信小程序 HTTPS报错整理常见问题及解决方案  WordPress 子目录安装中正确处理脚本路径的完整指南  利用python获取某年中每个月的第一天和最后一天  Laravel如何生成和使用数据填充?(Seeder和Factory示例)  Laravel如何使用withoutEvents方法临时禁用模型事件  如何快速搭建个人网站并优化SEO?  免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?  手机网站制作与建设方案,手机网站如何建设?  JavaScript如何实现路由_前端路由原理是什么  高性能网站服务器配置指南:安全稳定与高效建站核心方案  如何在搬瓦工VPS快速搭建网站?