应暴露 /healthz 和 /readyz 路径:/healthz 用于轻量级存活检查(进程是否运行),/readyz 用于就绪检查(能否接收流量);禁用 /health、/ping、/status,避免语义混淆或中间件劫持。

Go服务该暴露哪个HTTP路径做健康检查
用 /healthz 或 /readyz,别用 /health、/ping、/status。前者是 Kubernetes 官方推荐路径,被 kubelet、ingress controller 和多数监控工具默认识别;后者要么语义模糊(/ping 无法区分存活/就绪),要么易被中间件劫持(比如某些框架自动注册 /health 并加鉴权)。如果主服务用了 Gin 或 Echo,更得避开它们的默认路由前缀——/api/healthz 这种写法会让探针掉进中间件逻辑里卡住。
为什么必须用独立 HTTP server 启动健康端点
共用业务端口和 mux 是高频翻车点:当主服务因 GC、锁竞争或请求积压卡死时,/healthz 也会响应超时,Kubernetes 就会误判为进程崩溃,反复 kill + restart,形成 CrashLoopBackOff。正确做法是启动一个专用 http.Server,监听如 :8081 这类非业务端口,并用 http.NewServeMux() 创建干净路由,不挂任何中间件、日志、鉴权。
-
/healthzhandler 只查本地状态:atomic.LoadInt32(&healthy)、runtime.NumGoroutine() 是否突增、能否 accept 新连接 -
/readyz可查 DB/Redis,但必须基于缓存结果(例如上次db.PingContext()的时间戳),不能每次实时调用 - 所有外部依赖调用必须带 context timeout,硬性设为 ≤500ms(Kubernetes 默认
timeoutSeconds: 1)
handler 里哪些操作绝对不能写
高频 probe(默认每秒 1–2 次)会让任何低效操作迅速放大成故障。以下行为在 handler 中等同于埋雷:
- 调用
log.Printf、fmt.Println或任何写 stdout/stderr 的操作——日志量会指数级膨胀,触发容器日志限速或磁盘打满 - 执行
time.Sleep、未设 timeout 的http.Get、无缓冲 channel 写入 - 调用
runtime.GC()、os.Exit()、panic()或log.Fatal()——直接中断响应流 - 在 handler 里起 goroutine 异步检查——状态不同步,且无法响应超时
响应体也必须规范:w.Header().Set("Content-Type", "application/json"),body 非空(哪怕只是 {"status":"ok"}),并建议加 timestamp 字段便于排查时序问题。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
Kubernetes Probe 配置怎么避免互相打架
livenessProbe 和 readinessProbe 语义完全不同,配错会导致滚动更新卡住或流量切到不可用实例:
-
livenessProbe对应/healthz,只判断“进程是否活着”,必须轻量、秒级返回,initialDelaySeconds建议 ≥30(给 Go runtime warmup 留出时间) -
readinessProbe对应/readyz,判断“能否收流量”,可容忍稍长延迟(但别超 5s),failureThreshold别设太低,否则短暂抖动就摘流量 - 两个 probe 的
timeoutSeconds必须严格 ≤ handler 实际耗时,且/healthz的检查逻辑不能依赖/readyz所查的下游组件(比如 DB 连不上时/healthz仍要返回 200)
最常被忽略的一点:健康端点本身没有“自动修复”能力,Kubernetes 只负责按配置杀或摘,真正要靠 Go 代码用原子变量、状态缓存和超时控制把探针语义落到实处。

















