/healthz和/livez必须分开:/livez仅检查进程存活(如goroutine数、内存增长),禁调外部依赖;/healthz判断服务就绪(含db等依赖检查),失败则剔除流量但不重启容器。

/healthz 和 /livez 必须分开,不能混用一个端点
Kubernetes 的 livenessProbe 和 readinessProbe 依赖不同语义:前者只关心进程是否卡死(/livez),后者才决定能否转发流量(/healthz)。共用一个接口会破坏调度逻辑——比如 DB 挂了,/healthz 应返回 503 剔除实例,但 /livez 仍需返回 200 表示进程正常。
-
/livez里禁止调任何外部依赖,只检查 goroutine 数量是否爆炸、内存是否持续增长、或 runtime 信号是否响应 -
/healthz必须带context.WithTimeout控制每个依赖检查耗时,例如db.PingContext(ctx, 2*time.Second) - 两个 handler 都不能写日志——
log.Printf在高频探针下会拖慢 I/O,甚至触发 panic - 别用
http.ListenAndServe()启动,必须用显式http.Server实例,否则无法配合SIGTERM做优雅退出
依赖检查要分层超时,不能靠单一 http.Client.Timeout
HTTP 服务、Redis、PostgreSQL、gRPC 的连接行为差异极大,统一设 http.Client.Timeout 会误判。比如 Redis Dial 卡在 DNS 解析时,http.Client.Timeout 不生效;而 gRPC Dial 若没加 grpc.WithTimeout,可能永远阻塞。
- HTTP 探测优先用
HEAD,避免触发服务端业务逻辑;传Authorizationheader 时注意 token 是否过期 - Redis 检查用
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)+client.Ping(ctx).Err() - PostgreSQL 用
db.PingContext(ctx, 1500*time.Millisecond),别用db.QueryRow("SELECT 1")——它可能因锁表卡住 - gRPC 探测必须加
grpc.WithBlock()和grpc.WithTimeout(2*time.Second),否则Dial返回的是未连接的 stub
指标暴露必须用 prometheus/client_golang,别手拼 /metrics
自己拼字符串生成的 /metrics 会被 Prometheus 拒绝——格式校验失败(比如空格、换行、类型声明缺失)。官方 SDK 不仅自动注册 go_goroutines、go_memstats_alloc_bytes 等运行时指标,还保证并发安全。
- 所有指标(包括自定义的
component_health_status)必须在main()开头注册,不能在 handler 里重复prometheus.MustRegister() - 用
GaugeVec记录组件状态,label 设为component(如"db"、"redis"),值为1(健康)或0(异常) - HTTP 埋点走中间件,例如
promhttp.InstrumentHandlerDuration;但/healthz和/livez必须排除,否则请求量指标被污染 - 暴露端点用
promhttp.Handler(),不要自己写http.HandlerFunc输出文本
主动探测下游服务得用独立 goroutine,不是 HTTP handler
健康检查服务本身要监控其他服务(比如订单服务要探测支付网关是否存活),就不能靠别人来调你——得自己定时拨号。放在 HTTP handler 里同步执行,会导致一次失败就卡住整个 handler;用 time.Tick 在 main goroutine 死循环,panic 会直接崩掉进程。
- 用
time.NewTicker(30 * time.Second)启动 goroutine,每次 tick 触发全量探测 - 每个探测任务外层包
go func() { defer func() { recover() }(); c.Check() }(),防止单个 panic 杀死整个探测器 - HTTP、TCP、gRPC 等协议抽象成
Checker接口,各自实现Check()方法,主循环只调接口不关心协议细节 - 结果聚合用内存状态机(如
map[string]bool),别存数据库或发消息——延迟高且引入新依赖
真实场景里最常被忽略的,是 /healthz 返回 200 但 body 写 {"status":"down"} ——Kubernetes 只看状态码,JSON 内容根本不会解析。还有人把 pprof 暴露在生产环境又没加鉴权,结果被扫描工具反复抓取 profile,CPU 直接打满。这些不是“配置错了”,而是对探针机制的理解偏差。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











