共计 3713 个字符,预计需要花费 10 分钟才能阅读完成。
上个月,我们团队打算把内部多个业务 Agent 的底层推理全面下沉到本地服务器。最初技术选型时,有同事图省事直接拉起了一个 Ollama 容器,结果压力测试刚走到 5 个并发,首字延迟(TTFT)直接飙到了 6 秒开外,日志里全是请求排队超时。Ollama 拿来单人开发玩具还行,真要放到多智能体协作、高并发 API 代理场景下,其吞吐调度与动态批处理能力根本支撑不住。
为了榨干机架上那台双卡 RTX 4090(24G × 2)服务器的全部性能,我花了一个周末推倒重构,基于 vLLM 推理引擎 + LiteLLM 统一网关 搭建了一套工业级的本地大模型服务架构。本文直接抛弃那些泛泛而谈的理论,把整套实战拓扑、核心参数调优、多卡 NCCL 避坑指南以及真实压测数据完整复盘。
一、底层硬件拓扑与驱动避坑
在 Linux 环境下玩多卡消费级显卡(如 RTX 3090 / 4090),最大的深坑就是 PCIe 通道瓶颈 和 NVIDIA P2P 通信限制 。由于 4090 硬件层面移除了 NVLink 接口,双卡间的数据交换全靠 PCIe 总线,直接跑张量并行(Tensor Parallelism)极容易出现 NCCL 报错卡死。
在开始配置前,务必先在宿主机确认两张卡的 PCIe 拓扑关系:
nvidia-smi topo -m
如果输出结果中两张卡之间显示为 SYS 或 NODE,说明跨了 CPU 根复合体。在启动任何基于 PyTorch/NCCL 的分布式服务前,必须强行在环境变量中放开 P2P 限制,否则 vLLM 在初始化 NCCL 线程池时会直接无提示崩溃:
# 写入 /etc/profile 或容器环境变量
export NCCL_P2P_DISABLE=1
export NCCL_IB_DISABLE=1
export CUDA_DEVICE_ORDER=PCI_BUS_ID
export CUDA_VISIBLE_DEVICES=0,1
二、vLLM 高性能推理引擎部署实战
以目前开源界综合能力极强、适合做基座的 Qwen2.5-32B-Instruct-AWQ(4-bit 量化版,完美塞入双卡 48G 显存)为例。我们通过 Docker 直接拉取官方镜像,避免宿主机 Python 环境污染。
以下是我实测最稳定的生产级启动命令:
docker run -d --gpus all \
--name vllm-qwen32b \
--restart always \
--shm-size 16g \
-p 8000:8000 \
-e NCCL_P2P_DISABLE=1 \
-v /data/models:/models \
vllm/vllm-openai:v0.6.3.post1 \
--model /models/Qwen2.5-32B-Instruct-AWQ \
--served-model-name qwen2.5-32b \
--tensor-parallel-size 2 \
--max-model-len 16384 \
--gpu-memory-utilization 0.92 \
--max-num-seqs 64 \
--enforce-eager \
--enable-prefix-caching
关键参数解析与踩坑心得:
--tensor-parallel-size 2:将模型切分到 2 张 GPU 上,利用张量并行降低单卡显存开销并加速矩阵乘法。--gpu-memory-utilization 0.92:默认是 0.9。对于 4-bit 模型,将此值调高至 0.92 能为 vLLM 的 PagedAttention 预留更多显存作为 KV Cache 池。但切勿设为 0.98,极易引发 CUDA OOM 崩溃。--max-num-seqs 64:限制单次 Iteration 最大并发吞吐批次。数值越大,总吞吐(Tokens/s)越高,但单请求的首字延迟会略微增加,64 是我在业务实测中的甜点位。--enable-prefix-caching:极度重要!对于多轮对话、Agent 预设 System Prompt 场景,开启后命中前缀缓存能直接让首字生成延迟降低 70% 以上,省去了重复计算 Prompt 的开销。--enforce-eager:4090 上如果开启 CUDA Graph(默认模式),在部分长上下文场景下显存容易产生碎片溢出。加上该参数能禁用 CUDA Graph,换取极佳的稳定性,性能损失不足 3%。
三、使用 LiteLLM 搭建生产级 API 网关
直接把 vLLM 的 8000 端口暴露给上游应用是不明智的:没有 API Key 权限隔离、没有速率限制、无法针对流式输出(SSE)做断流重试,更无法在本地显卡爆显存时自动无缝降级切回云端接口(如 DeepSeek-V3 云端 API)。
这时候,LiteLLM 是我试过最轻量且强大的中间层代理。它原生兼容 OpenAI 接口规范,并且支持细粒度的路由与负载均衡。
创建 litellm-config.yaml 配置文件:
model_list:
# 本地部署的 vLLM 主模型
- model_name: local-qwen32b
litellm_params:
model: openai/qwen2.5-32b
api_base: http://192.168.1.100:8000/v1
api_key: "none"
tpm: 100000
rpm: 600
# 备用降级路由:公有云 DeepSeek
- model_name: fallback-deepseek
litellm_params:
model: openai/deepseek-chat
api_base: https://api.deepseek.com/v1
api_key: "sk-your-real-key"
router_settings:
routing_strategy: "usage-based-routing"
timeout: 30
num_retries: 2
fallbacks:
- local-qwen32b: ["fallback-deepseek"]
general_settings:
master_key: "sk-nassky-master-key-admin"
database_url: "sqlite:////data/litellm.db"
利用 Docker Compose 迅速将 LiteLLM 与可视化管理面板拉起:
services:
litellm:
image: ghcr.io/berriai/litellm:main-latest
container_name: litellm-proxy
restart: always
ports:
- "4000:4000"
volumes:
- ./litellm-config.yaml:/app/config.yaml
- ./data:/data
command: ["--config", "/app/config.yaml", "--port", "4000", "--detailed_debug"]
启动后,任何上游应用(LangChain、Dify、NextChat、Cursor)只需将 Base URL 改为 http://<IP>:4000/v1,即可像调用云端 API 一样使用本地算力,并享受超时自动降级与 API Key 配额管理功能。
四、实测压测与性能对比
为了用数据说明“为什么坚决不用 Ollama 扛业务”,我使用 Python 编写并发压测脚本,针对双卡 4090 部署的 Qwen2.5-32B-Instruct-AWQ 分别在 Ollama 和 vLLM 下进行了 20 客户端并发测试(输入 512 Tokens,限制输出 256 Tokens)。
| 指标维度 | Ollama (默认配置) | vLLM (PagedAttention + TP2) | 性能提升幅度 |
|---|---|---|---|
| 平均首字延迟 (TTFT) | 4,820 ms | 380 ms | 降低约 92% |
| 整机生成吞吐 (Tokens/s) | 22.4 tps | 186.5 tps | 提升超 8 倍 |
| 并发排队失败率 | 35% (超时熔断) | 0% | 完全无丢包 |
实测可以明显看出,在并发到达一定数量级时,vLLM 的连续批处理(Continuous Batching)机制将 GPU 的 Tensor Core 算力吃满,多请求之间可以拼单推理,而不会像 Ollama 那样陷入漫长的排队死锁。
五、不可忽视的三个运维暗坑
1. 内存共享(/dev/shm)不足导致 Worker 诡异挂掉
很多朋友部署 Docker 时不注意 --shm-size,默认只有 64MB。vLLM 在多卡张量并行时需要使用共享内存同步张量。如果没指定,容器会在推理长上下文时直接抛出 Bus error (core dumped)。请务必显式指定 --shm-size 16g 以上。
2. FastChat/OpenAI 客户端流式输出卡顿(Broken Pipe)
LiteLLM 反向代理 vLLM 时,如果上游网络闪断或客户端主动取消请求,底层 vLLM 默认可能继续生成完所有 Tokens,造成无意义的算力浪费。在 vLLM 启动参数中务必确保不要关闭连接感知;而在 LiteLLM 中,推荐配置较低的 stream_timeout: 10 快速回收后端显存资源。
3. 量化格式的选择陷阱:AWQ 还是 GPTQ?
在 NVIDIA Ada Lovelace 架构(RTX 40 系)上, 首选 AWQ。我在实测中发现,GPTQ-Int4 模型在当前主流 vLLM 版本中的解码延迟比 AWQ 高出约