Go服务健康探针需提供轻量、非阻塞的HTTP端点(如/healthz和/readyz),分别实现liveness与readiness检查,返回200或503状态码,并在启动时预热依赖、添加基础防护。

在 Go 语言中实现服务健康探针,核心是提供一个可被外部(如 Kubernetes、Nginx、Prometheus 或运维脚本)定期调用的 HTTP 端点,并在内部执行轻量、快速、无副作用的状态检查逻辑。关键不在于“多复杂”,而在于“可靠、及时、可观察”。
定义清晰的健康检查维度
健康状态通常分两类:
- liveness probe(存活探针):判断服务是否还在运行、是否卡死(如 goroutine 泄漏、死锁)。失败时应重启容器。
- readiness probe(就绪探针):判断服务是否已准备好接收流量(如依赖数据库连通、配置加载完成、缓存预热完毕)。失败时应从负载均衡摘除。
两者逻辑可重叠,但语义和动作不同,建议分开暴露端点(如 /healthz 和 /readyz),或通过查询参数区分。
编写轻量、非阻塞的检查逻辑
每个检查项必须满足:超时可控、不写数据、不触发业务副作用、耗时稳定(建议 ≤ 1s)。常见检查项包括:
立即学习“go语言免费学习笔记(深入)”;
- 内存使用率是否超过阈值(
runtime.ReadMemStats) - 协程数是否异常增长(
runtime.NumGoroutine()) - 关键依赖是否可达(如 ping 数据库连接池、HTTP 调用下游健康接口,带 context timeout)
- 本地缓存/队列积压是否超标(如 channel 长度、map size)
避免在健康接口中做文件读写、长 SQL 查询或调用未设 timeout 的外部服务。
暴露标准 HTTP 健康端点
使用标准 net/http 启动一个独立监听地址(如 :8081),避免与主业务端口耦合,便于隔离管控:
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 500*time.Millisecond)
defer cancel()
if err := checkLiveness(ctx); err != nil {
http.Error(w, "liveness check failed: "+err.Error(), http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
})
注意:返回状态码要规范——成功用 200 OK,失败用 503 Service Unavailable(K8s 默认识别),不要用 4xx 或自定义码。
集成到启动生命周期中
健康检查不是“事后补丁”,应在服务初始化阶段注册并预热依赖。例如:
- 启动时尝试建立一次 DB 连接并缓存连接池状态
- 用
sync.Once初始化健康检查所需的只读资源(如配置快照) - 若服务依赖 gRPC 客户端,确保其
Connect已完成且处于READY状态
这样能保证首次健康请求不会因初始化延迟而误报失败。
不复杂但容易忽略的是:健康端点本身也要有基础防护——比如限制访问来源(内网 IP)、加简单限流(防止被刷爆)、记录日志(用于排查频繁失败原因)。它虽小,却是整个服务可观测性的第一道门。










