健康检查端点必须返回标准http状态码:200表示就绪可流量,503表示暂时不可用;应使用http.handlefunc注册/healthz或/readyz,避免重定向或204;区分/livez(进程存活)与/readyz(依赖连通性),后者需加超时与降级,禁用log.fatal/os.exit,隔离pprof调试端口。

健康检查端点必须返回标准HTTP状态码
微服务健康检查不是“能访问就行”,客户端(如Kubernetes、Consul、Nginx)依赖HTTP 200表示“就绪且可流量”,HTTP 503表示“暂时不可用”。返回200但body里写{"status":"down"}会被多数调度器忽略——它们只看状态码。
- 用
http.HandlerFunc注册/healthz或/readyz,不要重定向或返回204 - Kubernetes建议区分
/livez(进程存活)和/readyz(可服务),二者逻辑可不同:前者只检查goroutine是否卡死,后者需验证数据库连接、下游gRPC可用性 - 避免在健康检查中做耗时操作(如查Redis慢查询),超时默认是1秒,K8s readiness probe失败3次即切流
用net/http自带机制实现轻量级探针
不需要引入完整框架(如Gin的中间件链)来处理健康检查。原生net/http足够,且更可控、无隐式开销。
- 直接注册
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { ... }),内部用w.WriteHeader(http.StatusOK)或http.StatusServiceUnavailable - 若需结构化响应体(如供人工排查),用
json.NewEncoder(w).Encode(map[string]string{"status": "ok", "ts": time.Now().UTC().Format(time.RFC3339)}),但注意别因此阻塞或panic - 禁止在handler里调用
log.Fatal或os.Exit——这会杀掉整个服务,不是“报告不健康”
依赖组件连通性检查要加超时与降级
真实场景中,健康检查常需验证DB、Redis、gRPC下游是否可达。但这些I/O操作天然不可靠,必须设限。
- 数据库检查用
db.PingContext(context.WithTimeout(ctx, 500*time.Millisecond)),而非db.Ping()(无超时) - 对下游gRPC服务,用
grpc.Dial时传grpc.WithBlock()+context.WithTimeout,连接失败立即返回503,不等默认30秒 - 关键依赖(如配置中心)短暂不可用时,可返回
200但带warning字段;非关键依赖(如日志上报)应静默忽略,避免把健康检查变成单点故障放大器
避免将pprof或debug端口暴露到生产健康检查路径
开发时习惯把/debug/pprof和/healthz都挂上,但生产环境的健康检查路径会被LB、监控系统高频轮询。如果误把调试接口混入,可能引发性能抖动甚至信息泄露。
立即学习“go语言免费学习笔记(深入)”;
- 确保
/healthz、/readyz路由与/debug/完全隔离,不要共用mux或中间件 - 使用
http.ServeMux时,明确用独立实例:一个用于业务+健康检查,另一个仅绑定localhost:6060跑pprof - CI/CD发布前用
curl -v http://$SERVICE/healthz验证响应头Status和body大小(理想
200的handler,而是让这个endpoint在数据库连接池打满、etcd集群脑裂、磁盘IO卡死时,依然能在100ms内给出准确判断——这要求每个依赖检查都经过压测验证,而不是“本地跑通就行”。










