健康检查机制的职责是持续确认上游节点是否存活,让网关把流量只发给健康节点。在我们自研的企业级 AI 网关里,健康检查分两层落地:对内用 Spring Boot Actuator 暴露各模块探活端点,对外用主动探针定期探测模型供应商 API 的可用性,再叠加被动检查兜底——按真实请求的失败率自动隔离异常模型。判定规则是经典的连续阈值:连续 N 次探活失败标记不健康、连续 M 次成功恢复健康。这套机制同时服务于内部 AI 爆款文章创作器,创作器里任何一次模型调用异常,都会被网关健康中心记录并进入隔离流程,避免故障扩散。
一、主动检查与被动检查的分工
健康检查分两类,各自解决的问题不同。主动检查是网关定时发起探测请求,不依赖业务流量,能提前发现故障,但会额外消耗请求量;被动检查直接统计真实请求的成败,不增加额外流量,但发现故障有滞后,且模型被隔离后没有新流量进来,就无法靠被动检查恢复。
| 维度 | 主动检查 | 被动检查 |
|---|---|---|
| 探测方式 | 定时发起探针请求 | 统计真实调用结果 |
| 发现故障速度 | 快,最多一个周期 | 慢,需累积失败样本 |
| 额外开销 | 有探针流量 | 无 |
| 能否自愈 | 能,持续探活可恢复 | 不能,需结合主动检查 |
网关把两者组合使用:主动检查负责定期探活并恢复节点,被动检查负责在探活间隙快速隔离突发故障的节点。生产配置里主动探活间隔 30 秒,被动检查以 30 秒为窗口统计失败率,超过 80% 即触发隔离。
二、主动探活的具体实现
2.1 各服务探活端点
每个接入网关的服务,包括 AI 爆款文章创作器,统一暴露 /actuator/health。网关的探活器按固定间隔轮询该端点,用状态码和响应时间两个指标评估健康度。
management:
endpoint:
health:
probes:
enabled: true
show-details: always
探活结果进入内存健康快照,结构是 modelName → HealthState,健康中心持有这张快照,路由模块每次决策前读取。
2.2 模型供应商的探活策略
对 OpenAI、通义千问这类外部模型 API,探活不能只做 TCP 连通性检查,必须发一个最小请求验证鉴权与返回结构。我们封装了一个 ProbeService,探针请求带上最小上下文,返回 200 且结构合法才算健康。
public boolean probe(ModelEndpoint ep) {
try {
ChatResponse resp = chatModel.call(new Prompt("hi"));
return resp.getResult() != null && !resp.getResult().getOutput().getText().isBlank();
} catch (Exception e) {
log.warn("probe failed: {}, reason={}", ep.name(), e.getMessage());
return false;
}
}
探针请求会产生计费,但最小请求的 token 消耗可以忽略。考虑到频繁探测可能触发供应商侧限流,探活器做去重与退避:同一模型在上一个探测周期未结束前不重复探测,失败后探活间隔自动拉长。
三、健康状态判定与恢复流程
健康状态转换是带迟滞的状态机,防止抖动造成反复切换。判定与恢复遵循固定流程:
- 探针连续失败次数达到阈值(默认 5 次),状态由健康切为不健康,节点从路由候选里摘除;
- 隔离窗口启动,窗口内该节点不再接收业务流量,但探活不停止;
- 隔离期结束后,放一条探针试活,成功则恢复健康并重新参与路由,失败则继续隔离;
- 恢复瞬间用少量灰度流量验证,确认稳定后再全量放行。
HealthCenter 定时扫描快照,把状态变化推给事件总线,路由、监控面板、告警三处同时响应,状态变化全程可追溯。
四、被动检查与隔离窗口
被动检查把每次模型调用的结果计入滑动窗口。失败判定按错误枚举走:限流、超时、5xx 都算失败,客户端 4xx 不算——那是请求自身问题,隔离节点没用。窗口内失败率超阈值,节点进入隔离;隔离时长按失败次数指数递增,连续正常则逐步缩短,与主流网关的惩罚式隔离思路一致。窗口用环形数组实现,只保留最近 30 秒的调用结果,避免长期累计导致反应迟钝:
public void record(String model, boolean success) {
SlidingWindow win = windows.computeIfAbsent(model, k -> new SlidingWindow(30));
win.push(success);
if (win.failureRate() > 0.8) {
healthCenter.isolate(model);
}
}
4.1 恐慌阈值兜底
极端场景下健康节点比例可能降到阈值以下,比如供应商整体故障只剩一个模型可用。此时严格只路由健康节点会压垮唯一幸存者。网关设了恐慌阈值:健康节点占比低于该值时,健康检查临时绕过,请求平均分发到所有节点,宁可多花成本换整体可用性,也不让单点被打爆。恐慌阈值默认设为较低比例,只在真正极端时才触发。
五、健康检查要避开的坑
探活路径要用轻量接口,不要拿重逻辑接口当探针,否则探活本身拖垮服务。被动检查恢复机制要配合主动检查一起配,否则隔离的节点永远回不来。另外探活频率要克制,全部模型同一秒探活会形成峰值流量,应该把探活任务错峰打散。
常见问题(FAQ)
Q1:健康检查频率设多少合适?
一般 10-30 秒探活一次,故障敏感业务可收紧到 5 秒,注意探针本身会占资源。
Q2:探活失败和真实故障有什么区别?
网络抖动、限流都可能让单次探活失败,所以用连续失败阈值判定,避免单次抖动误杀。
Q3:健康检查本身挂了怎么办?
健康检查服务独立部署并自监控,自身异常时告警,网关按上次健康快照继续运行,不因检查器故障而停摆。