3、故障转移概述:什么是故障转移、K8s自愈机制、Pod重启策略

各位同学,咱们今天聊点实在的。vLLM 跑在 K8s 上,最怕什么?怕它挂了没人管。你想想看,线上推理服务正跑着,突然 Pod 崩了,用户那边请求全超时——这场景,我经历过不止一次。

所以这一章,咱们把故障转移这件事彻底讲透。说白了,就是让系统在出问题的时候,自己能“活过来”。

3.1 什么是故障转移?

故障转移,英文叫 Failover。我个人的理解很简单:当某个组件挂了,系统能自动把流量切到健康的组件上,保证服务不中断。

在 K8s 的世界里,故障转移不是靠某个单一功能实现的。它是一套组合拳:

  • 健康检查:K8s 怎么知道 Pod 挂了?靠探针。
  • 自动重启:发现挂了之后怎么办?重启策略说了算。
  • 流量切换:重启期间流量去哪?Service + Endpoint 负责调度。

我记得有一次线上事故,vLLM 服务因为显存泄漏导致 OOM,Pod 被 Kill 了。但因为我们配置了正确的探针和重启策略,整个过程用户几乎无感知。嗯,这就是故障转移的价值。

核心观点:故障转移不是“出了事再补救”,而是“设计时就考虑好怎么恢复”。
K8s 故障转移核心流程 用户请求 → Service Pod 运行 vLLM 服务 Liveness / Readiness 探针 健康 → 继续服务 不健康 → 触发重启 Kubelet 执行重启策略

3.2 K8s 自愈机制:Liveness 和 Readiness 探针

K8s 的自愈能力,核心就靠两个探针:Liveness ProbeReadiness Probe。很多人搞混它们,其实区别很清晰。

3.2.1 Liveness Probe(存活探针)

这个探针回答一个问题:“Pod 还活着吗?”

如果 Liveness 探测失败,Kubelet 会认为 Pod 已经“死”了,然后根据重启策略干掉它、重新拉一个。我习惯把 Liveness 理解为“心跳检测”——只要程序还在跑,就算正常。

但这里有个坑。我曾经遇到一个案例:vLLM 服务因为某个请求卡死,进程没挂,但不再响应新请求了。Liveness 只检查进程是否存活,结果一直返回成功。实际上服务已经废了。所以光靠 Liveness 不够。

3.2.2 Readiness Probe(就绪探针)

这个探针回答另一个问题:“Pod 准备好接收流量了吗?”

Readiness 探测失败,K8s 会把 Pod 从 Service 的 Endpoint 列表中移除,流量就不会打过来了。但 Pod 不会被重启。

你想想看,这对 vLLM 推理服务有多重要?模型加载需要时间,如果 Readiness 没配好,流量在模型还没加载完就涌进来,直接报错。我建议 Readiness 探针一定要检查模型是否加载完成、推理接口是否可用。

我的经验:对于 vLLM 服务,Liveness 用 TCP 或 HTTP 检查进程端口,Readiness 用 HTTP 检查 /health 或 /v1/models 接口。这样既保证进程活着,也保证推理能力在线。

3.2.3 探针配置示例

apiVersion: v1
kind: Pod
metadata:
  name: vllm-inference
spec:
  containers:
  - name: vllm
    image: vllm/vllm-openai:latest
    ports:
    - containerPort: 8000
    livenessProbe:
      httpGet:
        path: /health
        port: 8000
      initialDelaySeconds: 30   # 给模型加载留时间
      periodSeconds: 10         # 每10秒检查一次
      failureThreshold: 3       # 连续3次失败才算真挂了
    readinessProbe:
      httpGet:
        path: /v1/models
        port: 8000
      initialDelaySeconds: 45   # 模型加载完再检查
      periodSeconds: 5
      failureThreshold: 2

注意看 initialDelaySeconds。我刚开始部署 vLLM 时,设得太短,模型还没加载完探针就开始检查,结果 Pod 一直被重启。后来调大了这个值,世界清净了。

3.3 Pod 重启策略

探针发现问题后,怎么处理?这就轮到重启策略上场了。K8s 支持三种策略:

策略 行为 适用场景
Always 容器退出后总是重启 推理服务、Web 服务等需要持续运行的 Pod
OnFailure 只有退出码非0时才重启 批处理任务、一次性 Job
Never 从不重启 调试、一次性测试

对于 vLLM 推理服务,我几乎只用 Always。为什么?因为推理服务是长跑选手,挂了就得立刻拉起来。OnFailure 适合那种跑完就结束的任务,比如数据预处理。

避坑指南:我曾经把 vLLM 的 restartPolicy 设成了 OnFailure,结果有一次 Pod 因为 OOM 被 Kill,退出码是 137(SIGKILL),OnFailure 策略认为这是“正常退出”,没重启。服务挂了半小时才发现。所以,线上推理服务请务必用 Always。

3.4 三者如何配合?

咱们把这三个概念串起来,看看完整的故障转移流程:

  1. Readiness 探针发现 Pod 不健康 → 从 Service 摘掉流量
  2. Liveness 探针发现 Pod 挂了 → 通知 Kubelet
  3. Kubelet 根据 restartPolicy 决定是否重启
  4. 重启后,Readiness 探针再次检查,通过后才恢复流量

你看,这一套流程下来,用户几乎感觉不到服务中断。嗯,这就是 K8s 自愈的魅力。

一句话总结:Liveness 保命,Readiness 保流量,restartPolicy 定规则。三者缺一不可。

好了,这一章的内容就到这里。记住,故障转移不是玄学,是设计出来的。下一章咱们会深入实战,看看怎么给 vLLM 配一套靠谱的探针。


专注资料整理