4、Pod故障场景:OOM Killer、GPU驱动崩溃、容器进程挂死,如何通过Probe检测

说实话,vLLM推理服务最让人头疼的,不是流量大了扛不住,而是Pod莫名其妙就挂了。你查日志,发现是OOM;你重启,发现GPU驱动报错;你盯着看,进程还在但就是不响应请求。这三种情况,我全踩过坑。

今天咱们就聊聊,怎么用Probe把这三种故障都揪出来。

4.1 OOM Killer:内存杀手怎么防?

OOM Killer,说白了就是Linux内核的"杀人机制"。当系统内存不够时,内核会挑一个进程杀掉。vLLM这种吃显存大户,特别容易中招。

我遇到过最惨的一次,是模型加载时显存估算失误,Pod直接被OOM Kill了。K8s检测到Pod退出,自动重启,结果重启后还是OOM,陷入死循环。

怎么检测?用livenessProbe配合exec命令,检查进程是否还活着:

livenessProbe:
  exec:
    command:
    - cat
    - /proc/1/status
  initialDelaySeconds: 30
  periodSeconds: 10
  failureThreshold: 3

但说实话,这招只能检测进程是否存活。OOM Kill后进程直接没了,K8s自己就能感知到Pod状态变化。真正要防的是即将发生的OOM。

我的经验:在vLLM容器里加一个内存监控脚本,当内存使用超过90%时,主动触发readinessProbe失败,让K8s先把流量切走,再优雅缩容或扩容。

4.2 GPU驱动崩溃:无声的杀手

GPU驱动崩溃,比OOM更隐蔽。进程还在,Pod状态还是Running,但推理请求全部超时。你查kubectl logs,啥也没有;查nvidia-smi,报错说驱动挂了。

为什么会这样?因为GPU驱动是内核模块,它崩溃了,用户态的vLLM进程感知不到。K8s只看进程是否存活,所以Pod一直显示Running。

我建议用livenessProbe配合nvidia-smi命令来检测:

livenessProbe:
  exec:
    command:
    - nvidia-smi
    - --query-gpu=index,name,temperature.gpu,utilization.gpu,memory.used,memory.total
    - --format=csv,noheader
  initialDelaySeconds: 15
  periodSeconds: 30
  failureThreshold: 2

这个Probe每隔30秒跑一次nvidia-smi。如果驱动崩溃,命令会返回非零退出码,Probe失败,K8s就会重启Pod。

注意:有些场景下nvidia-smi会卡住(比如驱动半死不活的状态),导致Probe超时。建议设置timeoutSeconds: 10,避免Probe本身成为性能瓶颈。

4.3 容器进程挂死:最头疼的情况

进程挂死,比前两种都难搞。进程在,端口在,但就是不干活。你发请求,它不响应;你查日志,最后一行停在半小时前。

我遇到过vLLM的推理线程死锁,所有请求都卡在队列里。Pod状态正常,但业务方疯狂报警。

这种场景,livenessProbereadinessProbe都得用上:

readinessProbe:
  httpGet:
    path: /health
    port: 8000
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 3

livenessProbe:
  httpGet:
    path: /health
    port: 8000
  initialDelaySeconds: 30
  periodSeconds: 15
  failureThreshold: 3

这里的关键是/health端点。vLLM默认提供这个接口,但只检查进程是否活着。我建议你自定义一个健康检查接口,做更深层的检测:

  • 检查推理队列长度是否超过阈值
  • 检查最近一次推理是否超时
  • 检查GPU显存是否泄漏

说白了,就是让Probe去问vLLM:"你还好吗?能干活吗?"而不是只问:"你还活着吗?"

4.4 三种场景的Probe策略对比

故障场景 推荐Probe类型 检测方式 关键参数
OOM Killer livenessProbe + readinessProbe 内存使用率监控 + 进程存活检查 initialDelaySeconds: 30, periodSeconds: 10
GPU驱动崩溃 livenessProbe nvidia-smi命令执行 periodSeconds: 30, failureThreshold: 2, timeoutSeconds: 10
容器进程挂死 livenessProbe + readinessProbe HTTP健康检查 + 自定义深度检测 periodSeconds: 5 (readiness), 15 (liveness)

4.5 实战避坑指南

我曾经踩过一个坑:把livenessProbereadinessProbe的检测逻辑写得太重,导致Probe本身占用了大量CPU。vLLM推理本来就吃资源,Probe再一抢,推理延迟直接飙升。

我的建议是:

  • Probe的检测逻辑要轻量,别在里面跑模型推理
  • initialDelaySeconds给Pod足够的启动时间,vLLM加载模型可能要几分钟
  • failureThreshold别设太小,避免网络抖动导致误杀
  • 日志里记录Probe的检测结果,方便排查问题
核心思路:Probe不是万能的,但它能帮你把故障发现时间从"用户报警"缩短到"K8s自动检测"。这个时间差,可能就是服务SLA的生死线。

4.6 知识体系图

下面这张图,把三种故障场景和对应的Probe策略串起来了。你一看就明白:

Pod故障场景与Probe检测策略 vLLM推理Pod OOM Killer 内存耗尽被内核杀死 GPU驱动崩溃 驱动异常,nvidia-smi失败 容器进程挂死 进程存活但不响应请求 检测策略 livenessProbe 内存监控 + 优雅缩容 检测策略 livenessProbe nvidia-smi命令检测 检测策略 liveness + readiness 自定义健康检查接口 核心目标:缩短故障发现时间 从用户报警 → K8s自动检测 → 自动恢复

嗯,这张图把三种故障和对应的Probe策略都串起来了。你对照着看,应该能快速定位问题。

最后说一句:Probe配置好了,不等于万事大吉。我建议你定期做混沌工程实验,主动注入故障,验证Probe是否真的能检测到。别等到线上出问题了,才发现Probe配置错了。

专注资料整理