健康检查接口应返回200 OK状态码及JSON响应体{"status": "ok", "timestamp": 1717023456},避免空响应或204;/healthz仅检查进程存活,不依赖DB等外部服务,/readyz才检查关键依赖并设超时容忍。

健康检查接口该返回什么状态码和响应体
健康检查接口不是返回 200 就算完事。Kubernetes、Nginx、Consul 等多数调度/代理系统默认只认 200 OK 且响应体为非空(或含特定字段)才判定为“存活”。返回 204 No Content 或空 JSON 会被部分工具当作失败处理。
建议统一用 200 OK,响应体为 JSON,至少包含 status 字段:
{"status": "ok", "timestamp": 1717023456}
如果要做就绪检查(readyz)或启动检查(livez),可额外加 checks 字段区分依赖项状态,但基础探活不强制。
用 net/http 写最简健康检查 handler
Go 标准库完全够用,无需引入第三方 Web 框架。核心是避免阻塞、不带副作用、不依赖外部服务(如 DB 连接池、Redis ping)——除非你明确想把它纳入健康判断逻辑。
常见错误:在 healthz handler 里调用 db.Ping() 却没设超时,导致探活请求卡死、触发误判下线。
- 基础写法:直接返回固定 JSON,零延迟
- 若需检查关键依赖,请用
context.WithTimeout控制单次检查上限(建议 ≤ 1s) - 避免在 handler 内做日志打印(尤其带 traceID 的),高频探活会冲垮日志系统
- 路径建议固定为
/healthz(K8s 默认)、/health(通用)或/ping(轻量)
如何让 HTTP 探活不干扰业务指标和 p99 延迟
HTTP 探活请求量可能远超业务流量(比如每秒 10 次 × 数十个实例),若和业务共用同一路由 mux、同一 Prometheus metrics 注册器、同一中间件链,会导致:http_request_duration_seconds 的 p99 被拉高、http_requests_total 统计失真、JWT 验证中间件无谓执行。
解决方案很直接:
- 用独立的
http.ServeMux或http.Handler实例挂载健康端点,不走主路由 - 启动时单独开一个监听地址,例如
:8081,只暴露/healthz和/metrics - 若必须复用主端口(如受限于云厂商 LB 配置),则在主 mux 中用
http.HandleFunc("/healthz", ...)显式注册,跳过所有中间件 - Prometheus metrics 中对探活请求打标,例如加
handler="healthz",便于过滤
为什么 /healthz 不该返回数据库连接状态
因为“服务是否能提供 API”和“此刻能否连上数据库”是两个不同维度的问题。把 DB 连接放进 /healthz,会导致:DB 临时抖动 → 所有实例被摘除 → 流量打到剩余节点 → DB 更忙 → 雪崩。
更合理的分层是:
-
/healthz:只检查进程存活、goroutine 是否卡死、内存是否 OOM(可通过runtime.ReadMemStats快速采样) -
/readyz:检查关键依赖(DB、Config Center、下游核心服务),但允许短时失败(比如连续 3 次失败才标记 not ready) -
/livez:K8s 原生支持,语义等同于/healthz,推荐直接复用
真正难的是 readyz 的“容忍窗口”设计——没有放之四海而皆准的阈值,得结合你的 DB 连接池大小、重试策略、下游 SLA 来定。这点容易被忽略,但线上出问题往往栽在这儿。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











