单卡搞定大模型高并发:vLLM与LiteLLM流式代理生产级调优实战

2次阅读
没有评论

共计 3488 个字符,预计需要花费 9 分钟才能阅读完成。

最近在给团队内部搭建一套私有代码助手和知识库 Agent 网关时,我又遇到了那个老生常谈的硬骨头:本地开源大模型在单个测试请求下跑得飞快,一旦前端并发进来五六个流式对话(SSE),首字延迟(TTFT)直接飙到 8 秒以上,显存瞬间报 OOM(Out of Memory),下游应用连片 504 超时。

很多朋友在用 Ollama 跑个人玩具项目时觉得挺顺手,但只要把它挂到真实的小型业务系统或多人 Agent 场景下,就会发现它的并发调度和队列控制极其脆弱。为了在单张 RTX 4090(24G)或者云端单卡 A10/A100 上榨干每一滴算力,并对外提供兼容 OpenAI 接口的高并发流式代理,我把生产栈重构成了 vLLM + LiteLLM 组合。这篇文章记录了我实测调优后的完整架构、配置文件、核心避坑点以及压测对比数据。

一、痛点拆解:为什么单卡并发总是崩?

在深入配置之前,先理清两个最致命的瓶颈:

  1. KV Cache 静态分配浪费或碎片化 :原生 HuggingFace 或简易部署框架通常会为每次推理按最大上下文预分配连续显存,导致两三个 4k 上下文请求就把 24G 显存吃光;vLLM 的 PagedAttention 虽然解决了内存碎片,但如果显存预留比例(gpu-memory-utilization)没算准,CUDA 上下文或突发长上下文依然会瞬间打崩服务。
  2. 流式长连接拖垮代理层 :SSE(Server-Sent Events)是长连接。传统的 Python 业务网关如果异步 IO 没处理好,或者反向代理缓冲区(Buffer)没关,会导致 Chunk 积压在代理层,客户端体验到的不是“打字机”流式效果,而是卡顿几秒后突然吐出一大坨文字。

二、底层推理引擎:vLLM 生产级启动配置实战

以部署当前实用性价比极高的 Qwen2.5-7B-Instruct(或 AWQ 量化版 14B)为例。直接裸跑命令往往会踩雷,推荐用 Docker 固化环境参数:

# docker-compose.vllm.yml
services:
  vllm-engine:
    image: vllm/vllm-openai:latest
    container_name: vllm-engine
    runtime: nvidia
    restart: unless-stopped
    environment:
      - CUDA_VISIBLE_DEVICES=0
      - NCCL_IGNORE_DISABLED_P2P=1
    volumes:
      - /data/huggingface/hub:/root/.cache/huggingface/hub
    ports:
      - "8000:8000"
    ipc: host
    command: >
      --model Qwen/Qwen2.5-7B-Instruct
      --served-model-name qwen-7b
      --host 0.0.0.0
      --port 8000
      --gpu-memory-utilization 0.90
      --max-model-len 8192
      --max-num-seqs 64
      --block-size 16
      --enable-prefix-caching
      --disable-log-requests
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

核心参数排坑指北:

  • --gpu-memory-utilization 0.90:别填 0.98!模型权重加载完后,剩下的显存全会被划分为 KV Cache Block。设得太满,一旦 CUDA 运行时在处理长 Prompt 临时分配激活显存时,就会直接抛出 CUDA out of memory。留 10% 是最稳妥的缓冲垫。
  • --max-num-seqs 64:单卡最大并发推理序列数。不要信默认的几百,在消费级单卡上设成 32 到 64 最为健康。并发打满时,vLLM 会优雅地在服务端排队排队(Queue),而不是直接把显存干爆。
  • --enable-prefix-caching: 强烈建议开启! 尤其做 Agent 系统或知识库 RAG 时,System Prompt 和多轮上下文开头很多是重合的。开启此项后,重合前缀直接复用 KV Cache,能把首字延迟(TTFT)降低 60% 以上。
  • ipc: host:必须配置,防止多进程间通信或 PyTorch 共享内存不足导致进程诡异暴毙。

三、流式网关层:LiteLLM 路由与连接池优化

vLLM 负责底层的张量计算与 KV 缓存,但在多客户端接入、密钥鉴权、熔断降级和用量监控层面,裸暴露 vLLM 是不明智的。LiteLLM 提供了极低开销的代理封装层。

编写 litellm-config.yaml:

model_list:
  - model_name: gpt-4o-mini  # 对外伪装成标准 OpenAI 模型名
    litellm_params:
      model: openai/qwen-7b
      api_base: http://vllm-engine:8000/v1
      api_key: "EMPTY"
      timeout: 120
      stream_timeout: 30

router_settings:
  routing_strategy: latency-based-routing
  num_retries: 2
  timeout: 60

general_settings:
  master_key: sk-nassky-master-secret-token

启动 LiteLLM 代理服务:

docker run -d \
  --name litellm-proxy \
  --network host \
  -v $(pwd)/litellm-config.yaml:/app/config.yaml \
  ghcr.io/berriai/litellm:main-latest \
  --config /app/config.yaml --port 4000

网关流式代理深度排错:

如果 LiteLLM 外面还套了一层 Nginx,很多同学会遇到“流式不流,一顿一顿”的现象。务必在反向代理的 location 块中强制关闭缓冲:

location /v1/chat/completions {
    proxy_pass http://127.0.0.1:4000;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    
    # 关键配置:禁用一切反向代理缓冲,保证实时 SSE 吐字
    proxy_buffering off;
    proxy_cache off;
    chunked_transfer_encoding on;
    
    proxy_read_timeout 600s;
    proxy_send_timeout 600s;
}

四、压测实录:并发与首字延迟(TTFT)实测

我在本地单卡 RTX 4090 机器上,使用 locust 对搭建完成的服务进行并发压力测试。输入 Prompt 长度约为 1200 Tokens(典型 RAG 检索场景),输出限制为 300 Tokens。

并发并发数(Concurrency) 原生 Ollama (默认配置) TTFT vLLM (无 Prefix Cache) TTFT vLLM (开启 Prefix Cache) TTFT 生成吞吐 (Tokens/s)
c = 1 380 ms 210 ms 110 ms 95 t/s
c = 8 2150 ms 480 ms 230 ms 420 t/s
c = 32 超时 / OOM 频繁 1280 ms 650 ms 1150 t/s
c = 64 完全服务不可用 2890 ms (请求平稳排队) 1420 ms (无爆显存) 1320 t/s

实测数据说明了一切:在开启 prefix-caching 并合理调校了 block-size 与并发序列队列后,单卡 4090 即使在 32 并发的高压突发下,首字吐出依然能控制在 1 秒以内,总吞吐量翻了 10 倍以上。最重要的是, 服务没有因为并发突增而崩溃 OOM,超出的请求全部在队列中安全挂起等待调度。

总结与避坑心得

单卡搞定大模型并发,拼的不是参数量大小,而是对显存分配和 IO 流的精细控制:

  1. 显存预留必须克制 :永远给 CUDA 上下文保留 10%~15% 的余量,绝不要把 gpu-memory-utilization 填到 1.0。
  2. RAG 场景必开前缀缓存 :--enable-prefix-caching 是单卡性价比最高的神级开关,能吃掉大量重复的检索上下文计算。
  3. 链路流控不能省 :推理引擎负责“快”,LiteLLM / Nginx 负责“稳”。关闭所有中间层 HTTP 缓冲区,流式 Agent 的响应体验才能丝滑跟手。

按照这套方案跑起来,即便是单卡小机器,也足以稳定支撑一个小团队的生产力工具和本地知识库调用了。极客折腾的意义就在于此:用精打细算的工程调优,把消费级硬件的生产力压榨到极限。

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