Kubernetes健康检查需严格分离/livez和/readyz:/livez仅检查进程自身状态(如goroutine卡死、关键channel阻塞),不触碰任何外部依赖;/readyz才并发探测DB、Redis等依赖并缓存结果,超时严格控制在300ms内,响应必须为200且含JSON状态体,探针参数与Go实现须严丝合缝对齐。

/livez 和 /readyz 必须分两个 handler 写
混用是滚动更新卡死、Pod 反复重启的头号原因。K8s 的 livenessProbe 和 readinessProbe 是两条独立路径,Go 里也必须拆开实现:
-
/livez只检查进程自身:比如主 goroutine 是否卡死、atomic.LoadInt32(&healthy)是否为 1、关键 channel 是否可写——不碰任何网络 I/O -
/readyz才查依赖:DB 连接池是否 ready、RedisPing()是否成功、gRPCGetState()是否等于connectivity.Ready - 别把
/healthz当万能路由;社区约定/livez//readyz更明确,K8s 官方组件(如 kube-apiserver)也这么用 - 用
http.HandleFunc直注册,绕过 Gin/Echo 中间件——日志、鉴权、panic recover 全部拖慢响应,还可能吞掉 5xx
依赖检查不能每次请求都连一次
高频探针(比如 periodSeconds: 2)下,每次 /readyz 都调 db.PingContext,等于每秒打爆 DB 连接池,且极易因超时触发误摘流量。
- 启动一个后台 goroutine,用
time.Ticker每 5 秒执行一次全量依赖探测 - 结果存进带
sync.RWMutex保护的结构体,字段至少含status("UP"/"DEGRADED"/"DOWN")、timestamp、各依赖明细(如{"db": "OK", "redis": "timeout"}) -
/readyzhandler 只读快照,不新建连接、不触发重试逻辑 - 超时必须设紧:DB 用
context.WithTimeout(ctx, 300*time.Millisecond),Redis 同理;别依赖默认 30s
探针参数和 Go 实现必须互相兜底
K8s 探针不是“设了就灵”,它和 Go 端的响应行为必须咬合。常见错配直接导致 CrashLoopBackOff:
-
initialDelaySeconds至少设为 Go 主流程初始化耗时 + 5s 缓冲;比如加载大配置、预热缓存需 8s,那就设15 -
timeoutSeconds必须大于 Go handler 最坏响应时间,但小于periodSeconds;例如 handler 要求 ≤300ms,那timeoutSeconds: 1就太紧,应设2 -
failureThreshold别设 1:DB 抖动 2 秒很常见,若periodSeconds: 5+failureThreshold: 1,一次失败就摘流量;建议3~5 -
livenessProbe绝对不能指向/readyz:DB 断开时/readyz返回 503,但/livez仍该返回 200——否则 K8s 杀完 Pod,新 Pod 启动后照样连不上 DB,无限循环
收到 SIGTERM 后要主动降级 readiness
K8s 发送 SIGTERM 表示“准备删你”,但不会等你处理完积压请求。这时候靠探针被动响应已经晚了,得 Go 自己控制:
立即学习“go语言免费学习笔记(深入)”;
- 用
atomic.StoreInt32(&isReady, 0)立即让/readyz返回 503,Endpoint Controller 会在几秒内从 Service Endpoints 中摘掉这个实例 - 之后 sleep 30 秒或监听
http.Server.Shutdown完成,再退出进程 - 别等
readinessProbe自然失败——它默认每 10 秒探一次,中间有近 10 秒流量还会进来 - 如果用
os.Signal捕获SIGTERM,记得用signal.Notify注册,且 handler 里不要做阻塞操作


















