故障检测机制:心跳检测、超时阈值与健康检查
各位同学,今天我们来聊聊故障检测机制。说白了,就是怎么知道下游的报价服务还活着。
我见过不少系统,报价路由看起来跑得挺欢,结果某个节点挂了半天,流量还在往里打。用户报错,业务方投诉,运维背锅。嗯,这种场景我经历过太多次了。
所以,一个靠谱的故障检测机制,是报价路由故障转移的基石。今天我把这块掰开揉碎了讲。
一、心跳检测:主动 vs 被动
心跳检测,就是定期确认对方是否存活。我个人习惯把它分成两种:主动心跳和被动心跳。
1. 主动心跳(Push 模式)
每个报价节点,每隔几秒主动向路由中心发一个「我还活着」的信号。
// 伪代码示例:主动心跳上报
while (true) {
Thread.sleep(5000); // 每5秒发一次
sendHeartbeat("node-01", "alive", System.currentTimeMillis());
}
这种模式的好处是实时性高。我在项目中遇到过,某个节点网络抖动,主动心跳能第一时间把异常报上来。但要注意,如果心跳包太多,会占用带宽。我曾经见过一个团队,每1秒发一次心跳,结果把路由中心的CPU打满了。
2. 被动心跳(Pull 模式)
路由中心主动去拉取每个节点的状态。有点像「你不过来,我就过去看看你」。
// 伪代码示例:被动心跳探测
for (String node : nodeList) {
boolean alive = checkNode(node, 3000); // 3秒超时
if (!alive) {
markAsDown(node);
}
}
被动心跳的好处是路由中心完全掌控节奏。但坏处也很明显——如果节点太多,轮询一圈下来,延迟会很高。你想想看,100个节点,每个3秒超时,一轮就是300秒。这期间节点挂了都不知道。
二、超时阈值设置:不是拍脑袋定的
超时阈值怎么设?很多同学直接写死3秒、5秒。说实话,这是给自己埋坑。
我总结了一个经验公式:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 心跳间隔 | 3~5秒 | 太频繁浪费资源,太慢延迟高 |
| 超时阈值 | 心跳间隔 × 3 | 允许一次丢包+一次重试 |
| 连续失败次数 | 3次 | 避免网络抖动误判 |
为什么会这样?我举个例子。假设心跳间隔5秒,超时阈值设成5秒。网络稍微抖一下,丢了一个包,节点就被判定为挂了。这太敏感了。
我个人习惯把超时阈值设成心跳间隔的3倍。比如心跳5秒一次,超时15秒。连续3次超时,才判定节点异常。这样既不会误判,也不会等太久。
三、健康检查接口设计
健康检查接口,不是简单地返回一个200就完事了。我见过太多「假健康」的案例。
一个合格的健康检查接口,应该包含以下信息:
// 健康检查接口返回示例
{
"status": "UP",
"timestamp": 1700000000000,
"details": {
"cpu": 0.45, // CPU使用率
"memory": 0.67, // 内存使用率
"connections": 128, // 当前连接数
"lastHeartbeat": 1700000000000,
"errorCount": 0 // 最近1分钟错误数
}
}
为什么要返回这么多信息?因为路由中心需要根据这些数据做决策。比如某个节点CPU飙到90%,虽然还活着,但响应速度肯定慢。这时候就应该把它从可用列表里摘掉。
四、异常状态判定逻辑
有了心跳数据和健康检查结果,接下来就是判定逻辑了。我把它总结成一张状态机图:
这张图我用了很多年。核心逻辑就一句话:不要因为一次失败就判定死亡,也不要因为一次成功就判定复活。
具体判定规则如下:
- 健康 -> 可疑:第一次心跳超时或健康检查异常。这时候不切流量,只是标记为可疑。
- 可疑 -> 故障:连续3次超时,或者健康检查返回严重错误(比如CPU 100%)。这时候立即摘掉节点。
- 故障 -> 恢复中:运维手动恢复,或者自动恢复策略触发。进入恢复中状态。
- 恢复中 -> 健康:连续3次心跳成功,且健康检查通过。这时候才把节点加回来。
- 恢复中 -> 故障:恢复过程中再次超时,说明节点不稳定,直接打回故障状态。
五、总结一下
故障检测机制,说白了就是三个问题:
- 怎么知道对方活着?—— 心跳检测(主动+被动)
- 多久算死?—— 超时阈值(3倍心跳间隔)
- 死了怎么办?—— 状态机判定(健康->可疑->故障->恢复中)
嗯,今天就讲到这里。这些内容看起来简单,但实际落地时坑很多。我建议你们回去后,先画一张自己系统的状态机图,然后对照着代码走一遍。你会发现,很多地方其实没你想的那么完美。
公众号:蓝海资料掘金营,微信deep3321