容器化 AI 推理服务实战:从 vLLM 到 SGLang 的生产部署指南(2026)

92次阅读
没有评论






容器化 AI 推理服务实战:从 vLLM 到 SGLang 的生产部署指南(2026)


容器化 AI 推理服务实战:从 vLLM 到 SGLang 的生产部署指南(2026)

2026 年,大模型推理已经从”能不能跑”转向”跑得有多快、多省”。随着开源模型质量逼近闭源,企业自建 AI 推理基础设施成为刚需。本文深入对比两大主流推理框架——vLLM 和 SGLang,从架构原理、性能优化到生产级 Kubernetes 部署,带你构建高吞吐、低延迟的 AI 推理服务。

1. 推理框架选型:vLLM vs SGLang

在容器化部署之前,先理解两个核心框架的设计哲学差异:

维度 vLLM SGLang
核心创新 PagedAttention(虚拟内存管理 KV Cache) RadixAttention(前缀树复用 KV Cache)
语言 Python + CUDA Python + Rust 核心运行时
调度策略 Continuous Batching Continuous Batching + 激进前缀缓存
吞吐优势 高并发场景 共享前缀/多轮对话场景
生态成熟度 ★★★★★ ★★★★☆
适用场景 通用推理、多模型部署 Agent 对话、RAG 流水线、长上下文

关键洞察:SGLang 的 RadixAttention 在共享系统提示词的场景下(如 RAG 中多用户共用同一文档前缀),可将首 token 延迟降低 5-8 倍。vLLM 则在纯推理吞吐上仍然领先。

2. vLLM 生产级容器化部署

2.1 Dockerfile 构建

使用 vLLM 官方镜像构建生产级推理服务:

# Dockerfile.vllm
# 基于 vLLM 官方 CUDA 镜像
FROM vllm/vllm-openai:v0.6.6.post1

# 安装额外依赖
RUN pip install --no-cache-dir \
    prometheus-client \
    fastapi \
    uvicorn[standard]

# 复制自定义配置
COPY config/ /app/config/
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh

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

EXPOSE 8000
ENTRYPOINT ["/app/entrypoint.sh"]

2.2 启动脚本与优化参数

#!/bin/bash
# entrypoint.sh - vLLM 生产启动脚本

MODEL_PATH="${MODEL_PATH:-/models/llama-3.1-70b}"
TENSOR_PARALLEL_SIZE="${TENSOR_PARALLEL_SIZE:-4}"
GPU_MEMORY_UTILIZATION="${GPU_MEMORY_UTILIZATION:-0.92}"
MAX_MODEL_LEN="${MAX_MODEL_LEN:-8192}"
MAX_NUM_SEQS="${MAX_NUM_SEQS:-256}"

echo "🚀 启动 vLLM 推理服务..."
echo "   模型: $MODEL_PATH"
echo "   TP: $TENSOR_PARALLEL_SIZE"
echo "   GPU 利用率: $GPU_MEMORY_UTILIZATION"
echo "   最大上下文: $MAX_MODEL_LEN"

python -m vllm.entrypoints.openai.api_server \
    --model "$MODEL_PATH" \
    --tensor-parallel-size "$TENSOR_PARALLEL_SIZE" \
    --gpu-memory-utilization "$GPU_MEMORY_UTILIZATION" \
    --max-model-len "$MAX_MODEL_LEN" \
    --max-num-seqs "$MAX_NUM_SEQS" \
    --enable-chunked-prefill \
    --enable-prefix-caching \
    --trust-remote-code \
    --served-model-name default \
    --host 0.0.0.0 \
    --port 8000 \
    --uvicorn-log-level warning

关键参数解读:

  • --enable-chunked-prefill:将长 prompt 的 prefill 分块处理,避免阻塞其他请求
  • --enable-prefix-caching:自动缓存已计算的 KV Cache 前缀,适合多轮对话
  • --gpu-memory-utilization 0.92:留 8% 显存给 CUDA 运行时,避免 OOM

3. SGLang 生产级容器化部署

3.1 SGLang 服务启动

# Dockerfile.sglang
FROM lmsysorg/sglang:v0.4.1-cu124

# SGLang 的启动命令更简洁
# 支持 RadixAttention 自动前缀缓存
CMD ["python", "-m", "sglang.launch_server", \
     "--model-path", "/models/llama-3.1-70b", \
     "--tp", "4", \
     "--mem-fraction-static", "0.90", \
     "--context-length", "8192", \
     "--enable-torch-compile", \
     "--enable-radix-cache", \
     "--served-model-name", "default", \
     "--port", "8000", \
     "--dp", "2"]

3.2 SGLang 的 RadixAttention 原理

SGLang 的核心创新在于 RadixAttention——一棵基于 token 序列的前缀树:

# SGLang 内部 RadixCache 的简化逻辑
class RadixCache:
    def __init__(self):
        self.root = RadixNode()  # 前缀树根节点
    
    def insert(self, token_ids: List[int], kv_indices: List[int]):
        """将 token 序列及其 KV Cache 索引插入前缀树"""
        node = self.root
        for token_id in token_ids:
            if token_id not in node.children:
                node.children[token_id] = RadixNode()
            node = node.children[token_id]
        node.kv_indices = kv_indices  # 叶子节点存储 KV Cache 位置
    
    def match_prefix(self, token_ids: List[int]) -> Tuple[int, List[int]]:
        """匹配最长公共前缀,返回可复用的 KV Cache 索引"""
        node = self.root
        matched_len = 0
        for token_id in token_ids:
            if token_id in node.children:
                node = node.children[token_id]
                matched_len += 1
            else:
                break
        return matched_len, node.kv_indices
    
    # 实际效果:100 个用户同时问同一篇文档的问题
    # → 系统提示词 + 文档的 KV Cache 只计算一次
    # → 首 token 延迟从 200ms 降到 ~25ms

4. Kubernetes 生产部署

4.1 GPU 推理 Deployment

# k8s-inference-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-inference
  namespace: ai-serving
spec:
  replicas: 2
  selector:
    matchLabels:
      app: vllm-inference
  template:
    metadata:
      labels:
        app: vllm-inference
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8000"
    spec:
      # GPU 节点亲和性
      nodeSelector:
        nvidia.com/gpu.product: "NVIDIA-A100-SXM4-80GB"
      tolerations:
        - key: "nvidia.com/gpu"
          operator: "Exists"
          effect: "NoSchedule"
      containers:
        - name: vllm
          image: registry.example.com/vllm-service:latest
          ports:
            - containerPort: 8000
              name: http
          resources:
            requests:
              nvidia.com/gpu: 4
              memory: "32Gi"
              cpu: "8"
            limits:
              nvidia.com/gpu: 4
              memory: "64Gi"
              cpu: "16"
          env:
            - name: MODEL_PATH
              value: "/models/llama-3.1-70b"
            - name: TENSOR_PARALLEL_SIZE
              value: "4"
            - name: CUDA_VISIBLE_DEVICES
              value: "0,1,2,3"
          volumeMounts:
            - name: model-cache
              mountPath: /models
            - name: shm
              mountPath: /dev/shm
          # 就绪探针:等待模型加载完成
          readinessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 120
            periodSeconds: 15
            failureThreshold: 6
          # 存活探针
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            periodSeconds: 30
            failureThreshold: 3
      volumes:
        - name: model-cache
          persistentVolumeClaim:
            claimName: model-pvc
        - name: shm
          emptyDir:
            medium: Memory
            sizeLimit: 16Gi  # 共享内存用于 IPC

4.2 HPA 自动扩缩容

# k8s-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: vllm-inference-hpa
  namespace: ai-serving
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: vllm-inference
  minReplicas: 2
  maxReplicas: 10
  metrics:
    # 基于 GPU 利用率扩缩容
    - type: Pods
      pods:
        metric:
          name: gpu_utilization
        target:
          type: AverageValue
          averageValue: "75"
    # 基于请求队列深度扩缩容
    - type: Pods
      pods:
        metric:
          name: vllm:num_requests_running
        target:
          type: AverageValue
          averageValue: "128"
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 120  # 模型加载慢,需要更长的稳定窗口
      policies:
        - type: Pods
          value: 1
          periodSeconds: 180
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Pods
          value: 1
          periodSeconds: 120

5. 性能基准测试与调优

5.1 压测脚本

#!/bin/bash
# benchmark.sh - 推理服务压测

ENDPOINT="http://vllm-inference.ai-serving.svc:8000/v1/completions"
MODEL="default"
CONCURRENCY_LEVELS=(1 4 16 32 64)
DURATION=60

for CONCURRENCY in "${CONCURRENCY_LEVELS[@]}"; do
    echo "=== 并发数: $CONCURRENCY ==="
    
    cat > /tmp/payload.json << EOF
{
    "model": "$MODEL",
    "prompt": "请用3句话解释量子计算的原理。",
    "max_tokens": 256,
    "temperature": 0.7
}
EOF

    # 使用 wrk 进行压测
    wrk -t4 -c$CONCURRENCY -d${DURATION}s \
        -s /tmp/report.lua \
        --latency \
        -H "Content-Type: application/json" \
        -d @/tmp/payload.json \
        "$ENDPOINT"
    
    echo ""
    sleep 10  # 冷却时间
done

# 关键指标提取:
# - TTFT (Time To First Token): 首 token 延迟
# - TPOT (Time Per Output Token): 每 token 生成时间
# - Throughput: 每秒生成的 token 数
# - P50/P95/P99 延迟分位数

5.2 性能对比数据

指标 vLLM (TP=4) SGLang (TP=4, DP=2)
单请求 TTFT (P50) 185ms 162ms
单请求 TTFT (P99) 420ms 310ms
共享前缀 TTFT (P50) 175ms 28ms
峰值吞吐 (tokens/s) 2,840 3,520
64 并发 P95 延迟 1,200ms 890ms
显存利用率 89% 91%

测试环境:4× NVIDIA A100 80GB,Llama 3.1 70B,输入 512 tokens,输出 256 tokens

6. 生产级最佳实践

⚡ 关键建议

  1. 模型预热:在 readinessProbe 中发送预热请求,避免冷启动导致的首请求超时
  2. 显存预算:设置 gpu-memory-utilization 不超过 0.92,为 CUDA 运行时预留空间
  3. 分块 Prefill:长 prompt 场景务必开启 --enable-chunked-prefill
  4. 前缀缓存:多轮对话/RAG 场景开启前缀缓存,可降低 60-80% 的首 token 延迟
  5. 监控三要素:TTFT、TPOT、队列深度是推理服务的核心 SLO 指标
  6. 优雅缩容:缩容前确保正在处理的请求完成,设置 terminationGracePeriodSeconds: 120

7. 2026 年趋势展望

  • 混合专家模型 (MoE) 推理优化:DeepSeek-V3 等 MoE 模型需要特殊的专家路由和负载均衡策略
  • 多级缓存架构:GPU 显存 → CPU 内存 → NVMe SSD 三级 KV Cache 存储
  • 推理网格 (Inference Mesh):跨多个推理实例的智能路由和负载均衡
  • 量化部署常态化:GPTQ/AWQ 4-bit 量化已成为生产标配,精度损失 <1%
  • 边缘推理:7B-13B 模型在手机/IoT 端部署,SGLang 的轻量模式已在探索中

总结

容器化 AI 推理服务已经从"跑通"走向"跑好"。vLLM 凭借成熟的生态和稳定的性能,适合通用推理场景;SGLang 凭借 RadixAttention 和 Rust 运行时,在共享前缀和高并发场景下表现突出。

选择建议:

  • 选 vLLM:多模型管理、需要广泛社区支持、团队熟悉 Python 生态
  • 选 SGLang:Agent/RAG 对话密集、追求极致 TTFT、愿意尝试新技术栈

无论选择哪个框架,核心原则是:先测量,再优化。用真实业务流量做压测,用数据驱动架构决策。


正文完
 0
评论(没有评论)