注册中心的心跳和健康检查有什么区别?
简化版
心跳主要表示实例进程或注册客户端还活着,通常由服务实例定期向注册中心续约。健康检查更关注实例是否真的能对外提供服务,可能检查 HTTP 健康接口、依赖状态、线程池、数据库连接等。
心跳通过不一定代表业务健康;健康检查失败也不一定代表进程死亡。工程上常把两者结合,用心跳判断实例存活,用健康检查判断是否可接流量。
详细版
心跳是注册中心维持实例租约的机制。实例定期发送续约请求,如果超过一定时间没有续约,注册中心会认为实例失联并摘除。它解决的是“实例是否还在和注册中心保持联系”的问题。
健康检查解决的是“实例是否能正常处理请求”的问题。一个进程可能还在发心跳,但数据库连接池耗尽、线程池阻塞、关键依赖不可用,这时它虽然活着,却不应该继续接收流量。健康检查可以由实例自检并上报,也可以由注册中心或负载均衡主动探测。
面试时要说清楚:心跳偏存活,健康检查偏可服务。摘除策略不能过于激进,否则网络抖动会误摘;也不能过于保守,否则坏实例会长期留在调用列表中。
完整版教学
一、心跳解决的是租约问题
注册中心保存实例信息时,不能假设实例永远存在。实例可能因为宕机、网络断开、容器销毁等原因消失。如果实例消失后注册中心还保留它,消费者就会调用到坏地址。
心跳机制类似租约。实例注册后需要定期续约,告诉注册中心“我还在”。如果超过租约时间没有续约,注册中心就认为这个实例失效。
典型参数包括:
- 心跳间隔:实例多久发送一次心跳。
- 过期时间:多久没收到心跳认为失效。
- 剔除周期:注册中心多久扫描一次过期实例。
这些参数影响故障发现速度和误判概率。
二、健康检查解决的是可服务问题
实例进程活着,不代表它能正常服务。例如:
- HTTP 端口还在,但业务线程池满了。
- 注册客户端还能发心跳,但数据库连接不可用。
- 进程没有退出,但 Full GC 或死锁导致请求处理很慢。
- 依赖的缓存或消息队列异常,核心功能不可用。
健康检查要比心跳更贴近业务可用性。常见健康检查包括 /health 接口、依赖连通性、线程池队列、磁盘空间、关键资源状态等。
三、心跳和健康检查的组合方式
常见组合有两种。
第一种是实例自检后上报状态。实例内部定期检查自身健康,如果不健康,就向注册中心更新状态为不可用。
第二种是注册中心或外部组件主动探测。注册中心定期调用实例健康接口,根据结果更新实例状态。
自检上报成本低,能检查更多内部状态;主动探测更独立,可以发现实例进程无法主动上报的问题。大型系统可能两者结合使用。
四、摘除策略要避免误伤
注册中心摘除实例不能太激进。网络短暂抖动、GC 暂停、注册中心自身压力升高,都可能导致心跳延迟。如果一延迟就立即剔除大量实例,消费者看到的可用实例会突然减少,流量集中到剩余实例,反而造成雪崩。
因此通常会设置合理的超时时间、连续失败次数、保护阈值和恢复策略。例如只有连续多次健康检查失败才标记不可用,恢复时也可以先低权重接流量,避免刚恢复实例被瞬间打满。
五、心跳通过但健康失败怎么办
如果心跳正常但健康检查失败,说明实例还活着但不适合接流量。注册中心可以把实例标记为 DOWN 或 OUT_OF_SERVICE,消费者负载均衡时应跳过该实例。
这类场景在发布和故障中都很常见。比如服务正在优雅下线时,可以继续保持进程和心跳,但健康状态改为不可接新请求,等待存量请求处理完再退出。
六、健康检查也不能检查过重
健康检查不能做得太重。比如每次健康检查都执行复杂 SQL 或调用多个下游,会给系统增加额外压力,也可能因为某个非核心依赖短暂异常导致实例被误判不可用。
更好的做法是分层:
- 存活检查:进程是否还在,端口是否可访问。
- 就绪检查:关键初始化是否完成,是否可接流量。
- 深度检查:用于监控告警,不一定直接影响摘除。
Kubernetes 中的 liveness 和 readiness 思路也类似:存活和就绪要区分。
七、面试回答建议
回答时先给定义:心跳判断实例是否和注册中心保持联系,健康检查判断实例是否具备服务能力。然后举例说明心跳正常但业务不健康的情况。
最后补充工程取舍:摘除不能过激,健康检查不能太重,要区分存活、就绪和深度检查,并配合优雅下线。
八、常见追问和落地边界
面试官可能会问健康检查是不是越全面越好。答案是否定的。健康检查越重,对服务本身和依赖的压力越大,也越容易因为非核心依赖抖动导致实例被误摘除。健康检查要分层,核心接流量检查要轻量、稳定、快速。
还有一个边界是健康检查不能替代业务容错。注册中心把不健康实例摘除需要时间,消费者仍然可能在窗口期调用到坏实例。所以调用方的超时、重试、熔断和失败实例避让仍然必不可少。
还可以补充一个线上判断标准:健康检查结果最好和流量入口一致。如果健康检查走的是一个几乎不依赖任何组件的空接口,但真实业务请求都依赖数据库和缓存,那么健康检查显示健康并不代表业务真的健康。反过来,如果健康检查把所有下游都检查一遍,任何非核心下游抖动都会导致实例被摘除。更合理的是把核心依赖纳入就绪检查,把非核心依赖放到监控告警里。
九、常见误区与追问
这道题要紧扣「心跳与健康检查」本身回答,不能把它混成泛泛的服务注册与发现套话。面试官通常会沿着“为什么需要、流程怎么走、失败怎么兜、代价是什么”继续追问,所以回答要覆盖注册、心跳、健康检查、实例缓存、路由选择和注册中心故障兜底。
| 回答层次 | 要讲清的内容 | 容易漏掉的边界 |
|---|---|---|
| 核心结论 | 心跳证明实例仍在续约,健康检查判断实例是否真的能承接业务流量,两者要结合使用 | 不要停在名词解释 |
| 流程机制 | 实例上报心跳 -> 注册中心更新租约 -> 健康检查探测接口 -> 连续失败计数 -> 摘除或降权实例 -> 恢复后预热加回 | 要说清触发点、状态变化、确认点和失败兜底 |
| 工程取舍 | 5 秒一次心跳、连续 3 次失败摘除,故障发现至少约 15 秒;阈值太短会误摘,太长会扩大故障窗口 | 服务发现降低地址治理成本,但会引入缓存陈旧、摘除延迟、注册中心可用性和客户端行为一致性问题 |
心跳与健康检查 面试拆解:
1. 实例上报心跳
2. 注册中心更新租约
3. 健康检查探测接口
4. 连续失败计数
5. 摘除或降权实例
6. 恢复后预热加回
记忆钩子:先给结论,再拆流程,再讲数字例子和失败边界;回答「心跳与健康检查」时要围绕题目问法收束,不要把相邻概念堆成一段没有重点的名词清单。
- 误区:心跳正常就代表服务健康。 进程活着但线程池满、数据库断连时业务仍可能不可用。
- 误区:健康检查越深越好。 深度检查成本高,可能把依赖抖动放大成实例摘除。
- 误区:一次失败就该下线。 网络毛刺常见,要连续失败阈值和恢复阈值。
- 追问:存活检查和就绪检查区别? 存活看进程是否该重启,就绪看是否能接流量。
- 追问:如何避免大面积误摘? 限制摘除比例、保留最小实例数,并结合熔断保护。
- 追问:恢复后为什么预热? 避免冷缓存、冷连接和瞬时流量让刚恢复实例再次失败。
十、加强记忆
心跳像“人还在打卡”,健康检查像“人能不能正常干活”。一个人能打卡,不代表身体状态和工具状态都适合上岗。
注册中心要同时关心活没活着,也要关心能不能接流量。