健康检查端点应仅用http.HandleFunc暴露/healthz路径,返回200及纯文本OK,设置Content-Type,不依赖外部资源;/readyz用于就绪检查,二者语义不同,不可混用。

Go 语言写健康检查服务,核心就是用 http.HandleFunc 暴露一个轻量、无副作用的 HTTP 端点,返回 200 并尽量避免依赖外部资源(如 DB、缓存)。
用 http.HandleFunc 实现最简健康检查端点
别搞复杂路由或框架封装,原生 net/http 足够。关键点是:不 panic、不阻塞、不调用不可靠依赖。
- 路径建议固定为
/healthz或/health,符合 Kubernetes 和多数运维工具默认探测路径 - 响应体保持极简,比如纯文本
OK或空响应体,减少序列化开销 - 务必设置
Content-Type: text/plain; charset=utf-8,避免某些 LB(如 AWS ALB)因 Content-Type 不匹配判定为失败 - 不要在 handler 里做数据库 ping、Redis ping、文件读取等——这些应放在就绪探针(
/readyz)里
func main() {
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
区分 /healthz 和 /readyz 的真实用途
很多人把两者混用,结果导致服务还没加载完配置就被流量打挂。Kubernetes 中它们语义不同:
-
/healthz:只反映进程是否存活(crashloop?goroutine 死锁?),必须秒级返回,且不能依赖任何外部系统 -
/readyz:反映服务是否准备好接收流量(比如配置已加载、gRPC server 已启动、本地 cache warm up 完成),可容忍稍长延迟(但建议 ≤5s) - 如果服务没实现
/readyz,Kubernetes 默认用/healthz兼任,容易引发“假就绪”问题
避免常见陷阱:超时、panic、日志刷屏
健康检查被高频轮询(比如每 2 秒一次),一个小失误就会拖垮服务。
立即学习“go语言免费学习笔记(深入)”;
- 禁止在 handler 里用
log.Printf或fmt.Println打日志——每秒几十次日志会迅速占满磁盘或 I/O - 不要调用可能阻塞的函数,例如
time.Sleep、未设 timeout 的http.Get、无缓冲 channel 写入 - 若需采集指标(如内存使用率),用
runtime.ReadMemStats,别调外部命令或读/proc(权限/性能风险) - Kubernetes 的
livenessProbe默认超时 1 秒,若 handler 偶尔卡住超过该值,会触发重启循环
配合 Docker/K8s 部署时的关键配置项
光写对 handler 不够,容器编排层的配置错一个,探活就失效。
- Dockerfile 中确保暴露端口:
EXPOSE 8080(虽非强制,但利于文档和扫描) - Kubernetes YAML 中,
livenessProbe和readinessProbe必须显式指定httpGet.path和port,不能只写 port 名称 - 推荐设置
initialDelaySeconds: 5(尤其有初始化逻辑的服务),避免启动瞬间被 kill - 不要把
failureThreshold设太小(如 1),网络抖动会导致误杀;3–5 是较稳妥值
真正难的不是写这个 endpoint,而是守住「健康」的定义边界:它只回答“我在不在”,不回答“我快不快”或“我稳不稳”。越想让它承载更多,越容易在凌晨三点被告警叫醒。










