健康检查接口应返回200状态码和含status、timestamp等字段的标准JSON结构;需同步探针下游依赖并控制总耗时≤3s;禁止暴露公网、防止goroutine泄漏。

健康检查接口该返回什么状态码和结构
微服务健康检查不是随便返回 200 OK 就算数。Kubernetes、Consul、Nacos 等主流注册中心默认只认 200 为健康,但会解析响应体判断细节;有些(比如 Spring Cloud Gateway)还会要求 JSON 中包含 status 字段且值为 "UP"。Go 里最稳妥的做法是:状态码用 200,响应体用标准 JSON,至少包含 status 和 timestamp:
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "UP",
"timestamp": time.Now().UTC().Format(time.RFC3339),
"service": "user-service",
})
}别用 503 表示“不健康”——这会让 Kubernetes 认为服务根本不可达,直接剔除实例,而不是等你恢复;也别省略 Content-Type,某些网关会因类型不匹配拒绝转发。
如何检查下游依赖是否真正可用
只检查自己进程是否存活(比如 http.ListenAndServe 没 panic)毫无意义。真实场景中,数据库连不上、Redis 超时、下游 HTTP 接口 5xx 频发,你的服务就算跑着也是“假活”。健康检查必须做轻量级探针:
- 数据库:执行
db.Exec("SELECT 1")或db.Ping(),设超时(建议 ≤ 2s) - Redis:用
client.Ping(ctx).Err(),别用Get("health")这类带键操作 - HTTP 依赖:用
http.DefaultClient.Do(req.WithContext(ctx)),手动控制 timeout 和重试次数(最多 1 次)
所有依赖检查必须并发执行,用 errgroup.Group 控制上下文超时,总耗时控制在 3s 内,否则注册中心会判定超时并反复调用,加重负载。
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
为什么不能把健康检查挂在 /health 并暴露给公网
暴露 /health 到公网等于公开服务拓扑和实时状态。攻击者可批量扫描,确认哪些实例在线、哪个版本有漏洞、甚至通过响应时间推测后端负载。正确做法是:
- 用反向代理(如 Nginx、Traefik)限制路径访问,只允许内网 IP 或服务网格 sidecar 访问
- 在 Go 中用中间件校验请求头或源 IP:
r.RemoteAddr匹配内网段,或检查r.Header.Get("X-Forwarded-For") - 生产环境禁用
/debug/pprof和/metrics同一监听地址,避免信息泄露
Kubernetes 的 livenessProbe 默认走 Pod IP 直通,不经过 Ingress,所以只要没显式暴露,一般安全;但如果你用了 hostNetwork: true 或 NodePort,就得格外小心。
goroutine 泄漏会让健康检查越来越慢
常见错误是在健康检查 handler 里启 goroutine 做异步检查,却不回收资源。比如:
go func() {
time.Sleep(5 * time.Second) // 模拟慢检查
log.Println("done")
}()每次请求都 spawn 新 goroutine,5 秒后才退出,QPS 高时会堆积成百上千个 idle goroutine,最终拖垮整个服务。正确方式只有两种:
- 所有检查同步执行,靠 context 超时强制中断
- 如果真要异步(比如上报健康日志),必须用带 cancel 的 context,并确保 goroutine 在 cancel 后立即退出
上线前用 curl -v http://localhost:8080/health 多刷几次,再执行 curl http://localhost:8080/debug/pprof/goroutine?debug=2 查看 goroutine 数量是否稳定——这是最容易被忽略的压测盲点。

















