Skip to content

필사 모드: KServe 模型服务完全指南:InferenceService、Canary 部署、Transformer、InferenceGraph 生产运维

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
KServe 模型服务

引言

训练 ML 模型和在生产环境中稳定地提供服务,本质上是两类不同的工程课题。在训练阶段,GPU 利用率和收敛速度是关键,而在服务阶段,延迟、吞吐量、版本管理、安全上线、故障恢复才是决定性因素。尤其是在多个模型相互协作的复合推理流水线中,单纯把模型丢进 Flask 的做法根本承受不住运维复杂度。

KServe(前身为 KFServing)是一个 CNCF Incubating 项目,专为以 Kubernetes 原生方式解决这类生产模型服务问题而设计。通过 InferenceService CRD 可以声明式地部署模型,借助基于 Knative 的自动伸缩来应对流量波动,用 Canary 部署实现安全上线,并可用 InferenceGraph 构建基于 DAG 的复合推理。

KServe 于 2019 年以 KFServing 之名作为 Kubeflow 项目的一部分起步,2021 年独立出来并更名为 KServe。2023 年加入 CNCF Sandbox 后快速成长,到 2025 年晋升为 Incubating 阶段。它支持 TFServing、TorchServe、Triton、vLLM 等主要推理运行时,并顺应 LLM 时代扩展到了 vLLM 后端与 Envoy AI Gateway 的集成。

本文将从 KServe 的核心架构一路讲到生产运维策略,配合代码覆盖实战所需的一切。

InferenceService CRD 深入解析

Predictor / Transformer / Explainer 架构

KServe 的 InferenceService 由三个核心组件构成。

Client Request
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
Transformer │────▶│  Predictor  │────▶│  Explainer (前处理/ (模型推理) (生成解释)│  后处理)    │◀────│             │     │             │
└─────────────┘     └─────────────┘     └─────────────┘
Client Response
  • Predictor:核心推理引擎。支持 TFServing、TorchServe、Triton、XGBoost、LightGBM、Sklearn、vLLM 等多种运行时。
  • Transformer:负责推理请求的前处理与响应的后处理。将图像缩放、分词、特征工程等工作从 Predictor 中分离出来,可以独立进行伸缩。
  • Explainer:为推理结果生成解释。通过 Alibi Explainer、AIF360 等提供模型预测依据。

支持的运行时对比

运行时框架GPU 支持动态批处理LLM 服务主要用途
TFServingTensorFlowOOXTF SavedModel 服务
TorchServePyTorchOOXPyTorch 模型服务
Triton多框架OOO多模型并发服务
vLLMPyTorch/HuggingFaceOOOLLM 推理优化
SklearnScikit-learnXXX轻量级 ML 模型
XGBoostXGBoostOXX梯度提升
LGBMLightGBMXXX梯度提升

基本的 InferenceService YAML

最基本形态的 InferenceService 只定义 Predictor。下面是一个为存放在 S3 上的 Sklearn 模型提供服务的示例。

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: sklearn-iris
  namespace: ml-serving
  annotations:
    serving.kserve.io/deploymentMode: Serverless
spec:
  predictor:
    minReplicas: 1
    maxReplicas: 10
    scaleTarget: 5
    scaleMetric: concurrency
    model:
      modelFormat:
        name: sklearn
      storageUri: 's3://ml-models/sklearn/iris/v1'
      resources:
        requests:
          cpu: '500m'
          memory: '512Mi'
        limits:
          cpu: '1'
          memory: '1Gi'

应用这份 YAML 后,KServe 控制器会创建 Knative Service,通过 Istio VirtualService 配置路由,并由 Knative Pod Autoscaler 基于 concurrency 执行自动伸缩。

vLLM 后端的 LLM 服务

从 KServe v0.13 起,vLLM 作为一级运行时得到支持。它会自动暴露与 OpenAI 兼容的 API,因此可以直接沿用现有的 OpenAI 客户端代码。

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: llama3-vllm
  namespace: ml-serving
spec:
  predictor:
    minReplicas: 1
    maxReplicas: 4
    model:
      modelFormat:
        name: vLLM
      storageUri: 'pvc://llm-model-cache/Meta-Llama-3.1-8B-Instruct'
      args:
        - '--max-model-len=8192'
        - '--gpu-memory-utilization=0.90'
        - '--enable-chunked-prefill'
        - '--max-num-batched-tokens=16384'
        - '--tensor-parallel-size=2'
      resources:
        requests:
          cpu: '8'
          memory: '32Gi'
          nvidia.com/gpu: '2'
        limits:
          cpu: '16'
          memory: '64Gi'
          nvidia.com/gpu: '2'
    tolerations:
      - key: 'nvidia.com/gpu'
        operator: 'Exists'
        effect: 'NoSchedule'
    nodeSelector:
      gpu-type: 'a100'

storageUri 中指定 PVC,可以把体积庞大的 LLM 权重提前缓存到节点上,从而实现快速加载。tensor-parallel-size=2 会把模型分散部署到 2 张 GPU 上,突破单张 GPU 的显存上限。

Canary 部署策略

用 canaryTrafficPercent 实现渐进式上线

在生产环境更新模型时,最危险的时刻就是新版本刚部署完之后。KServe 通过 canaryTrafficPercent 字段原生支持 Canary 部署,可以把流量逐步迁移到新版本。

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: fraud-detector
  namespace: ml-serving
  annotations:
    serving.kserve.io/deploymentMode: Serverless
spec:
  predictor:
    canaryTrafficPercent: 10
    minReplicas: 2
    maxReplicas: 20
    model:
      modelFormat:
        name: sklearn
      storageUri: 's3://ml-models/fraud/v2'
      resources:
        requests:
          cpu: '1'
          memory: '2Gi'
        limits:
          cpu: '2'
          memory: '4Gi'

上面的配置只把 10% 的总流量路由到新模型(v2),其余 90% 仍发往现有的稳定版本。部署后通过监控验证新版本的表现,再逐步调高 canaryTrafficPercent

分阶段切换脚本

编写自动化的渐进式上线脚本,可以减少人为失误。

#!/bin/bash
# canary-promote.sh - 渐进式 Canary 晋级脚本
ISVC_NAME="fraud-detector"
NAMESPACE="ml-serving"
STAGES=(10 30 50 80 100)
MAX_ERROR_RATE=0.05
OBSERVE_MINUTES=10

for pct in "${STAGES[@]}"; do
  echo "=== 将 Canary 流量更新为 ${pct}% ==="

  kubectl patch inferenceservice "$ISVC_NAME" -n "$NAMESPACE" \
    --type='json' \
    -p="[{\"op\": \"replace\", \"path\": \"/spec/predictor/canaryTrafficPercent\", \"value\": $pct}]"

  echo "正在观察 ${OBSERVE_MINUTES} 分钟的指标..."
  sleep $((OBSERVE_MINUTES * 60))

  # 从 Prometheus 查询 canary 错误率
  ERROR_RATE=$(curl -s "http://prometheus:9090/api/v1/query" \
    --data-urlencode "query=rate(revision_request_count{revision_name=~\".*canary.*\",response_code!=\"200\"}[5m]) / rate(revision_request_count{revision_name=~\".*canary.*\"}[5m])" \
    | jq -r '.data.result[0].value[1] // "0"')

  if (( $(echo "$ERROR_RATE > $MAX_ERROR_RATE" | bc -l) )); then
    echo "错误率 ${ERROR_RATE} 超过阈值 ${MAX_ERROR_RATE}。执行回滚。"
    kubectl patch inferenceservice "$ISVC_NAME" -n "$NAMESPACE" \
      --type='json' \
      -p='[{"op": "replace", "path": "/spec/predictor/canaryTrafficPercent", "value": 0}]'
    exit 1
  fi

  echo "错误率 ${ERROR_RATE} —— 处于正常范围。继续下一阶段。"
done

echo "=== Canary 晋级完成。v2 现已承载 100% 流量。 ==="

这个脚本将流量分 5 个阶段从 10% 切换到 100%,每个阶段都会监控 10 分钟的错误率。若错误率超过 5%,会自动回滚到 0%。

自定义 Transformer 实现

前处理/后处理流水线设计

在实际生产环境中,需要把客户端发来的原始数据(图像 URL、文本、JSON)转换成模型期望的张量格式。将 Transformer 与 Predictor 分离,能带来以下好处。

  • 独立伸缩:当前处理是 CPU 密集型、而推理是 GPU 密集型时,可以分别应用不同的伸缩策略
  • 可复用性:同一个 Transformer 可以在多个模型版本间复用
  • 部署独立性:更改 Transformer 逻辑时无需重新部署模型即可更新

继承 kserve.Model 并实现处理函数

通过继承 KServe Python SDK 的 kserve.Model 类来实现自定义 Transformer。

import kserve
from kserve import InferRequest, InferResponse, InferInput
from typing import Dict, List
import numpy as np
from PIL import Image
import requests
from io import BytesIO
import logging

logger = logging.getLogger(__name__)

class ImageTransformer(kserve.Model):
    """接收图像 URL,前处理后转发给 Predictor 的 Transformer"""

    def __init__(self, name: str, predictor_host: str):
        super().__init__(name)
        self.predictor_host = predictor_host
        self.target_size = (224, 224)
        self.mean = np.array([0.485, 0.456, 0.406])
        self.std = np.array([0.229, 0.224, 0.225])
        self.ready = False

    def load(self):
        """模型初始化。在此处放置 Warm-up 逻辑。"""
        logger.info("ImageTransformer 初始化完成")
        self.ready = True

    def preprocess(
        self, payload: Dict, headers: Dict = None
    ) -> InferRequest:
        """接收图像 URL,转换为归一化后的张量"""
        instances = payload.get("instances", [])
        processed_images = []

        for instance in instances:
            image_url = instance.get("image_url")
            response = requests.get(image_url, timeout=10)
            response.raise_for_status()

            image = Image.open(BytesIO(response.content)).convert("RGB")
            image = image.resize(self.target_size)

            # 转换为 numpy 数组后做归一化
            img_array = np.array(image, dtype=np.float32) / 255.0
            img_array = (img_array - self.mean) / self.std
            img_array = np.transpose(img_array, (2, 0, 1))  # CHW
            processed_images.append(img_array)

        input_tensor = np.stack(processed_images)

        infer_input = InferInput(
            name="input",
            shape=list(input_tensor.shape),
            datatype="FP32",
            data=input_tensor.tolist(),
        )
        return InferRequest(
            model_name=self.name,
            infer_inputs=[infer_input],
        )

    def postprocess(
        self, response: InferResponse, headers: Dict = None
    ) -> Dict:
        """将模型输出转换为易于阅读的格式"""
        predictions = response.outputs[0].data

        class_names = ["cat", "dog", "bird", "fish", "other"]
        results = []

        for pred in predictions:
            if isinstance(pred, list):
                probs = np.array(pred)
            else:
                probs = np.array([pred])

            top_idx = int(np.argmax(probs))
            results.append({
                "class": class_names[top_idx],
                "confidence": float(probs[top_idx]),
                "all_scores": {
                    name: float(score)
                    for name, score in zip(class_names, probs)
                },
            })

        return {"predictions": results}


if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--predictor_host", required=True)
    parser.add_argument("--model_name", default="image-classifier")
    args = parser.parse_args()

    transformer = ImageTransformer(
        name=args.model_name,
        predictor_host=args.predictor_host,
    )
    transformer.load()
    kserve.ModelServer(workers=4).start([transformer])

包含 Transformer 的 InferenceService YAML

把 Transformer 集成进 InferenceService 后,KServe 会自动配置 Transformer 与 Predictor 之间的内部路由。

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: image-classifier
  namespace: ml-serving
spec:
  transformer:
    minReplicas: 2
    maxReplicas: 15
    scaleTarget: 10
    scaleMetric: concurrency
    containers:
      - name: image-transformer
        image: registry.example.com/ml/image-transformer:v1.2.0
        args:
          - '--model_name=image-classifier'
        resources:
          requests:
            cpu: '1'
            memory: '2Gi'
          limits:
            cpu: '2'
            memory: '4Gi'
        env:
          - name: STORAGE_URI
            value: ''
  predictor:
    minReplicas: 1
    maxReplicas: 8
    model:
      modelFormat:
        name: pytorch
      storageUri: 's3://ml-models/image-classifier/resnet50-v2'
      resources:
        requests:
          cpu: '2'
          memory: '4Gi'
          nvidia.com/gpu: '1'
        limits:
          cpu: '4'
          memory: '8Gi'
          nvidia.com/gpu: '1'

在这个配置中,Transformer 在 CPU 节点上最多可扩展到 15 个,Predictor 在 GPU 节点上最多可扩展到 8 个。当前处理成为瓶颈时,只需增加 Transformer 的数量即可,因此更具成本效益。

InferenceGraph:基于 DAG 的复合推理

4 种节点类型

InferenceGraph 是 KServe 的高级功能,可以把多个 InferenceService 连接成 DAG,构建复合推理流水线。它从 v0.11 起晋升为 GA,支持 4 种节点类型。

节点类型执行方式输入传递主要用例说明
Sequence顺序执行把前一节点的输出作为下一节点的输入前处理链把 A 的结果传给 B 作为输入
Switch条件分支根据条件选择一个节点A/B 测试、路由基于条件选择单一路径
Ensemble并行执行 + 汇总把相同输入传给所有节点集成推理汇总/投票多个模型的结果
Splitter加权分配按比例选择一个节点流量拆分、Canary基于权重的流量路由

A/B 测试与集成模式

生产环境中经常使用的模式,是集成与 A/B 测试的组合。例如在欺诈检测系统中,同时运行基于规则的模型、XGBoost 模型和深度学习模型,再对结果做集成,就能比单一模型获得更高的准确率。

apiVersion: serving.kserve.io/v1alpha1
kind: InferenceGraph
metadata:
  name: fraud-detection-ensemble
  namespace: ml-serving
  annotations:
    serving.kserve.io/propagateHeaders: 'x-request-id,x-trace-id'
spec:
  nodes:
    root:
      routerType: Sequence
      steps:
        - name: feature-enrichment
          serviceName: feature-enricher
          weight: 100
        - name: ensemble-node
          nodeName: model-ensemble
    model-ensemble:
      routerType: Ensemble
      steps:
        - name: xgboost-model
          serviceName: fraud-xgboost
          weight: 40
        - name: deep-model
          serviceName: fraud-deep-learning
          weight: 40
        - name: rule-engine
          serviceName: fraud-rule-engine
          weight: 20
    result-combiner:
      routerType: Sequence
      steps:
        - name: weighted-average
          serviceName: ensemble-combiner
          weight: 100

这个 InferenceGraph 的运行方式如下。

  1. root 节点(Sequence):首先由 feature-enricher 把原始数据转换为丰富的特征,再把结果传给 model-ensemble 节点。
  2. model-ensemble 节点(Ensemble):XGBoost、深度学习、规则引擎三个模型以相同的输入并行执行。各模型的 weight 会在汇总最终结果时用作权重。
  3. 最终结果由三个模型的加权平均得出。

用于 A/B 测试的 Splitter 模式

apiVersion: serving.kserve.io/v1alpha1
kind: InferenceGraph
metadata:
  name: recommendation-ab-test
  namespace: ml-serving
spec:
  nodes:
    root:
      routerType: Splitter
      steps:
        - name: model-v1-stable
          serviceName: recommender-v1
          weight: 80
        - name: model-v2-experiment
          serviceName: recommender-v2
          weight: 20

Splitter 会把 80% 的流量分配给稳定版本,20% 分配给实验版本。与 InferenceService 的 Canary 不同,InferenceGraph 的 Splitter 是在完全独立的 InferenceService 之间做流量拆分,因此适用于不同模型架构之间的 A/B 测试。

自动伸缩策略

Knative Pod Autoscaler(KPA)vs HPA vs KEDA

KServe 支持三种自动伸缩器。适合的伸缩器会因工作负载特性而异。

特性KPA(Knative)HPA(Kubernetes)KEDA
Scale-to-ZeroOXO
伸缩指标concurrency、rpscpu、memory、custom外部指标(Prometheus、CloudWatch 等)
响应速度快(1-2 秒)一般(15-30 秒)一般(15 秒)
GPU 工作负载有限适合非常适合
自定义指标有限需要 Metrics API丰富的 Scaler 支持
Cold Start 应对activationScaleN/AminReplicaCount
配置复杂度

GPU 工作负载的 Scale-to-Zero

GPU 实例成本较高,因此 Scale-to-Zero 很重要。但 GPU 模型的 cold start 时间较长(从数十秒到数分钟),需要格外留意。使用 KPA 时,应恰当设置 scaledown 的延迟时间。

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: gpu-model
  namespace: ml-serving
  annotations:
    # 启用 Scale-to-Zero(默认值)
    serving.kserve.io/enable-scale-to-zero: 'true'
    # 最后一次请求后到 Scale-to-Zero 的等待时间
    autoscaling.knative.dev/scale-to-zero-pod-retention-period: '15m'
    # 缩容延迟(防止骤然缩容)
    autoscaling.knative.dev/scale-down-delay: '5m'
    # 可并发处理的请求数(GPU 模型应设置得较低)
    autoscaling.knative.dev/target: '2'
    autoscaling.knative.dev/metric: 'concurrency'
spec:
  predictor:
    minReplicas: 0
    maxReplicas: 4
    model:
      modelFormat:
        name: pytorch
      storageUri: 's3://ml-models/large-model/v1'
      resources:
        requests:
          nvidia.com/gpu: '1'
        limits:
          nvidia.com/gpu: '1'

KEDA + vLLM 指标自动伸缩

在 LLM 服务中,不依赖 CPU/内存,而是基于 vLLM 自身的指标(等待中的请求数、KV 缓存使用率)进行伸缩更为有效。借助 KEDA 的 Prometheus Scaler 可以实现这一点。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: llama3-vllm-scaler
  namespace: ml-serving
spec:
  scaleTargetRef:
    apiVersion: serving.kserve.io/v1beta1
    kind: InferenceService
    name: llama3-vllm
  minReplicaCount: 1
  maxReplicaCount: 8
  pollingInterval: 15
  cooldownPeriod: 300
  advanced:
    restoreToOriginalReplicaCount: true
    horizontalPodAutoscalerConfig:
      behavior:
        scaleUp:
          stabilizationWindowSeconds: 30
          policies:
            - type: Pods
              value: 2
              periodSeconds: 60
        scaleDown:
          stabilizationWindowSeconds: 300
          policies:
            - type: Pods
              value: 1
              periodSeconds: 120
  triggers:
    # 基于 vLLM 等待请求数的伸缩
    - type: prometheus
      metadata:
        serverAddress: http://prometheus.monitoring:9090
        metricName: vllm_waiting_requests
        query: |
          avg(vllm:num_requests_waiting{model_name="llama3-vllm"})
        threshold: '5'
    # 基于 KV Cache 使用率的伸缩
    - type: prometheus
      metadata:
        serverAddress: http://prometheus.monitoring:9090
        metricName: vllm_kv_cache_usage
        query: |
          avg(vllm:gpu_cache_usage_perc{model_name="llama3-vllm"})
        threshold: '0.85'

这个配置在以下两个条件中任意一个满足时,就会触发扩容。

  • vLLM 平均等待请求数超过 5 个时,增加 Pod。
  • GPU KV 缓存使用率超过 85% 时,增加 Pod。

缩容时会应用 5 分钟的稳定化窗口与每 2 分钟减少 1 个的策略,以防止骤然缩容。

v0.15 新特性

Envoy AI Gateway 集成

KServe v0.15(2025 年 6 月)中最值得关注的功能是 Envoy AI Gateway 集成,它为 LLM 服务提供了专门的路由与可观测性。

  • 基于 Token 的 Rate Limiting:按 API 密钥限制每分钟/每小时的 Token 使用量
  • 模型级路由:基于请求中的 model 字段路由到相应的后端(vLLM、Triton、外部 API)
  • Semantic Caching:对相似 Prompt 的响应进行缓存,降低成本与延迟
  • Usage Tracking:按模型/用户/团队跟踪 Token 使用量、延迟、错误率等

LocalModelCache 多节点组

如果每次都从 S3 下载大规模 LLM 权重,cold start 会耗费数分钟。v0.15 的 LocalModelCache 会把模型提前缓存到节点本地磁盘,大幅缩短 startup 时间。

apiVersion: serving.kserve.io/v1alpha1
kind: LocalModelCache
metadata:
  name: llama3-cache
  namespace: ml-serving
spec:
  sourceModelUri: 's3://ml-models/Meta-Llama-3.1-8B-Instruct'
  nodeGroups:
    - name: a100-nodes
      nodeSelector:
        gpu-type: 'a100'
      persistentVolumeClaimSpec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 50Gi
        storageClassName: local-nvme

这个配置会在所有带有 gpu-type: a100 标签的节点上创建 50Gi 的 NVMe 卷,并提前从 S3 下载模型权重。Pod 启动时会从本地磁盘而非 S3 加载权重,因此 cold start 时间可以从数分钟缩短到数秒。

LLM 服务优化

v0.15 中包含了多项针对 LLM 工作负载的优化。

  • LoRA 适配器 Hot-Swapping:在保留基础模型的同时,动态替换 LoRA 适配器。在多租户环境中可高效地为每个客户提供各自微调后的模型
  • 支持 Speculative Decoding:在 vLLM 后端借助 Draft Model 进行推测解码,将 Token 生成速度提升 2-3 倍
  • Prefix Caching:共享系统 Prompt 等重复前缀的 KV 缓存,缩短 TTFT(Time To First Token)

失败案例与故障排查

案例 1:Transformer OOM 导致推理流水线中断

现象:在图像分类流水线中,Transformer Pod 间歇性地被 OOMKilled,导致整个推理链失败。

原因分析:Transformer 在把大尺寸图像(8K 分辨率)加载到内存时,PIL 会按解压后的原始尺寸分配内存。当同时涌入 10 个请求时,瞬间需要 10 x 200MB = 2GB,而内存 limit 却设置为 1Gi。

解决方法:

# 在前处理的最早阶段就限制图像尺寸
from PIL import Image

# PIL DecompressionBomb 防护设置
Image.MAX_IMAGE_PIXELS = 89_478_485  # 约 9500x9500

def safe_load_image(image_bytes: bytes, max_size: int = 2048):
    """内存安全的图像加载"""
    img = Image.open(BytesIO(image_bytes))

    # 若原始尺寸超过 max_size,立即缩放
    if max(img.size) > max_size:
        ratio = max_size / max(img.size)
        new_size = (int(img.width * ratio), int(img.height * ratio))
        img = img.resize(new_size, Image.LANCZOS)

    return img.convert("RGB")

此外还把 Transformer 的内存 limit 上调到 4Gi,并把 concurrency target 降到 5,以此限制并发处理量。

案例 2:Scale-to-Zero 状态下的 Cold Start 延迟

现象:GPU 模型在 Scale-to-Zero 状态下,首个请求出现超过 60 秒的超时。

原因分析:从 S3 下载模型权重(2GB)并加载到 GPU 内存所需的时间,超过了 Knative 的默认超时时间(30 秒)。

解决方法:

  1. progressDeadline 扩展为 600 秒
  2. 应用 LocalModelCache,把模型预先缓存到节点本地
  3. 设置 minReplicas: 1,始终保留至少 1 个 Pod(在成本允许的情况下)

调试清单

调试 KServe 部署问题时,应系统性检查以下项目。

  1. 确认 InferenceService 状态:在 kubectl get isvc -n ml-serving 中确认 READY 是否为 True
  2. 确认 Pod 状态:用 kubectl get pods -n ml-serving -l serving.kserve.io/inferenceservice=MODEL_NAME 检查 Pod 状态
  3. 确认事件:在 kubectl describe isvc MODEL_NAME -n ml-serving 中查看 Events 部分
  4. 确认 Knative Revision:在 kubectl get revisions -n ml-serving 中检查 revision 状态
  5. 确认存储访问:检查 StorageInitializer 日志中是否存在 S3/GCS 访问错误
  6. 确认 Istio 路由:在 kubectl get virtualservice -n ml-serving 中检查流量路由规则
  7. 确认资源是否不足:在 kubectl describe node 中检查 GPU 可分配量与内存余量

运维注意事项

GPU 节点调度与 tolerations

GPU 节点通常都设置了 taint,因此 InferenceService 必须明确指定 tolerations 和 nodeSelector。若遗漏这一点,Pod 会一直停留在 Pending 状态。

spec:
  predictor:
    tolerations:
      - key: 'nvidia.com/gpu'
        operator: 'Exists'
        effect: 'NoSchedule'
    nodeSelector:
      gpu-type: 'a100'
    model:
      modelFormat:
        name: vLLM
      # ... 模型设置

模型缓存策略

运维大规模模型时,分层缓存策略必不可少。

  • 一级缓存(节点本地):利用 LocalModelCache,把模型权重保存在 NVMe SSD 上。加载速度最快
  • 二级缓存(PVC):利用 PersistentVolumeClaim,缓存到网络存储。可在节点间共享
  • 三级原始存储(Object Storage):在 S3、GCS 等处保存模型的原始文件。速度最慢但持久性最高

资源 Quota 管理

按命名空间设置 ResourceQuota,以防止团队之间的 GPU 资源争抢。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: ml-serving-quota
  namespace: ml-serving
spec:
  hard:
    requests.cpu: '64'
    requests.memory: '256Gi'
    requests.nvidia.com/gpu: '8'
    limits.cpu: '128'
    limits.memory: '512Gi'
    limits.nvidia.com/gpu: '8'
    persistentvolumeclaims: '20'

这个 Quota 把 ml-serving 命名空间的使用上限限制为最多 8 张 GPU、128 核 CPU、512Gi 内存。按团队拆分命名空间并各自分配合适的 Quota,就能实现稳定的多租户运维。

参考资料

현재 단락 (1/514)

训练 ML 模型和在生产环境中稳定地提供服务,本质上是两类不同的工程课题。在训练阶段,GPU 利用率和收敛速度是关键,而在服务阶段,延迟、吞吐量、版本管理、安全上线、故障恢复才是决定性因素。尤其是在多...

작성 글자: 0원문 글자: 16,145작성 단락: 0/514