跳转到内容

vLLM 面试题

30 道题
分类
LLM
题目数
30 道
已阅读 0 / 30 题
1 vLLM 的核心架构与 PagedAttention 原理是什么?

答案:

vLLM 是面向 LLM 推理服务的高吞吐、低延迟引擎,其核心创新为 PagedAttention 算法,将 KV Cache 按页(Page)管理,实现显存零浪费和请求间 KV Cache 共享。

核心架构:

OpenAI Compatible API Server (FastAPI / uvicorn)
    ├── Scheduler(调度器)
    │   ├── 请求队列管理
    │   ├── Preemption 策略(Swap / Recomputation)
    │   └── Continuous Batching(连续批处理)
    ├── LLM Engine(推理引擎)
    │   ├── Worker(GPU 推理执行单元)
    │   │   ├── Model Runner
    │   │   │   ├── PagedAttention Kernel
    │   │   │   ├── Quantization Layer(AWQ / GPTQ / FP8)
    │   │   │   └── CUDA Graph Capture
    │   │   └── KV Cache Manager
    │   │       ├── Block Table(页表)
    │   │       ├── Block Allocator(显存页分配器)
    │   │       └── Prefix Cache(前缀缓存)
    │   └── Parallel Execution
    │       ├── Tensor Parallelism(Megatron-LM)
    │       └── Pipeline Parallelism
    ├── Tokenizer
    │   └── HuggingFace Tokenizer(fast)
    └── Model Registry
        ├── HuggingFace Model Hub
        ├── AWQ / GPTQ 量化模型
        └── Custom Model Loader

PagedAttention 原理:

PagedAttention 借鉴操作系统虚拟内存管理,将 KV Cache 划分为固定大小的物理块(Block),通过页表(Block Table)将逻辑位置映射到物理显存地址。

传统 KV Cache(连续分配)        PagedAttention KV Cache(分页分配)

Block Table: Seq → Block[0], Block[2], Block[5]

```mermaid
graph LR
    subgraph 传统KVCache["传统 KV Cache(连续分配)"]
        A1["Seq A"] --- A2["████"]
        B1["Seq B"] --- B2["▓▓▓▓"]
        C1["Free"] --- C2["    "]
        D1["Seq C"] --- D2["░░░░"]
        E1["Waste"] --- E2["    "]
    end

    subgraph PagedAttention["PagedAttention KV Cache(分页分配)"]
        P0["Block 0\nKV A"] --- P1["Block 1\nFree"] --- P2["Block 2\nKV A"] --- P3["Block 3\nFree"]
    end

**关键数据结构:**

```python
# 页表结构(概念)
class BlockTable:
    block_size: int = 16          # 每个 Block 管理的 token 数
    blocks: List[KVCacheBlock]    # 物理 Block 池
    block_table: Dict[int, List[int]]  # seq_id → physical_block_ids

# PagedAttention Kernel
# 通过 block_table 索引访问非连续 KV Cache
# 每个 attention head 独立计算

核心技术指标:

特性传统 KV CachePagedAttention
内存分配连续分配,预分配最大值按需分页分配
内存浪费内部碎片严重(25%-50%)仅最后一个 Block 有碎片(<4%)
内存共享不支持支持 Block 级共享(Prefix Cache)
Paralle Sampling每条序列独立分配全部 KV Cache共享 Prompt 部分 KV Cache
显存利用率~60%~96%
2 PagedAttention 与传统 KV Cache 管理相比有哪些优势?

答案:

PagedAttention 在内存利用率、共享能力和调度灵活性三个维度对传统 KV Cache 管理形成根本性改进。

内存使用对比:

维度传统 KV CachePagedAttention
分配方式预分配 max_model_len 连续空间按需分配离散 Block
碎片内部碎片严重仅最后一个 Block 产生碎片
利用率30%-60%90%-98%
Batch Size 限制受显存碎片限制受 Block 总数限制,显著更大
可变长度序列需要统一长度导致浪费物理分离,无浪费

共享能力对比:

graph LR
    subgraph 传统KVCache["传统 KV Cache(无共享)"]
        R1["Request 1:\nThe cat sat on the mat → 完整 KV Cache"]
        R2["Request 2:\nThe cat sat on the sofa → 完整 KV Cache"]
    end

    subgraph PagedAttention["PagedAttention(Block 级共享)"]
        Shared["共享 5 个 Block\nBlock The\nBlock cat\nBlock sat\nBlock on\nBlock the"]
        Shared --> R1B["Block mat"]
        Shared --> R2B["Block sofa"]
    end

调度灵活性对比:

特性传统 KV CachePagedAttention
Preemption 开销完整取消并重算Block Swap 到 CPU / Recomputation
Dynamic Batching受限于已分配内存布局独立 Block 分配,灵活调度
Memory Defragmentation需要 GC / 重新分配块级回收,天然无碎片
Cross-Request 共享不支持Prefix Cache 自动共享

Block 大小选择:

Block Size优势劣势
16碎片率低,共享粒度细页表更大,kernel launch 开销增加
32碎片率和开销平衡默认配置
64Kernel 效率高碎片率略增
128Kernel launch 次数少共享粒度粗,碎片率高
3 vLLM 的 Continuous Batching 如何工作?

答案:

Continuous Batching(连续批处理)在每步迭代中动态调整批处理中的请求集合,新请求可随时加入,完成的请求立即退出,消除传统 Static Batching 的等待时间。

Static Batching vs Continuous Batching:

Static Batching:
时间 ──────────────────────────────────────→
Batch 1: [Req A ████████████]
Batch 2: [Req B ████████████████████████]
Batch 3: [Req C ██████]

Req B 短序列在 Batch 2 中等待 A 完成 → 资源浪费

Continuous Batching:
时间 ──────────────────────────────────────→
Step 1: [Req A] [Req B] [Req C]
Step 2: [Req A] [Req B] [Req C]
Step 3: [Req A] [Req B]        ← Req C 完成,退出
Step 4: [Req A] [Req D] [Req E] ← 新请求即时加入
Step 5: [Req A] [Req D] [Req E]
Step 6: [Req D] [Req E]         ← Req A 完成
...

调度流程:

graph TD
    A["1. 请求到达"] --> B["2. 请求排队 Wait Queue"]
    B --> C["3. Scheduler 检查"]
    C --> C1["GPU 显存 Block 是否可用"]
    C --> C2["Token 预算是否允许<br/>max_num_batched_tokens"]
    C1 & C2 --> D{"资源可用?"}
    D -->|"可用"| E["4. 分配 Block"]
    E --> F["5. 加入 Running Batch"]
    D -->|"不可用"| G["Preemption 策略"]
    G --> G1["Swap out<br/>交换到 CPU"]
    G --> G2["Recomputation<br/>放弃 KV Cache 重新计算"]
    G1 & G2 --> H["6. 每步迭代"]
    H --> H1["所有 Running 请求执行<br/>一次 forward pass"]
    H --> H2["检查 EOS / Stop Token"]
    H --> H3["完成请求从 batch 移除"]
    H --> H4["释放 Block 回空闲池"]
    H1 & H2 & H3 & H4 --> I["7. 循环至步骤 2"]

核心参数:

参数含义默认值
max_num_seqs单次推理最大并发序列数256
max_num_batched_tokens单次推理最大 Token 数可选
max_model_len单序列最大长度模型配置
gpu_memory_utilizationGPU 显存使用比例0.90
max_num_prefills每步最多新加入的 Prefill 请求数
4 vLLM 的推理调度中 Preemption / Swapping / Recomputation 如何实现?

答案:

当 GPU 显存不足时,vLLM 通过 Preemption 机制释放资源,支持交换到 CPU(Swapping)和放弃 KV Cache 重新计算(Recomputation)两种策略。

Preemption 决策流程:

graph TD
    Start["新请求到达,需要分配 Block"] --> Check["显存 Block 池有可用 Block?"]
    Check -->|是| Direct["直接分配"]
    Check -->|否| Preempt["触发 Preemption"]
    Preempt --> Victim["选择 victim 序列\n1. 最晚到达的序列(FIFO 逆序)\n2. 最长序列(释放更多 Block)\n3. 优先级最低"]
    Victim --> Swapping["Swapping\nKV Cache 交换到 CPU 内存"]
    Victim --> Recomputation["Recomputation\n放弃 KV Cache 重新计算"]

Swapping(KV Cache 交换):

graph LR
    subgraph GPU["GPU 显存"]
        VKC["Victim KV Cache\nBlock 0\nBlock 3\nBlock 7"]
    end
    subgraph CPU["CPU 内存"]
        SB["Swapped Blocks\nBlock 0 copy\nBlock 3 copy\nBlock 7 copy"]
    end
    VKC -- "D2H 拷贝" --> SB

Recomputation(重计算):

graph TD
    A["Victim 序列的 KV Cache<br/>全部释放"] --> B["新请求获得 Block 资源<br/>开始推理"]
    B --> C["Victim 序列恢复时"]
    C --> C1["完整重新执行 Prefill 阶段"]
    C --> C2["从 Checkpoint<br/>已生成 Token 重新 prefilling"]
    C --> C3["恢复原始 KV Cache Block"]
    C1 & C2 & C3 --> D["适用:Block 数较少<br/>重计算开销 小于 交换开销<br/>代价:额外计算开销"]

配置参数:

# 优先级:swap > recompute
--preemption-mode swap      # 仅交换
--preemption-mode recompute # 仅重计算
# 混合策略:swap 优先,swap 空间不足时用 recompute
策略显存需求计算开销延迟影响适用场景
Swapping低(依赖 CPU 内存)低(仅拷贝)恢复延迟取决于 PCIe 带宽长序列,batch 大
Recomputation零额外显存高(重算)恢复需完整 Prefill短序列,batch 小
5 vLLM 的 Prefix Caching 原理是什么?

答案:

Prefix Caching(前缀缓存)基于 PagedAttention 的 Block 级共享能力,自动检测并复用不同请求中相同的 Prompt 前缀对应的 KV Cache Block,避免重复计算。

工作机制:

Request A: [System Prompt][User Question A]
Request B: [System Prompt][User Question B]
Request C: [System Prompt][User Question C]

共享:3 个请求共享 System Prompt 对应的 KV Cache Block

Prefix Caching 流程:
1. 对新请求计算 Prefix 的 Hash
2. 在 Hash 表中查找已有 Block
   ├── 命中 → 引用已有 Block(引用计数 +1)
   └── 未命中 → 新分配 Block,计算 KV Cache,写入 Hash 表
3. 后续新 Token 继续新分配 Block

Hash 计算与查找:

# 概念示例
class PrefixCache:
    def __init__(self):
        # hash(prefix_tokens) → [block_id, ...]
        self.cache: Dict[int, List[int]] = {}
        self.block_manager: BlockManager
    
    def get_or_compute(self, tokens: List[int]) -> List[int]:
        cached_blocks = []
        for i in range(0, len(tokens), block_size):
            block_tokens = tokens[i:i + block_size]
            block_hash = hash(tuple(block_tokens))
            if block_hash in self.cache:
                cached_blocks.append(self.cache[block_hash])
            else:
                # 计算并缓存
                break  # 前缀匹配中断,后续需重新计算
        return cached_blocks

Prefix Caching 应用场景:

场景缓存命中率加速比
Chat 多轮对话(共享 System Prompt)80%-95%1.5x-3x(Prefill 阶段)
Few-Shot Prompting(共享 Few-Shot 示例)70%-90%2x-5x
RAG 检索增强(共享检索上下文)60%-85%1.5x-3x
Batch API 同 Prompt 多 Completion~100%5x-10x

启用方式:

# 启动时启用 Prefix Caching
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3-8B-Instruct \
    --enable-prefix-caching
6 vLLM 的 Tensor Parallelism 如何实现多 GPU 推理?

答案:

Tensor Parallelism(张量并行)将模型的权重矩阵按列或行切分到多个 GPU,每个 GPU 计算部分结果后通过 All-Reduce 或 All-Gather 通信合并。

Tensor Parallel 切分方式:

原始 FFN 层(单 GPU):

Input [B, H]
    ├── W_up [H, 4H]    → [B, 4H]
    │   ↓ SiLU
    │   Gate [H, 4H]    → [B, 4H]
    │   ↓
    │   ⊙ (element-wise)
    │   ↓
    └── W_down [4H, H]  → [B, H]

Tensor Parallel(2 GPU):

GPU 0:                              GPU 1:
W_up_0 [H, 2H]                      W_up_1 [H, 2H]
    ↓                                    ↓
Gate_0 [H, 2H]                      Gate_1 [H, 2H]
    ↓                                    ↓
W_down_0 [2H, H]                    W_down_1 [2H, H]
    ↓                                    ↓
Y_0 [B, H]                          Y_1 [B, H]
    └──────────── All-Reduce ────────────┘
                   Y = Y_0 + Y_1

Attention 头切分:

原始 Attention(32 heads):
Q, K, V: [B, 32, seq_len, head_dim]

Tensor Parallel(4 GPU):
GPU 0: heads 0-7   → Q, K, V
GPU 1: heads 8-15  → Q, K, V
GPU 2: heads 16-23 → Q, K, V
GPU 3: heads 24-31 → Q, K, V

每 GPU 独立计算 attention → All-Reduce 合并

配置方式:

# 双 GPU Tensor Parallel
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3-70B-Instruct \
    --tensor-parallel-size 4 \
    --gpu-memory-utilization 0.90

# 指定 GPU
CUDA_VISIBLE_DEVICES=0,1,2,3 python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3-70B-Instruct \
    --tensor-parallel-size 4

通信开销分析:

并行规模All-Reduce 次数通信量效率
TP=2 (单机)每层 2 次NVLink 600 GB/s~95%
TP=4 (单机)每层 2 次NVLink 600 GB/s~90%
TP=8 (单机)每层 2 次NVLink 600 GB/s~80%
TP=8 (跨机)每层 2 次网络 100-200 Gbps~40-60%
TP=16 (跨机)每层 2 次网络 100-200 Gbps~25-40%
7 vLLM 的 Pipeline Parallelism 如何实现?

答案:

Pipeline Parallelism(流水线并行)将模型的 Transformer 层按序切分到多个 GPU,形成计算流水线,在每个 GPU 完成本层计算后将中间结果传递至下一 GPU。

Pipeline 切分策略:

原始模型(32 层):
Layer 0 → Layer 1 → ... → Layer 31

Pipeline Parallel(4 GPU):
GPU 0: Layer 0-7    ──→  GPU 1: Layer 8-15   ──→  GPU 2: Layer 16-23  ──→  GPU 3: Layer 24-31
      ↑ 接收 Input         ↑ 接收 GPU 0 hidden      ↑ 接收 GPU 1 hidden      ↑ 接收 GPU 2 hidden
      ↓ 发送 hidden        ↓ 发送 hidden            ↓ 发送 hidden            ↓ 发送 hidden → Output

Micro-Batch 调度:

Pipeline 时间线(4 GPU, 4 micro-batches):

时间 ────────────────────────────────────→

GPU 0: [F0_B0][F0_B1][F0_B2][F0_B3] [...]
GPU 1:    [B0_B0][F1_B0][F1_B1][F1_B2][F1_B3][...]
GPU 2:       [B0_B1][B0_B0][F2_B0][F2_B1][F2_B2][F2_B3]
GPU 3:          [B0_B2][B0_B1][B0_B0][F3_B0][F3_B1][F3_B2]

F = Forward, B = Backward, N = GPU index, Bn = Batch n

气泡(Bubble):流水线启动和排空期间 GPU 空闲时间
Bubble Ratio ≈ (PP_size - 1) / num_micro_batches

Tensor Parallel + Pipeline Parallel 组合:

# 8 GPU:TP=2 × PP=4
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3-405B-Instruct \
    --tensor-parallel-size 2 \
    --pipeline-parallel-size 4

组合拓扑:

GPU 0 ←─→ GPU 1    (TP Group 0, Layer 0-7)
  ↓ NVLink            ↓ NVLink
GPU 2 ←─→ GPU 3    (TP Group 1, Layer 8-15)
  ↓ NVLink            ↓ NVLink
GPU 4 ←─→ GPU 5    (TP Group 2, Layer 16-23)
  ↓ NVLink            ↓ NVLink
GPU 6 ←─→ GPU 7    (TP Group 3, Layer 24-31)

TP 组内:NVLink 高速通信
PP 组间:P2P send/recv
并行策略最优场景限制
纯 TP单机 ≤ 8 GPU跨机通信开销大
纯 PP模型层数多,GPU 间带宽低Bubble 开销
TP + PP大规模集群(>8 GPU)配置调试复杂度高
8 vLLM 支持哪些量化推理方案?

答案:

vLLM 支持 AWQ、GPTQ、FP8、INT8、INT4 等多种量化推理方案,通过降低权重和/或激活值的精度减少显存占用和内存带宽需求。

量化方案对比:

量化方案精度格式显存节省精度损失硬件要求推理速度
FP16 (baseline)16-bitNVIDIA GPU基准
AWQINT4 weight + FP16 act~4x weight<0.5%NVIDIA GPU (SM ≥ 7.5)1.3x-1.5x
GPTQINT4/INT8 weight~4x/2x<1%NVIDIA GPU1.2x-1.4x
FP8 (W8A8)FP8 weight + FP8 act~2x<0.1%H100/H200/B2001.5x-2x
INT8INT8 weight + FP16 act~2x<1%NVIDIA GPU1.2x-1.4x
bitsandbytes INT4INT4 weight + FP16 act~4x<2%NVIDIA GPU1.1x-1.3x

AWQ(Activation-aware Weight Quantization):

AWQ 原理:
1. 分析各 Channel 的 Activation 分布
2. 根据 Activation 重要性对权重加缩放因子
3. 对高 Activation Channel 用更高精度
4. 量化前进行 Channel-wise Scaling

量化流程:
W_FP16 ──→ 分析 Activation 分布 ──→ 计算 Saliency ──→ Scaling ──→ W_INT4

各方案启动命令:

# AWQ 量化模型
python -m vllm.entrypoints.openai.api_server \
    --model TheBloke/Llama-3-8B-Instruct-AWQ \
    --quantization awq \
    --dtype auto

# GPTQ 量化模型
python -m vllm.entrypoints.openai.api_server \
    --model TheBloke/Llama-3-8B-Instruct-GPTQ \
    --quantization gptq \
    --dtype auto

# FP8 量化(H100/H200)
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3-70B-Instruct \
    --quantization fp8 \
    --dtype auto

# INT8 量化
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3-8B-Instruct-INT8 \
    --quantization int8 \
    --dtype auto

# bitsandbytes INT4
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3-8B-Instruct \
    --load-format bitsandbytes \
    --quantization bitsandbytes

FP8 量化两种模式:

模式说明精度速度
W8A8 (FP8 KV Cache)Weight FP8 + Activation FP8最高最快
W8A16Weight FP8 + Activation FP16较高较快
9 vLLM 如何提供 OpenAI Compatible API 服务?

答案:

vLLM 内置与 OpenAI API 完全兼容的 HTTP 服务端,支持 /v1/completions/v1/chat/completions/v1/models 等端点,客户端可使用 openai Python SDK 直接调用。

启动服务:

python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct \
    --served-model-name qwen2.5-7b \
    --host 0.0.0.0 \
    --port 8000 \
    --api-key sk-vllm-secret \
    --max-model-len 8192 \
    --gpu-memory-utilization 0.90 \
    --tensor-parallel-size 1

支持的 API 端点:

端点功能OpenAI 兼容
/v1/models列出可用模型完全兼容
/v1/completions文本补全完全兼容
/v1/chat/completions对话补全完全兼容
/v1/embeddings文本嵌入完全兼容
/v1/tokenizeToken 化(vLLM 扩展)扩展接口
/v1/detokenize反 Token 化(vLLM 扩展)扩展接口
/health健康检查
/metricsPrometheus 指标

客户端调用示例:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="sk-vllm-secret",
)

# Chat Completions
response = client.chat.completions.create(
    model="qwen2.5-7b",
    messages=[
        {"role": "system", "content": "你是一个运维专家"},
        {"role": "user", "content": "如何排查 GPU OOM?"},
    ],
    temperature=0.7,
    max_tokens=1024,
    stream=True,
)

for chunk in response:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")

# /v1/models
models = client.models.list()
for m in models:
    print(m.id)

多模型服务:

# 单进程仅支持单个模型,多模型需启动多个实例
# 搭配 Nginx / Envoy 做路由

upstream vllm-qwen {
    server localhost:8001;
}
upstream vllm-llama {
    server localhost:8002;
}

# LiteLLM Proxy 统一路由多个 vLLM 实例
# litellm --model qwen2.5-7b --api_base http://localhost:8001
# litellm --model llama-3-8b --api_base http://localhost:8002
10 vLLM 如何在 Kubernetes 上部署?

答案:

vLLM 在 Kubernetes 上以 Deployment 形式部署 GPU 推理服务,配合 Service、Ingress、HPA 实现生产级推理服务。

基础 Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-qwen25-7b
  labels:
    app: vllm
    model: qwen2.5-7b
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vllm
      model: qwen2.5-7b
  template:
    metadata:
      labels:
        app: vllm
        model: qwen2.5-7b
    spec:
      nodeSelector:
        nvidia.com/gpu.product: NVIDIA-A100-SXM4-80GB
      containers:
        - name: vllm
          image: vllm/vllm-openai:v0.7.2
          command:
            - python3
            - -m
            - vllm.entrypoints.openai.api_server
          args:
            - --model
            - Qwen/Qwen2.5-7B-Instruct
            - --served-model-name
            - qwen2.5-7b
            - --host
            - "0.0.0.0"
            - --port
            - "8000"
            - --max-model-len
            - "8192"
            - --gpu-memory-utilization
            - "0.90"
            - --tensor-parallel-size
            - "1"
            - --dtype
            - auto
          ports:
            - containerPort: 8000
              name: http
          env:
            - name: CUDA_VISIBLE_DEVICES
              value: "0"
            - name: VLLM_API_KEY
              valueFrom:
                secretKeyRef:
                  name: vllm-api-key
                  key: api-key
            - name: HF_HOME
              value: /model-cache
          resources:
            limits:
              nvidia.com/gpu: 1
              memory: 64Gi
            requests:
              nvidia.com/gpu: 1
              memory: 32Gi
          volumeMounts:
            - name: model-cache
              mountPath: /model-cache
          readinessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 60
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 120
            periodSeconds: 30
      volumes:
        - name: model-cache
          persistentVolumeClaim:
            claimName: model-cache-pvc
apiVersion: v1
kind: Service
metadata:
  name: vllm-qwen25-7b
spec:
  selector:
    app: vllm
    model: qwen2.5-7b
  ports:
    - port: 8000
      targetPort: 8000
  type: ClusterIP
apiVersion: v1
kind: Secret
metadata:
  name: vllm-api-key
type: Opaque
stringData:
  api-key: "sk-production-secret-key"

模型初始化方案:

方案方式优点缺点
InitContainer 下载InitContainer 拉取模型后再启动主容器启动确定,可重试启动慢(首次)
PVC 预持久化提前通过 Job 或手动将模型拷贝到 PVC启动快,多副本共享存储成本高
挂载 NFS / S3通过 FUSE CSI 挂载远程存储弹性扩展,存储与计算分离首次加载延迟高
EmptyDir + Init临时下载到节点本地无需持久化存储每次重建重新下载

生产部署拓扑:

graph TD
    Internet["Internet"] --> Ingress["Ingress / LoadBalancer"]
    Ingress --> APIGateway["API Gateway (nginx / envoy)"]
    APIGateway --> V1["vllm-1\n(qwen2.5-7b)\nGPU: A100"]
    APIGateway --> V2["vllm-2\n(qwen2.5-7b)\nGPU: A100"]
    APIGateway --> V3["vllm-3\n(qwen2.5-7b)\nGPU: A100"]
    V1 --> Monitor["Prometheus + Grafana\n监控 TTFT / TPOT / Throughput"]
    V2 --> Monitor
    V3 --> Monitor
11 vLLM 如何管理 GPU 显存?

答案:

vLLM 通过 gpu_memory_utilization 参数控制 GPU 显存使用比例,将显存划分为模型权重区、KV Cache Block 池和临时工作区三部分。

GPU 显存分配模型:

GPU 显存总容量(如 A100-80GB = 80 GiB)
    ├── CUDA Context / Driver Overhead(~0.5-1 GiB)
    ├── 模型权重区(不可压缩)
    │   ├── FP16 权重:参数量 × 2 bytes
    │   ├── 量化权重:参数量 × (quant bits / 8) bytes
    │   └── 示例:Llama-3-70B FP16 → ~140 GiB(需要 TP)
    ├── KV Cache Block 池(可配置)
    │   ├── Block 数 = (总显存 - 模型权重) × gpu_memory_utilization / block_size_bytes
    │   ├── 每个 Block 大小 = num_layers × num_kv_heads × head_dim × 2(K+V) × block_size × 2 bytes
    │   └── Block 不足时触发 Preemption
    └── 临时工作区(CUDA Kernels,activation buffer)
        ├── 中间 Activation 值(每层计算)
        └── NCCL 通信 Buffer(TP/PP 场景)

Block 数量计算示例:

Llama-3-8B, A100-40GB, max_model_len=8192, block_size=16

1. 权重显存:
   8B params × 2 bytes = 16 GiB

2. 可用显存:
   40 GiB - 16 GiB - 1 GiB (overhead) = 23 GiB

3. 有效 KV Cache 池(gpu_memory_utilization=0.90):
   23 GiB × 0.90 = 20.7 GiB

4. 每 Block 大小:
   layers=32, num_kv_heads=8, head_dim=128
   每 Block = 32 × 8 × 128 × 2 × 16 × 2 bytes = 2,097,152 bytes ≈ 2 MiB

5. 最大 Block 数:
   20.7 GiB / 2 MiB ≈ 10,598 Blocks

6. 最大并发序列数(每序列平均 512 tokens = 32 Blocks):
   10,598 / 32 ≈ 331 条序列(含 Prefill + Decode)

gpu_memory_utilization 调优:

可用显存风险推荐场景
0.90 (默认)基线的 90%通用场景
0.95基线的 95%中等(CUDA Graph 可能 OOM)追求最大 Batch Size
0.85基线的 85%最低保守配置,CUDA Graph 开启
0.75基线的 75%最低需要额外 CUDA Context 场景
12 vLLM 的 Chunked Prefill 如何工作?

答案:

Chunked Prefill(分块预填充)将长 Prompt 的 Prefill 阶段拆分为多个小块(Chunk),与 Decode 阶段交替执行,避免单个长 Prefill 阻塞整个 Batch 的响应延迟。

传统 Prefill vs Chunked Prefill:

传统 Prefill(长 Prompt 阻塞其他请求):

GPU ──┬──────────────────────────────────────┬──────────┬──────────┬─────
      │  Prefill Req A (long, 4096 tokens)  │ Decode A │ Decode B │ ...
      └──────────────────────────────────────┴──────────┴──────────┴─────
      其他请求在此期间全部排队等待 ← 首 Token 延迟高

Chunked Prefill(交替执行):

GPU ──┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬─────
      │  C1  │  D1  │  C2  │  D2  │  D3  │  C3  │  D4  │  D5  │ ...
      └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴─────
      C = Prefill Chunk(计算 Prompt KV Cache)
      D = Decode Step(生成下一个 Token)
      
      Prefill 分散到多步执行,Decode 请求不被阻塞

Chunked Prefill 调度逻辑:

每步调度决策:

1. 计算当前 Batch 的可用 Token 预算:
   token_budget = max_num_batched_tokens - current_batch_tokens

2. 如果有待 Prefill 请求:
   ┌── 拆分 Prefill 为 Chunk
   │   chunk_size = min(token_budget, (max_num_batched_tokens / num_prefill_requests))
   │   prefill_chunk = prompt[offset : offset + chunk_size]
   └── 将 Chunk 加入当前 Step

3. 剩余 Token 预算分配给 Decode 请求

4. 记录 Prefill 进度(offset),下一步继续

5. Prefill 完成后,请求转为 Decode 状态

Chunked Prefill 关键参数:

python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct \
    --enable-chunked-prefill \
    --max-num-batched-tokens 8192
参数含义推荐值
--enable-chunked-prefill启用 Chunked Prefill长 Prompt 场景建议开启
--max-num-batched-tokens每步最大 Token 数512-8192(依据显存)
Chunk Size(隐式)由调度器 Token 预算决定自动计算

TTFT 改善对比:

场景传统 Prefill TTFTChunked Prefill TTFT改善
轻负载(<5 req)500ms200ms2.5x
中等负载(5-20 req)2000ms400ms5x
高负载(>50 req)8000ms600ms13x
混合长/短 Prompt大波动平稳延迟抖动降低 80%
13 vLLM 的 Speculative Decoding 如何实现?

答案:

Speculative Decoding(推测解码)使用小型 Draft Model 快速生成候选 Token 序列,由 Target Model 并行验证并接受,实现每步生成多个 Token 而保持目标模型质量不变。

工作流程:

1. Draft Model 快速推测 K 个 Token(如 K=5):
   Draft Model(小模型,~100M)→ [T1, T2, T3, T4, T5]

2. Target Model 并行验证:
   Target Model(大模型,~70B)
   一次 Forward Pass 计算 [T1, T2, T3, T4, T5] 的概率分布

3. Rejection Sampling 接受/拒绝:
   对每个 Ti:
   ┌── 如果 P_target(Ti) ≥ P_draft(Ti) → 接受 Ti
   └── 如果 P_target(Ti) < P_draft(Ti) → 以概率 P_target/P_draft 接受
       否则拒绝并从 Ti 位置重新采样

4. 更新 KV Cache,继续下一轮推测

三种 Speculative Decoding 方法(vLLM 支持):

方法Draft 来源优点缺点
Draft Model独立小模型灵活,可替换额外显存占用
EAGLE额外预测头无需独立模型需要特定格式模型
NGram (Prompt Lookup)输入 Prompt 的 n-gram 匹配零额外显存仅对重复文本有效
Medusa多个预测头Draft 质量高需要特定模型格式

配置示例:

# Draft Model 方式
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3-70B-Instruct \
    --speculative-model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
    --num-speculative-tokens 5 \
    --speculative-draft-tensor-parallel-size 1

加速效果:

场景加速比说明
代码生成(高确定性)2x-3xDraft 命中率高
通用对话1.3x-1.7x命中率中等
翻译1.5x-2.5x输出确定性较高
创意写作(高随机性)1.1x-1.3xDraft 命中率低
14 vLLM 如何支持 Multi-LoRA Serving?

答案:

vLLM 支持同时加载多个 LoRA 适配器,不同请求可指定不同 LoRA 适配器,适配器的权重与 Base Model 共享 KV Cache 和显存,实现高效多任务推理。

LoRA Serving 架构:

Base Model(共享,不可变)
    ├── Attention Layer
    │   ├── Q_proj: W_base
    │   ├── K_proj: W_base
    │   ├── V_proj: W_base
    │   └── O_proj: W_base
    └── FFN Layer
        ├── Gate: W_base
        ├── Up: W_base
        └── Down: W_base

LoRA Adapter 1: Q_adapt1, V_adapt1       (任务 A)
LoRA Adapter 2: Q_adapt2, V_adapt2       (任务 B)
LoRA Adapter 3: Gate_adapt3, Down_adapt3 (任务 C)

每请求计算:output = W_base(x) + LoRA_A(LoRA_B(x)) × scaling

启动配置:

python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3-8B-Instruct \
    --enable-lora \
    --lora-modules \
        sql-lora=/path/to/sql-lora-adapter \
        code-lora=/path/to/code-lora-adapter \
        medical-lora=/path/to/medical-lora-adapter \
    --max-lora-rank 64 \
    --max-loras 32 \
    --max-cpu-loras 64

请求指定 LoRA 适配器:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="sk-vllm-secret",
)

# 使用 code-lora 适配器生成代码
response = client.chat.completions.create(
    model="code-lora",
    messages=[{"role": "user", "content": "写一个快速排序的 Python 实现"}],
    max_tokens=512,
)

LoRA 配置参数:

参数含义推荐值
--enable-lora启用 LoRA 支持必需
--max-lora-rank最大 LoRA rank16/32/64(取决于适配器)
--max-lorasGPU 上同时驻留的 LoRA 数8-32
--max-cpu-lorasCPU 内存中缓存的 LoRA 数64-256
--fully-sharded-lorasLoRA 权重跨 TP GPU 分片>1 TP 时推荐
--max-lora-served-per-sequence单请求可指定的 LoRA 数量1(默认)

Multi-LoRA 性能指标:

LoRA 数量额外显存推理速度影响
1~50-200 MiB (rank=16)几乎无影响
8~400 MiB-1.6 GiB<2% 开销
32~1.6-6.4 GiB<5% 开销
64~3.2-12.8 GiB<10% 开销(LRU 换入换出)
15 vLLM 支持哪些多模态模型?

答案:

vLLM 原生支持多种视觉-语言多模态模型,包括 LLaVA、Qwen-VL、InternVL、Phi-3-Vision 等,视觉编码器与文本模型共享推理引擎。

支持的多模态模型列表:

模型系列架构特点Vision Encoder分辨率模型示例
LLaVA-1.5CLIP + MLP ProjectorViT-L/14 (CLIP)336×336llava-v1.5-7b, llava-v1.5-13b
LLaVA-NeXTDynamic High ResolutionViT-L/14最高 672×672llava-v1.6-34b
Qwen-VLQwen ViT + ResamplerQwen-ViT (448×448)固定Qwen-VL-Chat
Qwen2-VLNaive Dynamic ResolutionQwen2-ViT动态Qwen2-VL-7B-Instruct
InternVL2Dynamic High ResolutionInternViT-6B动态InternVL2-8B
Phi-3-VisionCLIP 风格SigLIP-400M336×336Phi-3-vision-128k-instruct
PixtralPixtral-ViTPixtral-ViT动态Pixtral-12B
Fuyu无单独 Vision Encoder内嵌图像 Patch固定fuyu-8b

启动命令:

# LLaVA-1.5
python -m vllm.entrypoints.openai.api_server \
    --model llava-hf/llava-1.5-7b-hf \
    --max-model-len 4096 \
    --limit-mm-per-prompt image=5

# Qwen2-VL
python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2-VL-7B-Instruct \
    --max-model-len 8192 \
    --limit-mm-per-prompt image=10 \
    --mm-processor-kwargs '{"max_pixels": 1003520}'

多模态请求示例:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="sk-vllm-secret",
)

response = client.chat.completions.create(
    model="Qwen2-VL-7B-Instruct",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "image_url", "image_url": {"url": "https://example.com/image.png"}},
                {"type": "text", "text": "这张图片描述了什么?"},
            ],
        }
    ],
    max_tokens=512,
)

多模态推理显存估算:

模型纯文本显存+1 张图片显存+5 张图片显存
LLaVA-1.5-7B~16 GiB~17 GiB~22 GiB
Qwen2-VL-7B~18 GiB~19 GiB~25 GiB
InternVL2-8B~20 GiB~22 GiB~30 GiB
16 vLLM 的请求队列与调度策略如何管理?

答案:

vLLM 调度器维护 Wait Queue(排队队列)和 Running Queue(运行队列),通过优先级调度、FCFS、抢占等策略管理请求生命周期。

请求生命周期:

graph TD
    REQ["请求到达"] --> WAIT["Wait Queue"]
    WAIT --> EVAL["Scheduler 评估"]
    EVAL --> C1["Token 预算是否允许"]
    EVAL --> C2["Block 是否可用"]
    EVAL --> C3["是否达到 max_num_seqs"]
    EVAL --> C4["是否达到 max_lora_served"]
    C1 & C2 & C3 & C4 --> DECISION{"可调度?"}
    DECISION -->|"可调度"| ALLOC["分配 Block<br/>加入 Running"]
    DECISION -->|"不可调度"| RETRY["继续等待<br/>或触发 Preemption"]
    ALLOC --> GEN["生成 Token<br/>检查 EOS/Stop"]
    GEN --> DONE_DECISION{"完成?"}
    DONE_DECISION -->|"完成"| RELEASE["释放 Block<br/>返回 Response"]
    DONE_DECISION -->|"继续"| GEN

调度策略类型:

策略英文名行为默认
FCFSFirst-Come First-Served按到达顺序调度
Priority优先级调度高优先级请求优先分配资源
Preemptive抢占调度高优先级请求可抢占低优先级依赖 Preemption Mode

核心调度参数:

python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct \
    --max-num-seqs 256 \
    --max-num-batched-tokens 8192 \
    --max-num-partial-prefills 1 \
    --scheduler-delay-factor 0.0
参数含义默认值
--max-num-seqs单次推理最大并发序列数256
--max-num-batched-tokens单次推理最大 Token 数
--max-num-partial-prefillsChunked Prefill 每次最多处理的 Prefill 请求1
--scheduler-delay-factor延迟调度因子0.0
17 vLLM 的分布式推理(Ray / Multi-Node)如何部署?

答案:

vLLM 支持基于 Ray 的跨节点分布式推理,通过 Ray 集群实现多机多卡协同,适合超大模型(如 DeepSeek-V3 671B)的推理部署。

分布式架构:

Ray Cluster
    ├── Head Node(Driver Process)
    │   ├── Ray Head(GCS, Dashboard)
    │   └── OpenAI API Server
    ├── Worker Node 1(4×A100-80G)
    │   ├── Ray Worker 1 → vLLM Worker (TP=2, GPU 0-1)
    │   ├── Ray Worker 2 → vLLM Worker (TP=2, GPU 2-3)
    │   └── Ray Worker 3 → vLLM Worker (PP stage 1)
    └── Worker Node 2(4×A100-80G)
        ├── Ray Worker 4 → vLLM Worker (TP=2, GPU 0-1)
        ├── Ray Worker 5 → vLLM Worker (TP=2, GPU 2-3)
        └── Ray Worker 6 → vLLM Worker (PP stage 2)

Ray 分布式启动:

# 1. 启动 Ray 集群
ray start --head --port=6379
ray start --address='<head-ip>:6379' --num-gpus=4

# 2. 多节点推理
python -m vllm.entrypoints.openai.api_server \
    --model deepseek-ai/DeepSeek-V3 \
    --tensor-parallel-size 2 \
    --pipeline-parallel-size 4 \
    --distributed-executor-backend ray \
    --gpu-memory-utilization 0.90

分布式通信拓扑:

节点间通信:
├── NCCL over RDMA(InfiniBand / RoCEv2)
│   延迟 ~1-3 μs,带宽 200-400 GB/s
├── NCCL over TCP(以太网)
│   延迟 ~20-50 μs,带宽 25-100 Gbps
└── GLOO(备份后端)

TP 组内通信模式:
├── All-Reduce(每层 2 次)
├── All-Gather(Attention 输出合并)
└── Reduce-Scatter(部分场景)

大规模部署资源配置参考:

模型参数量GPU 配置TPPP节点数
Llama-3-70B FP1670BA100-80G × 4411
Llama-3-405B FP8405BH100-80G × 8811
DeepSeek-V2236B (21B active)A100-80G × 8811
DeepSeek-V3671B (37B active)H100-80G × 8844
Qwen2.5-72B FP1672BA100-80G × 4411
18 vLLM 的性能基准测试如何评估?

答案:

vLLM 性能评估主要关注吞吐量(Throughput)、延迟(Latency)、首个 Token 生成时间(TTFT)和每 Token 生成间隔(TPOT)四个核心指标。

核心性能指标定义:

指标英文定义单位
TTFTTime to First Token从请求发送到收到第一个 Token 的时间ms / s
TPOTTime per Output Token首个 Token 后每个 Token 的平均生成时间ms / token
TBTTime between Tokens相邻 Token 之间的时间间隔ms
Throughput吞吐量单位时间生成的 Token 总数tokens/s
RPSRequests per Second单位时间处理的请求数req/s
ITLInter-Token Latency解码阶段每 Token 的延迟ms

性能基准测试命令:

# 安装 benchmark 工具
pip install vllm[benchmark]

# 离线基准测试(不需要启动 API Server)
python -m vllm.entrypoints.openai.run_batch \
    --model Qwen/Qwen2.5-7B-Instruct \
    --input-len 1024 \
    --output-len 512 \
    --num-prompts 100

# 在线服务性能测试
python benchmarks/benchmark_serving.py \
    --backend vllm \
    --model Qwen/Qwen2.5-7B-Instruct \
    --dataset-name sharegpt \
    --dataset-path ShareGPT_V3_unfiltered_cleaned_split.json \
    --num-prompts 1000 \
    --request-rate 4.0

典型性能数据(A100-80G, Llama-3-8B FP16, 单卡):

场景Input LenOutput LenThroughputTTFT (avg)TPOT
短对话1281284500 tok/s45ms22ms
中等对话10242563200 tok/s120ms31ms
长文档摘要40965121800 tok/s380ms55ms
批量离线推理51210245200 tok/s

vLLM benchmark 参数说明:

# benchmark_serving.py 关键参数
--request-rate        # 每秒发送请求数(控制 QPS)
--num-prompts         # 总请求数量
--burstiness          # 请求突发性系数
--seed                # 随机种子(可复现)
--result-filename     # 结果输出 JSON 文件
--percentile-metrics  # 分位数指标(如 "ttft_p99,tpot_p95")

性能对比:

框架Throughput (tok/s)TTFT P50TTFT P99
vLLM (Continuous Batching)320045ms120ms
HuggingFace TGI280050ms150ms
TensorRT-LLM450035ms90ms
SGlang340042ms110ms
19 vLLM 的日志与监控如何配置?

答案:

vLLM 通过内置的 Prometheus /metrics 端点暴露推理服务指标,支持通过 Grafana 可视化,并通过 Python logging 输出结构化运行日志。

Prometheus 核心指标:

指标名类型说明
vllm:num_requests_runningGauge当前正在处理的请求数
vllm:num_requests_waitingGauge排队等待的请求数
vllm:num_requests_swappedGauge被交换到 CPU 的请求数
vllm:gpu_cache_usage_percGaugeGPU KV Cache 使用率百分比
vllm:cpu_cache_usage_percGaugeCPU Swap Cache 使用率百分比
vllm:request_success_totalCounter成功完成的请求总数
vllm:request_prefill_time_secondsHistogramPrefill 阶段耗时分布
vllm:request_decode_time_secondsHistogramDecode 阶段耗时分布
vllm:time_to_first_token_secondsHistogramTTFT 分布
vllm:time_per_output_token_secondsHistogramTPOT 分布
vllm:request_prompt_tokensHistogram请求 Prompt Token 数分布
vllm:request_generation_tokensHistogram生成 Token 数分布
vllm:num_preemptions_totalCounterPreemption 总数
vllm:prefix_cache_hit_totalCounterPrefix Cache 命中数
vllm:prefix_cache_query_totalCounterPrefix Cache 查询总数

Prometheus 抓取配置:

# prometheus.yml
scrape_configs:
  - job_name: "vllm"
    scrape_interval: 15s
    static_configs:
      - targets:
          - "vllm-1:8000"
          - "vllm-2:8000"
        labels:
          cluster: "production"
          model: "qwen2.5-7b"

Grafana 监控面板关键查询:

# KV Cache 使用率
rate(vllm:gpu_cache_usage_perc[5m])

# TTFT P99
histogram_quantile(0.99, rate(vllm:time_to_first_token_seconds_bucket[5m]))

# TPOT P50
histogram_quantile(0.50, rate(vllm:time_per_output_token_seconds_bucket[5m]))

# 吞吐量(每秒 Token)
sum(rate(vllm:request_generation_tokens_sum[1m]))

# 排队请求数
vllm:num_requests_waiting

# Prefix Cache 命中率
sum(rate(vllm:prefix_cache_hit_total[5m]))
  /
sum(rate(vllm:prefix_cache_query_total[5m]))
* 100

日志配置:

# 环境变量控制日志级别
export VLLM_LOGGING_LEVEL=DEBUG  # DEBUG, INFO, WARNING, ERROR
export VLLM_TRACE_FUNCTION=1     # 启用函数调用追踪
20 vLLM 的安全控制机制有哪些?

答案:

vLLM 支持 API Key 鉴权、模型访问控制、请求速率限制和 TLS 加密等安全机制,满足生产环境的访问控制需求。

API Key 鉴权:

# 方式 1:命令行指定
python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct \
    --api-key sk-vllm-production-secret

# 方式 2:环境变量
export VLLM_API_KEY="sk-vllm-production-secret"
python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct

请求必须携带 API Key:

# 请求头 Authorization: Bearer sk-vllm-production-secret
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="sk-vllm-production-secret",
)

安全架构(推荐:Sidecar 代理模式):

graph TD
    A["Client"] --> B["TLS Termination<br/>nginx / envoy"]
    B --> B1["验证 API Key"]
    B --> B2["速率限制"]
    B --> B3["请求日志"]
    B1 & B2 & B3 --> C["vLLM Server<br/>不对外暴露<br/>仅内网可访问"]

安全配置清单:

安全层配置方式说明
API Key--api-key / VLLM_API_KEY服务端强制鉴权
TLS前置 Nginx/Envoy 终止 TLS加密传输
速率限制API Gateway / Nginx limit_req_zone防止过载
网络隔离Kubernetes NetworkPolicy / 防火墙规则vLLM 仅监听内网
模型访问控制多 vLLM 实例 + 不同 API Key按用户角色分配模型
请求日志Nginx Access Log + JSON 格式审计追溯
敏感信息过滤日志中不记录完整 Prompt数据隐私

Nginx 反向代理 + 安全配置示例:

upstream vllm_backend {
    server vllm-1:8000 max_fails=3 fail_timeout=30s;
    server vllm-2:8000 max_fails=3 fail_timeout=30s;
}

# 速率限制
limit_req_zone $binary_remote_addr zone=vllm_limit:10m rate=10r/s;

server {
    listen 443 ssl;
    ssl_certificate     /etc/ssl/certs/vllm.crt;
    ssl_certificate_key /etc/ssl/private/vllm.key;

    location /v1/ {
        limit_req zone=vllm_limit burst=20 nodelay;
        proxy_pass http://vllm_backend;
        proxy_set_header Host $host;
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;

        # 移除客户端 API Key,使用服务端固定 Key
        proxy_set_header Authorization "Bearer sk-vllm-internal";
    }
}
21 vLLM 支持哪些自定义采样参数?

答案:

vLLM 兼容 OpenAI API 采样参数,支持 Temperature、Top-P、Top-K、Repetition Penalty、Frequency Penalty、Presence Penalty 等完整采样控制。

核心采样参数:

参数类型范围默认值说明
temperaturefloat0.0-2.01.0控制随机性,0 为确定性输出
top_pfloat0.0-1.01.0核采样(Nucleus Sampling)阈值
top_kint-1 到 vocab_size-1(禁用)仅从 Top-K 个 Token 中采样
repetition_penaltyfloat≥1.01.0抑制重复 Token
frequency_penaltyfloat-2.0 到 2.00.0按频率惩罚已出现 Token
presence_penaltyfloat-2.0 到 2.00.0按存在惩罚已出现 Token
min_pfloat0.0-1.00.0最小概率阈值(Min-P Sampling)
stopstr/list停止词/字符串
max_tokensint1-max_model_len16最大生成 Token 数
seedint随机种子(确定性输出)

采样策略组合效果:

场景TemperatureTop-PTop-KRepetition Penalty效果
事实性问答0.0-0.31.01.0确定性高,准确
代码生成0.2-0.50.9501.05平衡准确和多样
创意写作1.0-1.50.9-0.9540-801.0-1.1多样性高
翻译0.0-0.31.01.0确定性翻译
长文本续写0.7-1.00.9501.05-1.15连贯多样,避免重复

API 调用示例:

response = client.chat.completions.create(
    model="qwen2.5-7b",
    messages=[{"role": "user", "content": "写一首关于秋天的诗"}],
    temperature=0.9,
    top_p=0.95,
    top_k=50,
    repetition_penalty=1.1,
    frequency_penalty=0.3,
    presence_penalty=0.2,
    max_tokens=256,
    seed=42,
    stop=["</s>", "###"],
)

Repetition Penalty 机制:

Repetition Penalty 工作方式:
对于已生成的 Token t,其 logits 除以 repetition_penalty

logits_penalized[t] = logits[t] / repetition_penalty  (repetition_penalty > 1.0)

效果:
- repetition_penalty = 1.0: 无惩罚
- repetition_penalty = 1.1: 轻微惩罚
- repetition_penalty = 1.2: 中度惩罚(常见推荐值)
- repetition_penalty = 1.5: 强力惩罚(可能影响流畅度)

Frequency Penalty 工作方式:
logits[t] = logits[t] - frequency_penalty × count(t)

Presence Penalty 工作方式:
logits[t] = logits[t] - presence_penalty × (1 if count(t) > 0 else 0)
22 vLLM 的 Streaming 输出与 SSE 如何工作?

答案:

vLLM 通过 Server-Sent Events(SSE)协议实现 Streaming 输出,每个生成的 Token 以增量(Delta)形式推送给客户端,无需等待完整回复。

SSE 数据流格式:

Client                           vLLM Server
  │                                   │
  │──→ POST /v1/chat/completions      │
  │    {"stream": true, ...}           │
  │                                    │
  │←── data: {"choices":[{"delta":     │
  │    {"role":"assistant"},"index":0}]│}
  │                                    │
  │←── data: {"choices":[{"delta":     │
  │    {"content":"你"},"index":0}]}   │
  │                                    │
  │←── data: {"choices":[{"delta":     │
  │    {"content":"好"},"index":0}]}   │
  │                                    │
  │←── ...                             │
  │                                    │
  │←── data: {"choices":[{"delta":     │
  │    {"content":"。"},"index":0},    │
  │    "finish_reason":"stop"}]}       │
  │                                    │
  │←── data: [DONE]                    │

客户端 SSE 流式处理:

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="sk-vllm-secret")

stream = client.chat.completions.create(
    model="qwen2.5-7b",
    messages=[{"role": "user", "content": "解释 Kubernetes Operator 模式"}],
    stream=True,
    stream_options={"include_usage": True},  # 可以获取 usage 统计
)

full_response = ""
for chunk in stream:
    if chunk.choices:
        delta = chunk.choices[0].delta
        if delta.content:
            print(delta.content, end="", flush=True)
            full_response += delta.content
    if hasattr(chunk, "usage") and chunk.usage:
        print(f"\n--- Usage: {chunk.usage}")

# 使用 httpx / aiohttp 直接处理 SSE
# 流解析时需要考虑 network chunk 与 SSE event 不是一一映射

客户端 SSE 处理注意事项:

  1. 每个 data: 行不一定对应一个完整 Token(可能多个 Token 合并在一个 SSE 事件中)。
  2. data: [DONE] 标记流结束。
  3. finish_reason 仅在最后一个有效 data: 行中出现。
  4. stream_options={"include_usage": true} 可在最后一条消息中获取 Token 用量。
  5. 网络中断时需实现重试逻辑(检查已生成的 Token 数,发送带有历史消息的续写请求)。

Streaming 与非 Streaming 对比:

特性Streaming非 Streaming
首个数据到达时间TTFT (~几十 ms)完整响应时间 (~秒级)
用户体验逐字显示,感知延迟低等待完整响应后一次性展示
客户端复杂度需要 SSE 解析简单 HTTP 响应解析
适用场景Chat UI、实时交互批处理、API 调用、离线任务
带宽每个 Token 一次网络传输单次传输
23 vLLM 的容错与错误处理机制有哪些?

答案:

vLLM 在服务端和客户端两个层面提供容错与错误处理机制,包括 Graceful Shutdown、请求超时、OOM 保护、请求重试等。

错误类型与处理策略:

错误类型HTTP 状态码原因客户端处理
模型未找到404模型名称不匹配 --served-model-name检查模型名
API Key 无效401未提供或错误的 API Key提供正确 Key
请求过大400/413Prompt Tokens 超 max_model_len截断或报错
服务过载503排队队列满指数退避重试
OOM 错误500GPU 显存不足重试(可能被调度到其他实例)
超时500请求处理超时设置合理 timeout
取消请求499客户端主动断开

客户端容错重试策略:

import time
import random
from openai import OpenAI, APIError, APITimeoutError, APIConnectionError

def retry_chat_completion(client, max_retries=3, base_delay=1.0, **kwargs):
    for attempt in range(max_retries):
        try:
            return client.chat.completions.create(**kwargs)
        except APITimeoutError:
            if attempt == max_retries - 1:
                raise
            delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
            time.sleep(delay)
        except APIConnectionError:
            if attempt == max_retries - 1:
                raise
            delay = base_delay * (2 ** attempt)
            time.sleep(delay)
        except APIError as e:
            if e.status_code == 503 and attempt < max_retries - 1:
                delay = base_delay * (2 ** attempt) + random.uniform(0, 2)
                time.sleep(delay)
            else:
                raise

服务端 Graceful Shutdown:

# vLLM 收到 SIGTERM 后的行为:
# 1. 停止接受新请求
# 2. 等待现有请求完成(或超时)
# 3. 释放 GPU 显存
# 4. 退出进程

# Kubernetes Pod Graceful Shutdown 配置
spec:
  terminationGracePeriodSeconds: 120
  containers:
    - name: vllm
      lifecycle:
        preStop:
          exec:
            # SIGTERM 前先通知 LoadBalancer 摘除
            command: ["/bin/sh", "-c", "sleep 15"]

OOM 保护配置:

# 保守的显存配置
python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct \
    --gpu-memory-utilization 0.85 \
    --max-model-len 4096 \
    --enforce-eager \           # 禁用 CUDA Graph(节省部分显存)
    --max-num-seqs 128          # 限制最大并发

稳定性保障最佳实践:

实践配置目的
显存余量gpu_memory_utilization=0.85为 CUDA 动态分配留缓冲区
限制并发max_num_seqs 合理值防止 Kv Cache 耗尽
限制长度max_model_len 合理值防止超长 Prompt OOM
健康检查就绪探针 /healthK8s 自动摘除不健康 Pod
多副本replicas ≥ 2单点故障无感知切换
请求超时proxy_read_timeout长连接保护
24 vLLM 的 Max Num Seqs 与 Max Model Len 如何影响性能?

答案:

max_num_seqs 控制单次推理的最大并发序列数,max_model_len 控制单序列最大 Token 长度,二者共同决定显存和吞吐量。

参数关系模型:

GPU 显存约束:

total_gpu_mem × gpu_memory_utilization
    = model_weights_mem
    + kv_cache_block_pool_mem
    + workspace_mem

kv_cache_block_pool_mem
    ≈ max_num_seqs × max_model_len / block_size × block_bytes

推论:
- max_model_len ↑ → 每序列最多 Block 数 ↑ → 可支持的 max_num_seqs ↓
- max_num_seqs ↑ → 总并行序列 ↑ → 每序列最大长度 ↓
- block_size 固定时,显存限制了一条帕累托前沿

参数影响矩阵:

max_num_seqsmax_model_len显存需求Throughput适用场景
2562048高(短序列)实时对话(短)
1284096通用对话
648192长文档处理
3216384低(并发)超长上下文
832768极高极长上下文

参数调优策略:

1. 分析业务流量特征:
   ├── 绝大多数请求 Prompt 长度?
   ├── 是否需要长上下文(RAG、文档分析)?
   └── 并发量级预估?

2. 确定 max_model_len:
   └── max_model_len = P99 请求长度 × 1.2(安全余量)

3. 计算 Block 容量:
   总 Block 数 = kv_cache_pool_mem / block_bytes
   每序列 Block 数 = max_model_len / block_size
   理论最大并发 = 总 Block 数 / 每序列 Block 数

4. 设置 max_num_seqs:
   └── max_num_seqs = min(256, 理论最大并发 × 0.8)

5. 压测验证:
   └── 固定 max_model_len,逐渐增加并发,观察显存 Usage 和延迟

实测数据参考(Llama-3-8B, A100-40G):

max_num_seqsmax_model_len峰值显存最大 Throughput(Tok/s)TTFT P50
256204838 GiB450035ms
128409637 GiB380055ms
64819233 GiB280090ms
321638431 GiB1600180ms
25 vLLM 与 TGI 如何对比?

答案:

vLLM 和 HuggingFace TGI(Text Generation Inference)均为主流 LLM 推理引擎,二者在架构设计、性能表现和生态支持上各有优势。

架构对比:

维度vLLMTGI
KV Cache 管理PagedAttention(页式)缓存分配的连续内存管理
批处理策略Continuous BatchingContinuous Batching
并行策略TP + PP(原生)TP(原生),PP 有限支持
量化支持AWQ, GPTQ, FP8, INT8, INT4GPTQ, AWQ, EETQ, FP8, bitsandbytes
后端自研 CUDA Kernel + PyTorchRust(核心)+ Python + Candle
服务接口OpenAI Compatible APIOpenAI Compatible API + 自有格式
LoRA 支持Multi-LoRA(GPU/CPU 动态加载)Multi-LoRA 支持
Prefix Cache原生支持有限支持
Chunked Prefill原生支持不支持
Speculative Decoding支持(Draft + EAGLE + NGram)不支持(计划中)
多模态LLaVA, Qwen-VL, InternVL, Phi-VisionIdefics3, LLaVA, Qwen2-VL
Web Serveruvicorn + FastAPIRust Web Server
Watermarking不支持支持

关键差异:

差异点vLLMTGI
显存效率PagedAttention 接近零浪费连续分配存在碎片
跨请求 KV 共享Block 级共享(Prefix Cache)会话级缓存
开发语言Python 为主Rust 为主(热路径)
生态系统vLLM 社区活跃(GitHub Stars 更多)HuggingFace 生态紧密集成
新模型支持速度较快(社区驱动)较快(HF 官方支持)
服务器内存占用较低较低(Rust Web Server)
Docker 镜像大小~6 GB~3 GB

如何选择:

场景推荐原因
追求最大吞吐量vLLMPagedAttention + Chunked Prefill
HuggingFace 生态紧密集成TGI与 HF Hub、推理端点原生集成
需要多模态推理vLLM更广泛的多模态模型支持
需要 Prefix CachevLLM原生 Block 级共享
需要 Chunked PrefillvLLMTGI 不原生支持
小型团队快速部署TGIDocker 镜像小,配置简单
需要 Watermarking 功能TGIvLLM 不支持
26 vLLM 与 SGlang 如何对比?

答案:

SGlang 是新兴的高性能 LLM 推理框架,与 vLLM 在设计理念上有诸多相似之处,同时在调度和前端编译方面有自己的技术创新。

技术对比:

维度vLLMSGlang
KV Cache 管理PagedAttentionRadixAttention(Radix Tree)
前缀缓存Hash 表(Block 级)Radix Tree(Token 级)
调度策略FCFS + PreemptionRadix-Aware 调度
前端编译SGLang DSL(结构化生成语言)
批处理Continuous BatchingContinuous Batching
Chunked Prefill支持支持
Speculative Decoding支持支持(EAGLE)
量化AWQ, GPTQ, FP8, INT8, INT4AWQ, GPTQ, FP8
TP / PP支持支持
LoRAMulti-LoRA支持
多模态广泛支持LLaVA, Qwen-VL
服务 APIOpenAI CompatibleOpenAI Compatible + SGLang Runtime
结构化输出JSON Mode原生 Constrained Decoding (Regex/JSON Schema)

核心差异:RadixAttention vs PagedAttention:

PagedAttention(vLLM):
Block 表管理,Hash 查找前缀缓存

RadixAttention(SGlang):
Radix Tree 组织 KV Cache,自动前缀匹配

           root
        /   |    \
      "你" "我" "请"
      /       \
    "好"      "是"
              /  \
           "AI"  "谁"

同一路径共享 KV Cache,新请求自动匹配最长前缀

SGlang 独有的 Radix-Aware 调度:

SGlang 调度器优先调度共享前缀的请求到同一 Batch:
- 最大化 Prefix Cache 命中率
- 减少冗余 Prefill 计算
- 对 Chat 多轮对话和 Batch API 场景显著提升吞吐

SGlang DSL 示例:

# SGlang 结构化生成
import sglang as sgl

@sgl.function
def multi_turn_qa(s, question):
    s += sgl.system("你是一个运维专家")
    s += sgl.user(question)
    s += sgl.assistant(sgl.gen("answer", max_tokens=256))

# 约束生成(JSON 模式)
@sgl.function
def extract_info(s, text):
    s += sgl.user(f"Extract from: {text}")
    s += sgl.gen("json", regex=r'\{"name": "\w+", "age": \d+\}')

选择指南:

场景推荐原因
Prefix Cache 命中率高(多轮对话)SGlangRadix Tree 自动匹配
需要约束生成(JSON/Regex)SGlang原生约束解码
需要结构化生成 DSLSGlangSGLang Runtime / DSL
追求最大生态兼容性vLLM更多模型、更多硬件支持
需要 FP8/量化vLLM量化方案更全面
Benchmark 吞吐最高SGlang部分 Benchmark 中领先
已有 vLLM 部署保持 vLLM迁移成本
27 vLLM 与 TensorRT-LLM 如何对比?

答案:

TensorRT-LLM 是 NVIDIA 官方的 LLM 推理优化框架,通过图编译优化和高度定制的 CUDA Kernel 实现极致推理性能。

架构对比:

维度vLLMTensorRT-LLM
推理引擎自研 Python CUDA KernelTensorRT 图编译器
模型加载HuggingFace 直接加载需转换为 TensorRT Engine
运行时编译无(Python JIT)需要离线编译 Engine
KV Cache 管理PagedAttentionPaged KV Cache(类似设计)
批处理Continuous BatchingIn-Flight Batching(类似)
图优化无(依赖 PyTorch)图融合、Kernel 自动调优
量化支持AWQ, GPTQ, FP8, INT8, INT4FP8, INT8, INT4, 混合精度
硬件NVIDIA, AMD, IntelNVIDIA 独占
服务接口OpenAI Compatible APITriton Inference Server
部署复杂度低(pip install + run)高(需编译 Engine)
新模型支持HuggingFace 模型直接加载需编写模型定义 + 编译

性能对比(Llama-3-8B, A100-80G, TGIS Benchmark):

指标vLLMTensorRT-LLM
峰值吞吐 (tok/s)3,2004,500
TTFT P50 (ms)4535
TPOT P50 (ms)2218
首次启动(冷启动)<1 分钟5-30 分钟(编译)
模型切换<1 分钟每次需重新编译
显存效率~96%(PagedAttention)~95%

部署流程对比:

vLLM:
1. pip install vllm
2. python -m vllm.entrypoints.openai.api_server --model xxx
(1 分钟内完成)

TensorRT-LLM:
1. git clone TensorRT-LLM + 编译 C++ 库
2. 编写模型配置(config.json)
3. 用 checkpoint 构建 TRT Engine(5-30 分钟)
4. 启动 Triton Inference Server
5. 加载 TRT Engine
(首次 >30 分钟)

选择决策矩阵:

条件推荐 vLLM推荐 TensorRT-LLM
追求极致吞吐是(图编译优化 + Kernel 调优)
快速原型验证
频繁模型切换—(每次需重新编译)
生产固定模型长期服务是(编译开销可接受)
非 NVIDIA 硬件—(仅 NVIDIA)
NVIDIA 一体方案是(Triton + TensorRT 生态)
HuggingFace 模型直接加载
LLM API 服务—(Triton 更重)
28 vLLM 如何配合 AutoAWQ / AutoGPTQ 进行离线量化?

答案:

vLLM 运行时直接支持 AWQ 和 GPTQ 量化模型的推理加载,离线量化需使用 AutoAWQ 或 AutoGPTQ 工具预先完成。

离线量化流程:

AWQ 离线量化:

1. 准备校准数据(代表性样本,通常 128-256 条)
2. AutoAWQ 分析每层的 Activation 分布
3. 计算 Channel-wise Saliency(显着性)
4. 应用 Scaling Factor 保护重要 Channel
5. 对 Weights 执行 INT4 量化
6. 保存量化模型(兼容 HF 格式)

GPTQ 离线量化:

1. 准备校准数据
2. AutoGPTQ 逐层量化
3. 对每层使用 Optimal Brain Quantization(OBQ)算法
4. 量化后进行调整以补偿误差
5. 保存量化模型

AutoAWQ 量化命令:

from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

model_path = "Qwen/Qwen2.5-7B-Instruct"
quant_path = "Qwen2.5-7B-Instruct-AWQ"

# 加载模型
model = AutoAWQForCausalLM.from_pretrained(
    model_path,
    low_cpu_mem_usage=True,
    use_cache=False,
)
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)

# 量化配置
quant_config = {
    "zero_point": True,
    "q_group_size": 128,
    "w_bit": 4,
    "version": "GEMM",
}

# 加载校准数据
from datasets import load_dataset
calib_data = load_dataset("mit-han-lab/pile-val-backup", split="validation")

# 执行量化
model.quantize(
    tokenizer,
    quant_config=quant_config,
    calib_data=calib_data,
)

# 保存
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)

AutoGPTQ 量化命令:

from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
from transformers import AutoTokenizer

model_path = "Qwen/Qwen2.5-7B-Instruct"
quant_path = "Qwen2.5-7B-Instruct-GPTQ"

tokenizer = AutoTokenizer.from_pretrained(model_path, use_fast=True)

# GPTQ 量化配置
quantize_config = BaseQuantizeConfig(
    bits=4,                # 4-bit 量化
    group_size=128,        # Group Size
    damp_percent=0.01,     # 阻尼因子
    desc_act=False,        # 是否按 Activation 排序
    sym=True,              # 对称量化
    true_sequential=True,  # 逐层量化
)

# 加载模型
model = AutoGPTQForCausalLM.from_pretrained(
    model_path,
    quantize_config=quantize_config,
)

# 加载校准数据
from datasets import load_dataset
calib_dataset = load_dataset("wikitext", "wikitext-2-raw-v1", split="test")
examples = [tokenizer(ex["text"]) for ex in calib_dataset.select(range(128))]

# 执行量化
model.quantize(examples)

# 保存
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)

量化后 vLLM 加载:

# AWQ
python -m vllm.entrypoints.openai.api_server \
    --model ./Qwen2.5-7B-Instruct-AWQ \
    --quantization awq \
    --dtype auto

# GPTQ
python -m vllm.entrypoints.openai.api_server \
    --model ./Qwen2.5-7B-Instruct-GPTQ \
    --quantization gptq \
    --dtype auto

参数对比:

参数AutoAWQAutoGPTQ
量化方法Activation-AwareOptimal Brain Quantization
bits42/3/4/8
group_size12832/64/128
校准数据量128-256 条128-512 条
量化时间(7B 模型)~15 分钟~30-45 分钟
vLLM 兼容性优秀优秀
精度损失(vs FP16)<0.5%<1%
29 vLLM 的扩展与新硬件支持情况如何?

答案:

vLLM 从 NVIDIA GPU 起步,逐步扩展到 AMD ROCm、Intel Gaudi、Intel GPU、AWS Inferentia 等多种硬件平台,仍在积极演进。

硬件支持矩阵:

硬件平台状态量化支持多 GPU (TP)备注
NVIDIA CUDA (Ampere/Hopper)完整支持AWQ/GPTQ/FP8/INT8/INT4完整主要优化目标
NVIDIA CUDA (Volta/Turing)完整支持AWQ/GPTQ/INT8/INT4完整不支持 FP8
AMD ROCm (MI250/MI300X)支持AWQ/GPTQ/INT8支持通过 PyTorch ROCm
Intel Gaudi 2 / 3支持(社区)有限通过 Intel Gaudi PyTorch
Intel GPU (Data Center Max)实验性有限通过 Intel XPU PyTorch
x86 CPU支持INT8/INT4非 GPU 场景
Apple Silicon (MPS)实验性Metal Performance Shaders
AWS Inferentia (Neuron)不支持使用 vLLM Neuron 分支

AMD ROCm 部署:

# Docker 方式(推荐)
docker run --rm -it \
    --device=/dev/kfd --device=/dev/dri \
    --group-add video \
    vllm/vllm-openai:rocm \
    python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct \
    --dtype auto \
    --tensor-parallel-size 1

# 或直接 pip 安装(ROCm 环境)
pip install vllm
python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct

AMD ROCm 注意事项:

注意点说明
FP8 量化MI300X 支持 FP8,MI250 不支持
CUDA GraphROCm 下默认禁用(--enforce-eager
性能差异部分算子 ROCm 优化不如 CUDA(逐步追赶)
Dockervllm/vllm-openai:rocm 专用镜像

Intel Gaudi 2/3 部署:

# Gaudi 基础镜像
docker pull vault.habana.ai/gaudi-docker/1.18.0/ubuntu22.04/habanalabs/pytorch-installer-2.4.0:latest

# vLLM 需从源码编译
git clone https://github.com/vllm-project/vllm.git
cd vllm
pip install -e .
python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct \
    --device hpu

平台选择建议:

条件推荐硬件原因
最佳性能 + 生态NVIDIA H100/H200/B200CUDA 生态最成熟
性价比优先AMD MI300X显存大(192GB),成本低
训练 + 推理混合NVIDIA A100/H100MIG 支持灵活切分
Intel 生态绑定Intel Gaudi 3与 Intel 生态一致
纯 CPU 推理(低负载)x86 CPU零 GPU 成本
30 vLLM 生产环境部署最佳实践有哪些?

答案:

vLLM 生产环境的稳定、高效、可维护运行需要在容器化、配置调优、监控告警、灰度发布和多实例负载均衡等方面遵循规范操作。

容器化部署最佳实践:

# 生产 Dockerfile 示例
FROM vllm/vllm-openai:v0.7.2

ENV VLLM_LOGGING_LEVEL=INFO
ENV CUDA_MODULE_LOADING=LAZY
ENV OMP_NUM_THREADS=1

# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

# 非 root 运行
USER 1000:1000

ENTRYPOINT ["python3", "-m", "vllm.entrypoints.openai.api_server"]

生产配置参数基线:

python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-72B-Instruct \
    --served-model-name qwen2.5-72b \
    --tensor-parallel-size 4 \
    --gpu-memory-utilization 0.90 \
    --max-model-len 8192 \
    --max-num-seqs 128 \
    --enable-prefix-caching \
    --enable-chunked-prefill \
    --max-num-batched-tokens 8192 \
    --swap-space 4 \
    --dtype auto \
    --api-key sk-production-secret \
    --disable-log-requests \
    --disable-log-stats

Kubernetes 生产就绪配置清单:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-prod
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    spec:
      # 反亲和:分布到不同节点
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  app: vllm
              topologyKey: kubernetes.io/hostname
      # 服务质量保证
      terminationGracePeriodSeconds: 120
      containers:
        - name: vllm
          resources:
            limits:
              nvidia.com/gpu: 4
              memory: 256Gi
            requests:
              nvidia.com/gpu: 4
              memory: 128Gi
          startupProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 30
            failureThreshold: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 10
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 60
            periodSeconds: 15
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: vllm-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: vllm-prod
  minReplicas: 2
  maxReplicas: 8
  metrics:
    - type: Prometheus
      prometheus:
        metric: avg(vllm:num_requests_waiting) / avg(vllm:num_requests_running)
        target:
          type: AverageValue
          averageValue: "0.5"

生产检查清单:

类别检查项标准
可靠性多副本replicas ≥ 2
可靠性Pod 反亲和分布到不同节点
可靠性Graceful ShutdownterminationGracePeriodSeconds ≥ 120
可靠性滚动更新maxUnavailable=0
性能显存利用gpu_memory_utilization ≤ 0.90
性能Prefix Cache多轮对话场景必须开启
性能Chunked Prefill长 Prompt 场景必须开启
性能模型长度max_model_len ≤ 业务 P99 + 20% 余量
监控Prometheus/metrics 暴露
监控告警规则KV Cache > 85%, 排队请求 > 50, P99 延迟翻倍
安全API Key强制鉴权
安全网络策略vLLM 不暴露公网
运维模型缓存PVC 持久化模型
运维日志轮转限制输出,禁用 request 级别日志

灰度发布策略:

Step 1:启动新版本 Pod(1 个)
    ├── 验证健康检查通过
    └── 检查 /metrics 指标正常

Step 2:接入 10% 流量(Canary)
    ├── 观察 15 分钟
    ├── 对比新旧版本 P50/P99 Latency
    └── 对比 Throughput

Step 3:接入 50% 流量
    ├── 观察 30 分钟
    └── 检查错误率

Step 4:全量切换
    ├── 滚动更新所有 Pod
    └── 保留一个旧 Pod 作为快速回滚目标

Step 5:稳定运行 1 小时后清理旧 Pod

告警规则参考:

# Prometheus Alert Rules
groups:
  - name: vllm
    rules:
      - alert: VLLMKVCacheHigh
        expr: vllm:gpu_cache_usage_perc > 85
        for: 5m
        annotations:
          summary: "vLLM GPU KV Cache 使用率超过 85%"

      - alert: VLLMQueueHigh
        expr: vllm:num_requests_waiting > 50
        for: 3m
        annotations:
          summary: "vLLM 排队请求超过 50"

      - alert: VLLMTTFTP99High
        expr: histogram_quantile(0.99, rate(vllm:time_to_first_token_seconds_bucket[5m])) > 1
        for: 5m
        annotations:
          summary: "vLLM TTFT P99 超过 1 秒"

      - alert: VLLMSwappedRequests
        expr: vllm:num_requests_swapped > 0
        for: 1m
        annotations:
          summary: "vLLM 有请求被交换到 CPU"