这是我们在 H100 套餐的 vLLM 模板中使用的配置,这里按步骤完整写出,方便您在干净的 Ubuntu 镜像上复现,或按自己的需要改造。目标是一个接近生产环境的接口:在单张 80 GB 的 H100 上以 FP8 精度运行 Llama 3.1 70B Instruct,通过带 API 密钥的反向代理提供兼容 OpenAI 的 API,并做足够的测量,以便判断何时该加第二张卡。
一张 H100 能装下什么
80 GB 的显卡只有在权重经过量化的前提下,才装得下 70B 模型。以 FP8 计,Llama 3.1 70B 的权重约为 70 GB,扣除 CUDA 和 vLLM 的开销后,留给 KV 缓存的只有大约 8 GB。这足够在 32k 上下文下支撑少数几个并发序列,或者在 8k 上下文下支撑 40 个左右。如果您在 70B 上既需要长上下文又需要高并发,就要用两张 H100 做张量并行;如果两者都不需要,那么在 RTX 5090 上运行 8B 或 14B 模型,成本只是零头,响应还更快。
| 模型 | 精度 | 权重 | 剩余 KV 缓存(80 GB) | 8k 上下文下可从容承载的并发数 |
|---|---|---|---|---|
| Llama 3.1 8B | BF16 | 16 GB | ~58 GB | 200+ |
| Qwen2.5 32B | FP8 | 33 GB | ~41 GB | ~120 |
| Llama 3.1 70B | FP8 | 70 GB | ~8 GB | ~40 |
| Llama 3.1 70B | BF16 | 140 GB | 装不下 | 至少 2× H100 |
基础系统
从 Ubuntu 24.04 · CUDA 12.8 · driver 570 基础镜像开始。先确认显卡和驱动正常,再安装 Python 环境。我们使用 uv,因为它解析 CUDA wheel 包只需要几秒钟。
nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv /opt/vllm && source /opt/vllm/bin/activate
uv pip install vllm==0.6.6 huggingface_hub[cli]
使用已接受 Llama 许可协议的令牌登录 Hugging Face,并把权重预先下载到持久化存储卷上,这样重装系统时就不必再白白传输 70 GB 数据:
huggingface-cli login
huggingface-cli download neuralmagic/Meta-Llama-3.1-70B-Instruct-FP8 --local-dir /data/models/llama-70b-fp8
真正重要的参数
vLLM 有上百个参数,其中五个决定了这台服务的好坏。
vllm serve /data/models/llama-70b-fp8 \
--served-model-name llama-3.1-70b \
--max-model-len 16384 \
--gpu-memory-utilization 0.95 \
--max-num-seqs 48 \
--enable-prefix-caching \
--host 127.0.0.1 --port 8000
--max-model-len决定为每个序列预留多少 KV 缓存。请把它设为您实际要处理的最长提示词长度,而不是模型支持的最大值;与 32k 相比,16k 能让每个序列槽位的内存占用减半。--gpu-memory-utilization 0.95在没有其他任务占用的显卡上是安全的。如果您还要让第二个进程共用这块 GPU,请保持默认值 0.9。--max-num-seqs限制并发序列数。设得太高,请求会在调度器内部排队,并出现很长的尾延迟;设得太低,显卡又会闲置。对于 16k 上下文的 70B FP8,建议从 48 起步,再根据监控指标调整。--enable-prefix-caching会为相同的提示词前缀复用 KV 块,而聊天请求中的系统提示词大多就属于这类前缀。它几乎没有额外开销,在聊天流量上往往能带来 20% 到 30% 的吞吐提升。--host 127.0.0.1:vLLM 本身没有认证机制,绝不能让它监听公网接口。
重启后依然能自动运行的 systemd 单元
cat > /etc/systemd/system/vllm.service <<'EOF'
[Unit]
Description=vLLM OpenAI-compatible server
After=network-online.target
[Service]
User=vllm
Environment=HF_HOME=/data/hf
ExecStart=/opt/vllm/bin/vllm serve /data/models/llama-70b-fp8 --served-model-name llama-3.1-70b --max-model-len 16384 --gpu-memory-utilization 0.95 --max-num-seqs 48 --enable-prefix-caching --host 127.0.0.1 --port 8000
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
useradd -r -d /data -s /usr/sbin/nologin vllm && chown -R vllm /data
systemctl daemon-reload && systemctl enable --now vllm
journalctl -fu vllm
从 NVMe 加载 70 GB 权重大约需要 90 秒。日志里出现 Uvicorn running on http://127.0.0.1:8000 这一行,就说明服务已经就绪。
带 API 密钥的反向代理
Caddy 会自动申请证书,并且只需三行配置就能校验 Bearer 令牌。请先把一条 DNS 记录指向这台服务器。
apt install -y caddy
cat > /etc/caddy/Caddyfile <<'EOF'
llm.example.com {
@noauth not header Authorization "Bearer CHANGE-ME-32-RANDOM-CHARS"
respond @noauth 401
reverse_proxy 127.0.0.1:8000 {
flush_interval -1
}
}
EOF
systemctl reload caddy
flush_interval -1 是让流式响应保持流式输出、而不被缓冲的关键。测试时使用 OpenAI SDK,把 base_url 设为 https://llm.example.com/v1,把 api_key 设为该令牌即可;客户端的其他部分都不需要改动。
实测数据
使用上述配置,在单张 H100 SXM 上,以 1,000 个 token 的提示词和 300 个 token 的生成长度测得:
| 并发请求数 | 输出 tokens/s(合计) | 首 token 延迟 | 单请求 tokens/s |
|---|---|---|---|
| 1 | 34 | 0.28 s | 34 |
| 8 | 230 | 0.41 s | 29 |
| 32 | 640 | 0.9 s | 20 |
| 48 | 720 | 1.6 s | 15 |
曲线在 40 到 48 个并发序列处趋于平缓;再往上,排队只会增加延迟。如果您的流量经常高于这个水平,下一步就是加上第二张 H100,并启用 --tensor-parallel-size 2,吞吐大约翻倍,同时也能运行 BF16 精度。
监控
vLLM 在 /metrics 上暴露 Prometheus 指标。值得设置告警的有三项:vllm:num_requests_waiting(等待请求数持续一分钟以上超过少数几个,就说明已经饱和)、vllm:gpu_cache_usage_perc(超过 90% 意味着序列正在被抢占)以及 p95 的 vllm:e2e_request_latency_seconds。如需监控显卡本身,可再加上 nvidia-smi dmon -s um 或 netdata 附加组件。
何时该升级
有三个信号说明这套配置已经超出了一张显卡的承载能力:等待请求数这项指标很少归零;产品需要在真实并发下支持 32k 上下文;或者您想同时提供两个模型的服务。这三种情况,2× 和 4× H100 套餐都能解决,同一个单元文件只需加上张量并行参数即可沿用。在那之前,这一张显卡以固定的月费,就能承载出乎意料多的流量。
