1. 健康检查概述
聊容灾之前,咱们得先把“健康检查”这事儿聊透。我刚开始做运维那会儿,觉得健康检查就是个“ping”一下的事儿。直到有一次线上故障,数据库主库挂了整整15分钟,我们竟然没人知道。嗯,从那以后,我才真正开始重新审视什么是健康检查。
1.1 什么是健康检查
说白了,健康检查就是一套自动化的“望闻问切”流程。它定期去探测你的系统、服务或实例,看它们到底还能不能正常工作。
你想想看,一个服务进程还活着,不代表它就能正常响应请求。我在项目中遇到过不少这样的情况:进程在,端口也在,但业务已经慢到无法忍受了。这时候,简单的“ping端口”就完全不管用。
所以,健康检查要做的,是确认三个层次的问题:
- 存活检查:进程还在不在?端口还开着没?
- 就绪检查:服务有没有准备好接收流量?
- 业务检查:核心业务接口能不能在预期时间内返回正确结果?
1.2 健康检查的目的与重要性
为什么要费这么大劲做健康检查?直接写个脚本监控CPU内存不行吗?
我个人的理解是,健康检查解决了一个最核心的问题:快速确认系统是否具备对外提供服务的能力。它不是为了发现问题,而是为了在问题发生的那一刻,立刻触发决策——到底是继续用这台机器,还是把它摘掉,换一台干净的上来。
我梳理了一下,健康检查的目的可以归纳为三点:
- 服务摘流量:一旦检查发现实例不健康,立刻通知负载均衡把流量切走,防止故障扩散。我曾经因为漏配了一个健康检查,导致一台内存泄漏的服务器继续接收请求,最终把整个集群拖垮了。
- 触发恢复:通知编排平台重启容器或重建实例,把不健康的状态重置掉。
- 辅助决策:在发布、扩缩容、容灾切换的瞬间,健康检查结果是判断“是否成功”的唯一标准。
1.3 健康检查的分类
为了把这些概念讲明白,我画了一张结构图,把健康检查的分类体系呈现出来。
从上面的图你能看出来,健康检查可以从三个维度来分类。在实际工作中,我们往往需要把它们组合起来用。我来详细说说每一类。
按检查层次来分
这是最实用的分类方式。我一般会把它做成一个金字塔:
- 存活检查(Liveness Probe):最简单的逻辑。进程活着吗?端口通着吗?它只告诉你“死没死”。如果挂了,就重启。
- 就绪检查(Readiness Probe):服务有没有能力处理请求?比如,应用刚启动完,但缓存还没预热。这时候存活检查是通的,但就绪检查应该返回失败。流量就不会打进去。
- 业务自定义检查:这是我最看重的。比如数据库连接池里还能不能拿到连接?核心API的P99延迟是否超过了100ms?我曾经见过一个案例:缓存集群里的节点全挂了,但每个节点上的sentinel进程还活着,存活检查全绿,业务已经瘫痪了5分钟。原因就是没人做业务层面的检查。
按检查主体来分
这决定了你怎么去“问”系统:
| 检查方式 | 原理 | 适用场景 | 缺点 |
|---|---|---|---|
| TCP探查 | 尝试建立TCP连接,成功即视为健康 | 基础网络连通性、后端服务端口检查 | 无法感知业务状态,连接成功后什么都不代表 |
| HTTP探查 | 发送GET/POST请求,根据状态码判断 | Web服务、API网关、微服务 | 需要应用暴露健康端点,增加一点性能开销 |
| gRPC/自定义协议 | 通过自定义接口或gRPC health协议交互 | 内部微服务体系、长连接网关 | 实现较复杂,需要SDK支持 |
我的经验:我通常把HTTP探查作为第一选择。因为它最灵活,健康端点里甚至可以返回“整体健康度评分”。我曾经在一个高并发项目里,把健康检查设计成“累进式检查”——前两次快速返回200,第三次全量检查并附带慢查询检测。这样既保证了探测的轻量,又能在需要时深入检查。
按触发方式来分
这一点容易被忽视,但容灾场景下特别重要:
- 被动检查:流量进来后,服务才返回状态。比如客户端请求超时,就认为实例不健康。这种方式有风险——脏流量可能已经进入系统了。
- 主动检查:由监控系统或负载均衡器主动发请求去检测实例状态。这样能在流量进入之前就做出决策。容灾切换必须用主动检查,被动检查只能作为补充。
你想想看,容灾切换的瞬间,我们需要的是一个“确定性”——这台机器到底能不能接流量。主动检查能给出这个确定性。我建议所有核心服务都把主动检查作为容灾切流的前提条件。