go服务健康检查必须分离/healthz(进程存活)和/readyz(业务就绪)端点,分别监听独立端口、禁用中间件与阻塞操作,依赖状态缓存而非实时探测,并设非空响应体与content-type。

Go 服务的健康检查端点不是“能返回 200 就算完事”,它必须让 Kubernetes、Docker 或 Consul 等系统在毫秒级内无歧义地判断:进程是否活着(liveness),以及是否真能处理请求(readiness)。混用、超时、依赖外溢、中间件干扰,都会导致滚动更新失败、无限重启或流量误切。
/healthz 和 /readyz 必须分离且监听独立端口
共用一个 HTTP server 处理业务和健康检查是常见隐患:主服务阻塞(如大量请求积压、GC STW、锁竞争)会导致 /healthz 无法响应,Kubernetes 误判为进程死亡并反复重启——而其实 goroutine 还在跑。
- 用
http.NewServeMux()创建专用 mux,启动独立http.Server,监听如:8081这类非业务端口 -
/healthz只检查本地状态:能否 accept 连接、atomic.LoadInt32(&healthy)是否为 1、goroutine 数未突增 -
/readyz可查 DB/Redis,但必须走缓存结果(如lastPingTime),而非每次实时db.Ping() - 不要把
/healthz挂在主路由下(比如/api/healthz),避免被中间件或鉴权逻辑拖垮
handler 里禁止任何阻塞 I/O 和日志输出
健康检查 handler 是基础设施通道,不是业务逻辑入口。一次 log.Printf 或未设 timeout 的 http.DefaultClient.Do 就可能让探针超时(K8s 默认 timeoutSeconds=1),触发 CrashLoopBackOff。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 所有外部调用必须包裹
context.WithTimeout(ctx, 500 * time.Millisecond),硬性截断 - 禁用
log.Fatal、panic、os.Exit:它们会终止进程或 goroutine,让探针直接断连 - 不写日志到 stdout/stderr(除非 error 级别且打到 stderr);高频 probe 会撑爆日志卷或触发限速
- 避免在 handler 中新建 goroutine 异步检查——状态不同步,且无法响应超时
响应体必须非空、带 Content-Type、结构统一
Kubernetes kubelet、Docker daemon、某些 Ingress 控制器(如旧版 nginx-ingress)对空 body 或缺失 Content-Type 的响应会静默失败,判定为 unhealthy。
- 务必写 body:
w.WriteHeader(http.StatusOK); json.NewEncoder(w).Encode(map[string]string{"status": "ok"}) - 必须设 header:
w.Header().Set("Content-Type", "application/json") - 推荐加
timestamp字段(time.Now().UTC().Format(time.RFC3339)),方便排查时序问题 - 不要返回敏感信息(DB 地址、配置项)、不要拼接全量 metrics(
runtime.ReadMemStats()可以,但runtime.GC()绝对不行)
readiness 检查不能实时 ping 依赖,要靠状态缓存
每次 /readyz 请求都执行 db.Ping(),等于主动给数据库连接池加压。网络抖动时,probe 耗时飙升 → K8s 摘实例 → 流量切走 → 剩余实例压力更大 → 全面雪崩。
- 用
sync.RWMutex+time.Time缓存上次成功时间:lastDBPing - handler 中只读:
if time.Since(lastDBPing) > 30 * time.Second { status["db"] = "degraded" } - 后台 goroutine 定期(如每 10 秒)尝试
db.PingContext并更新lastDBPing - 对非关键依赖(如日志上报、指标推送),直接跳过检查,或标记为
"degraded"不影响整体"status": "ok"
最易被忽略的一点:健康检查 server 的生命周期必须与主服务解耦,且需响应 SIGTERM 主动关闭。否则容器停止时,健康端口还在 listen,K8s 会误认为服务“假活”,延迟驱逐。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










