/healthz比/health更安全,因其避免被中间件或框架默认路由劫持,Kubernetes原生支持且Ingress/Service Mesh默认放行;应绕过框架用net/http直接注册,区分/livez与/readyz端点,并严格对齐探针配置。

为什么/healthz比/health更安全
用 /healthz 而不是 /health,核心原因是避免被中间件或框架默认路由劫持。比如某些 Gin 中间件会自动注册 /health 做内部监控,或 Nginx 重写规则误匹配;而 /healthz 这种带后缀的路径在绝大多数框架里是“干净”的,Kubernetes 本身也原生识别它。
-
/health语义直观,但容易和业务监控、指标端点(如/health/metrics)混淆 -
/healthz是 Kubernetes 官方推荐后缀(同/livez//readyz),多数 Ingress 控制器和 Service Mesh(如 Istio)默认放行 - 别用
/ping或/status:前者无状态语义,后者常被 Prometheus Exporter 占用,易导致探针返回 404 或 500
如何用 net/http 正确注册健康端点
不要把健康检查塞进框架路由树里——尤其当你用 Gin/Echo 时,Use() 注册的全局中间件(如 JWT、日志、CORS)会拦截所有请求,导致 /healthz 返回 401 或超时。最稳的方式是绕过框架,直接用标准库注册。
- 用
http.HandleFunc("/healthz", healthHandler),而非r.GET("/healthz", ...) - 确保 handler 内不调用任何可能阻塞或 panic 的逻辑:不连 DB、不读文件、不调外部 API
- 响应必须设
Content-Type: text/plain; charset=utf-8,AWS ALB 和部分 Ingress 会因类型不匹配判为失败 - 返回纯文本
"ok"比 JSON 更轻量,除非你明确需要结构化字段(如时间戳)用于调试
livenessProbe 和 readinessProbe 路径不能共用一个 handler
很多人图省事只写一个 /healthz 端点,然后让两个探针都打它——这会导致数据库挂了但 Pod 还在接收流量,或者 goroutine 卡死却没被重启。Kubernetes 不会帮你区分语义,它只按配置执行动作。
-
livenessProbe应指向/livez:只检查进程是否卡死(例如用atomic.LoadInt32(&live))、主循环是否仍在运行 -
readinessProbe应指向/readyz:可检查 DBPingContext(ctx, 500*time.Millisecond)、Redis 连接、本地缓存加载完成等 - 两个端点必须独立注册:
http.HandleFunc("/livez", liveHandler)和http.HandleFunc("/readyz", readyHandler) - 若强行复用路径,至少在 handler 里通过
r.URL.Path分支判断,但不如物理分离清晰可靠
Kubernetes 探针配置与 Go 端点必须严格对齐
探针配错比没配还危险:比如 timeoutSeconds: 1 但 Go handler 里做了 2 秒 DB ping,每次都会触发重启;或者 port 写成 8080,但 Go 服务实际监听 8000,探针永远 503。
立即学习“go语言免费学习笔记(深入)”;
- 确认 Go 服务监听端口和
livenessProbe.httpGet.port一致(注意不是 service port,是 containerPort) -
initialDelaySeconds至少设为 15:Go 启动常需加载配置、初始化 gRPC client、连接消息队列,硬编码 5 秒大概率导致启动期反复 kill -
failureThreshold建议设为 3:容忍短暂抖动(如网络瞬断、DB 临时拒绝连接),避免雪崩式重启 - 别信 “默认值”:Kubernetes 默认
timeoutSeconds是 1 秒,Go 端必须保证 handler 在 800ms 内返回,否则必失败
/readyz 返回 503,等正在处理的消息消费完再退出。这点没人替你做,全靠你在 Go 代码里用原子变量控制。


















