一、健康检查为什么成了"杀手"
在 Kubernetes 集群部署大模型推理服务后,实例正常处理请求却频繁被 kubelet 重启。事件日志原因出奇一致——Liveness probe failed。
大模型推理负载与常规 Web 服务截然不同。一次 Prefill 可能持续数秒,高并发下 GPU 被持续占满。kubelet 的 /healthz 请求进入队列后,若前面排了多个推理任务,探针响应很容易超过 1s 超时。许多团队直接照搬微服务探针配置,连续三次超时即触发重启。对加载 70B 模型需数分钟的 Pod,这是自杀配置。
⚠️ 核心误区是把进程存活等同于服务健康。推理服务健康是多维度的。
二、从误杀根因到 Probe 分级
误杀来自三个层面错配。探针类型错配最常见:Liveness 本意检测死锁,团队却常把就绪逻辑塞进去。队列繁忙时 Liveness 失败直接重启容器,而非摘流。超时参数错配同样致命:P99 延迟 5 到 10 秒,探针超时却设 1 秒。优雅终止缺失雪上加霜:请求断开、KV Cache 丢失、客户端收 502,形成死亡螺旋。
📊 正确做法是建立探针分级。Startup 确认模型加载完成,Liveness 只做存活检查,Readiness 反映能否接收新请求,需检查队列深度与 GPU 显存。
| 探针类型 | 检查目标 | 失败后果 | 建议配置 |
|---|---|---|---|
| Startup Probe | 模型加载完成、服务可访问 | 不标记为 Ready | failureThreshold=30, periodSeconds=10 |
| Liveness Probe | 进程未死锁、主线程存活 | 重启容器 | 极简 HTTP 200,timeoutSeconds=5 |
| Readiness Probe | 是否还能接收新请求 | 从 Endpoints 摘除 | 检查队列深度与 GPU 显存 |
🔍 Readiness 失败只摘流量不杀容器,Liveness 失败才重启。把负载检查放到 Readiness 是第一原则。
[外链图片转存中…(img-7BrQXAbJ-1779153757152)]
三、自定义就绪检查实战
Readiness Probe 不能只做简单 ping。生产就绪端点需暴露真实负载状态:排队请求数或 GPU 显存超阈值时返回 503,让负载均衡器把流量切走。
以下是基于 FastAPI 的实现框架。核心逻辑是维护运行时指标,在就绪端点按阈值返回状态。
fromfastapiimportFastAPI app=FastAPI()queue_depth=0max_queue_depth=16gpu_memory_percent=0.0max_gpu_memory_percent=0.92@app.get("/health/ready")asyncdefreadiness_probe():ifqueue_depth>=max_queue_depth:return{"status":"unready","reason":"queue_full"},503ifgpu_memory_percent>=max_gpu_memory_percent:return{"status":"unready","reason":"gpu_memory_high"},503return{"status":"ready"}@app.get("/health/live")asyncdefliveness_probe():return{"status":"alive"}💡 不要把就绪检查做成同步推理。若就绪端点需访问 GPU 状态,确保不进入主推理队列。
[外链图片转存中…(img-UVix0X4i-1779153757153)]
四、优雅终止:别让重启变成事故
即使探针配置正确,实例升级或缩容时仍需终止 Pod。Kubernetes 发送 SIGTERM 后给 Pod 宽限期,默认 30 秒。推理服务须在此窗口内停收新请求,并尽量让进行中的推理跑完。
importsignalimportsysimporttimefromfastapiimportRequest shutting_down=Falsedefhandle_sigterm(signum,frame):globalshutting_down shutting_down=Truetime.sleep(15)sys.exit(0)signal.signal(signal.SIGTERM,handle_sigterm)@app.middleware("http")asyncdefshutdown_guard(request:Request,call_next):ifshutting_downandrequest.url.path!="/health/live":return{"status":"shutting_down"},503returnawaitcall_next(request)⚙️ 生产环境更稳妥的做法是收到 SIGTERM 后立即将 Readiness 设为 false,等待活跃请求归零再退出。terminationGracePeriodSeconds 建议 120 秒以上,必须大于最长单请求推理时间。
🛡️ 关键参数是 terminationGracePeriodSeconds 必须大于最长单请求推理时间。
五、深度思考与趋势判断
当前主流推理框架的健康端点普遍偏简单,多数只提供 /health 返回 200,在生产规模化部署时显得不足。笔者认为推理服务健康模型正从二元存活向多维状态机演进。未来会出现三个趋势:按模型维度拆分健康状态;服务网格与自定义探针深度集成;推理框架内置过载保护,动态就绪反馈替代静态限流。
🎯 核心判断是推理服务的 SRE 体系不能照搬微服务经验。探针设计的本质是负载感知,而非心跳检测。
总结
推理服务被健康检查误杀,根源在探针逻辑与负载特征不匹配。通过建立三级探针体系、自定义就绪检查与优雅终止机制,可将重启频率从每小时数次降到每周数次。
你在部署大模型推理服务时,是否遇到过探针误杀问题?欢迎分享经验。
📌 别忘了点赞收藏,后续持续更新 AI 推理优化的深度解析与实战干货。关注我带你玩转 AI。