/health/ready必须同步探测DB连通性,使用已初始化的*sql.DB句柄和context.WithTimeout(≤2s),失败返回503及具体错误;/health/live仅检查进程快照,严禁依赖外部服务;两者须由独立HTTP服务暴露,且Probe配置须与代码路由、端口严格一致。

/health/ready 必须同步探测 DB 连通性,不能只返回 200
很多服务在 Kubernetes 里流量一进来就 500,根本原因是 /health/ready 没做真实依赖检查——它只确认进程活着,却不管数据库连没连上。Kubelet 看到 200 就把 Pod 加进 Endpoint,结果请求全打到一个连不上 DB 的实例上。
正确做法是让 /health/ready 同步调用 db.PingContext(),且必须带超时、复用已有连接池,而不是每次新建 *sql.DB 实例。
- 用启动时已初始化的全局
*sql.DB句柄,避免探针触发频繁建连,耗尽文件描述符 - 超时必须显式设:例如
ctx, cancel := context.WithTimeout(context.Background(), 1500*time.Millisecond),总耗时控制在 2s 内 - 失败时返回
http.StatusServiceUnavailable (503),响应体带具体错误项,比如{"database": "timeout"},别只写{"status": "down"} - 不要在 handler 里做连接池 warmup 或 migrate ——这些该在
main()启动阶段完成
为什么不能把 DB 检查塞进 /health/live
/health/live(或 /healthz)语义是“进程是否存活”,不是“业务是否可用”。把它和 DB 绑死,会导致一次数据库抖动就触发容器重启,反而放大故障。
Kubernetes 的 livenessProbe 一旦失败,会直接 kill 并重启 Pod;而 readinessProbe 失败只是摘流量,给修复留出窗口。两者必须严格分离。
-
/health/live只做快照:检查runtime.NumGoroutine()是否异常、关键 channel 是否已 close、内存是否接近 cgroup limit -
/health/ready才负责 DB、Redis、gRPC 等同步依赖探测 - 两个端点必须由不同 HTTP handler 提供,最好用独立的
http.ServeMux,绕过 Gin/Echo 中间件链,防止 panic 或日志中间件拖慢或吞掉探针请求
DB 检查卡住会拖垮整个 HTTP server
Go 的 http.Server 默认用 goroutine 池处理每个请求。如果 /health/ready handler 因 DB 超时不返回,这个 goroutine 就一直占着,高并发下很快耗尽池子,所有新请求排队等待——包括真正的业务请求。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
这不是理论风险,是线上高频问题:一次慢查询或网络分区,就能让整个服务“假死”。
- 所有依赖检查必须带
context.WithTimeout(),且 timeout 值 ≤readinessProbe.timeoutSeconds - 1 - 非强依赖项(如监控上报、审计日志)改用异步检查 + 缓存结果,不阻塞响应流
- 避免在 handler 里调
db.Exec或db.QueryRow——PingContext()足够验证连通性,更轻量 - 如果 DB 是最终一致型(如某些分库场景),可降级为检查连接池中空闲连接数是否 > 0,而非强制 Ping
Probe 配置要和代码行为对齐,否则白写
Kubernetes 不会“理解”你的健康逻辑,它只按 YAML 里的 httpGet.path 和 port 去发请求。路径写错、端口不匹配、超时设太短,都会让探针持续失败。
常见坑是:代码暴露 /health/ready 在 8080 端口,但 Deployment 里 containerPort: 80,或者 targetPort 写成字符串 "http" 却没定义 Service port name。
-
readinessProbe.httpGet.path必须严格等于代码注册的路由,比如/health/ready,不能少斜杠或大小写错 -
readinessProbe.httpGet.port必须和容器实际监听的端口一致,且与containerPort匹配(注意不是hostPort) -
timeoutSeconds: 3,periodSeconds: 5,failureThreshold: 3是较稳组合,避免单次网络抖动误判 -
initialDelaySeconds: 15—— 给 DB 连接池 warmup 留出时间,尤其用了连接池自动重试或慢启动策略时
真正容易被忽略的,是健康检查 handler 和业务 server 共享同一个 http.Server 实例。一旦业务 handler panic 或阻塞,整个 server 的 goroutine 池可能被拖垮,连探针都收不到。最稳妥的做法,是用独立的 http.Server 监听另一个端口(比如 8081)专跑健康端点,彻底隔离。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










