共计 3940 个字符,预计需要花费 10 分钟才能阅读完成。
上个月帮朋友的小团队改造内部大模型基础设施,他们原先的方案是用简单的 FastChat 加上原生 PyTorch 推理服务,几个人同时触发代码补全或文档解析,请求排队能排到五六秒以上,显卡利用率却在 30% 左右晃荡,时不时还因为长上下文 OOM(显存溢出)直接崩掉。更麻烦的是,业务端对接了一堆异构接口,换个模型就得改一次客户端 SDK。
对于个人极客或小微团队来说,没必要一上来就堆庞大的 Triton 或 Ray 集群。我们最终敲定了一套极其精简但生产可用的方案: 底座采用 vLLM 作为推理加速引擎,上层挂载 LiteLLM 充当统一 API Gateway 与负载代理 。单张 RTX 4090(24G)或者云端单卡 A10,就能跑出百级并发的吞吐表现。这篇文章就把整套配置、踩坑细节与生产调优参数完整理一遍。
一、为什么是 vLLM + LiteLLM 组合?
很多新手容易把模型推理引擎(Inference Engine)和网关(API Gateway)混在一起。简单拆解一下两者的职责边界:
- vLLM:专注于“单机极致吞吐”。基于 PagedAttention 机制,它把 KV Cache 像操作系统虚拟内存一样做分页管理,消除了连续显存分配碎片,直接把模型并发并发量拉升了数倍。
- LiteLLM:专注于“协议统一与流量调度”。把底层所有的开源模型、甚至公有云(Claude、DeepSeek、OpenAI)封装成统一的
/v1/chat/completions规范,自带密钥管理、速率限制、重试回退与流式响应转发。
让 vLLM 专心啃显卡计算,把用户鉴权、路由降级、并发排队交给 LiteLLM 处理,整个系统的弹性和可维护性会高出好几个量级。
二、生产级 Docker Compose 编排实战
别在宿主机上肉身编译 PyTorch 和 CUDA 依赖,版本冲突会浪费大半天时间。我们直接走容器化编排。以下是我在生产环境验证过的 docker-compose.yml 完整文件:
version: '3.8'
services:
# 1. 底层推理引擎:vLLM
vllm-engine:
image: vllm/vllm-openai:latest
container_name: vllm-engine
runtime: nvidia
restart: always
environment:
- HUGGING_FACE_HUB_TOKEN=hf_your_token_here
volumes:
- /data/models:/root/.cache/huggingface
ports:
- "8000:8000"
ipc: host
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
command: >
--model Qwen/Qwen2.5-Coder-7B-Instruct
--gpu-memory-utilization 0.88
--max-model-len 8192
--enforce-eager
--trust-remote-code
--port 8000
# 2. 上层代理网关:LiteLLM Proxy
litellm-proxy:
image: ghcr.io/berriai/litellm:main-latest
container_name: litellm-proxy
restart: always
ports:
- "4000:4000"
volumes:
- ./config.yaml:/app/config.yaml
command: ["--config", "/app/config.yaml", "--port", "4000"]
depends_on:
- vllm-engine
紧接着,在同级目录下编写 LiteLLM 的路由配置文件 config.yaml:
model_list:
# 本地部署的开源代码模型
- model_name: coder-local
litellm_params:
model: openai/Qwen/Qwen2.5-Coder-7B-Instruct
api_base: http://vllm-engine:8000/v1
api_key: "none"
stream: true
# 兜底降级备选(当本地模型超时或排队过长时)- model_name: fallback-cloud
litellm_params:
model: deepseek/deepseek-chat
api_key: "sk-your-cloud-api-key"
litellm_settings:
drop_params: true
set_verbose: false
general_settings:
master_key: "sk-nassky-master-key-2026"
启动服务非常干脆:
docker compose up -d
# 查看显卡状态和模型加载日志
docker logs -f vllm-engine
三、三个致命踩坑点与深度排障
看着配置很简单,但我在实际压测和上线时,遭遇过几个容易让人通宵排错的暗坑:
1. ipc: host 缺失导致的随机死锁
在 Docker 部署 vLLM 时,很多人会漏掉 ipc: host。因为 PyTorch 的 DataLoader 和底层通信在多线程处理并发时大量使用共享内存(POSIX Shared Memory)。Docker 默认的 /dev/shm 大小只有 64MB。并发一旦打上去,容器内共享内存撑爆,PyTorch 不会报错退出,而是直接挂起陷入死锁,GPU 占用瞬间掉为 0%,HTTP 连接全部挂起超时。 必须显式配置 ipc: host 共享宿主机内存 。
2. 显存碎片与 --gpu-memory-utilization 比例陷阱
vLLM 启动时会预先按 gpu-memory-utilization 的比例把显存申请掉,剩下的显存全部划给 KV Cache。如果你设为 0.95 或 0.98,一旦系统其他进程产生轻微显存波动,或者 CUDA Context 需要临时分配几百兆,就会直接触发 CUDA OOM 暴毙。
对于 24G 显存的卡, 稳妥值是 0.85 ~ 0.90。多留出 2~3GB 显存应对突发的系统开销,能保证服务连续运行几个月不 crash。
3. 流式传输(Streaming)在反向代理后的背压崩溃
如果前面挂了 Nginx 做对外暴露,必须关掉代理缓冲,否则客户端不仅感受不到打字机效果,还会导致推理端过快消费而传输堆积在服务端:
location / {
proxy_pass http://127.0.0.1:4000;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding on;
# 关键:彻底关闭缓冲,保证每个 SSE token 实时直通
proxy_buffering off;
proxy_cache off;
}
四、实测吞吐数据与压测验证
我们在单台配备 RTX 4090、32G 内存的机器上,使用 Qwen2.5-Coder-7B-Instruct(FP16)通过压测脚本进行端到端并发测试(输入 Prompt 长度约 512 tokens,生成输出约 256 tokens):
| 并发客户端数 | 原生 Transformers (Tokens/s) | vLLM + LiteLLM (Tokens/s) | TTFT (首字延迟) |
|---|---|---|---|
| 1 (单请求基准) | 52 tps | 78 tps | ~180ms |
| 10 并发 | 48 tps (严重排队) | 520 tps | ~240ms |
| 30 并发 | OOM 崩溃 | 1140 tps | ~410ms |
可以看到,随着并发上升,基于 PagedAttention 的 Batching 优势极其恐怖。原生代码在 30 并发时直接打崩显存,而 vLLM 的总吞吐突破了 1100 tokens/s,首字延迟(TTFT)依然控制在半秒以内。
五、客户端调用验证
既然 LiteLLM 已经抹平了协议差异,现在所有代码都可以直接使用官方 openai SDK 调用:
from openai import OpenAI
client = OpenAI(
api_key="sk-nassky-master-key-2026",
base_url="http://localhost:4000"
)
response = client.chat.completions.create(
model="coder-local",
messages=[{"role": "system", "content": "你是一个资深架构师。"},
{"role": "user", "content": "写一段 Python 高并发 asyncio 任务池样例代码"}
],
stream=True
)
for chunk in response:
content = chunk.choices[0].delta.content
if content:
print(content, end="", flush=True)
总结与避坑心得
私有化大模型不是无脑堆硬件的游戏,合理拆分层级结构能省下大量无用功:
- 算子与调度剥离 :让 vLLM 专管显存显卡,LiteLLM 专管鉴权与转发,后续横向扩展加多卡或加机器时,LiteLLM 只需要加几行
api_base就能做到多机轮询均衡。 - 显存分配宁缺毋滥 :不要把
gpu-memory-utilization顶满,留足余量才能防突发请求击穿服务。 - 全链路关闭 Buffering:从 LiteLLM 到反向代理 Nginx,任何一处缓冲配置不当都会毁掉流式体验。
这套方案运行在我们本地测试集群已经数月,无论是日常对接 Cursor/Continue 写代码,还是跑内部自动化 Agent 任务,性能和稳定性都非常抗打。如果你正在发愁单卡私有化部署的瓶颈,这套组合可以直接照抄作业。
===END===