目录
- 一、推理性能基础
- 二、性能瓶颈分析
- 三、KV Cache 优化
- 四、连续批处理(Continuous Batching)
- 五、量化技术
- 六、推测解码(Speculative Decoding)
- 七、注意力优化
- 八、推理引擎对比
- 九、vLLM 实战
- 十、TensorRT-LLM 实战
- 十一、SGLang 与 LMDeploy
- 十二、分布式推理
- 十三、性能基准测试
- 十四、生产部署
- 十五、常见问题
一、推理性能基础
1.1 关键指标
| 指标 | 含义 | 关注场景 |
|---|---|---|
| TTFT (Time To First Token) | 首 token 延迟 | 交互式对话 |
| TPOT (Time Per Output Token) | 单 token 生成时间 | 流式输出体验 |
| Throughput | 总吞吐(tokens/s) | 批处理/服务化 |
| Goodput | SLA 内有效吞吐 | 生产服务 |
| QPS | 每秒请求数 | 容量规划 |
1.2 推理两阶段
┌────────────┐ ┌────────────────┐
│ Prefill │ ──────> │ Decode │
│ (并行处理 │ │ (逐 token │
│ prompt) │ │ 生成) │
└────────────┘ └────────────────┘
compute-bound memory-bound
GPU 利用率高 GPU 利用率低
- Prefill:一次处理整个 prompt,矩阵乘充分并行 → 计算密集
- Decode:每次只生成 1 token,瓶颈在显存带宽 → 内存密集
这是为什么 decode 阶段 GPU 利用率常常只有 20-30%。
1.3 显存占用估算
7B 模型 FP16 推理:
| 部分 | 大小 |
|---|---|
| 权重 | 7B × 2 bytes = 14 GB |
| KV Cache (per token) | 约 0.5 MB |
| 激活值 | ~1-2 GB |
| 总计 (空载) | ~16 GB |
KV Cache 公式:
2 × num_layers × num_kv_heads × head_dim × seq_len × dtype_bytes
8K 上下文的 7B 模型 KV Cache 约 4 GB。
二、性能瓶颈分析
2.1 Roofline 模型
吞吐 = min(
计算上限 (FLOPS),
访存上限 (BW × 算术强度)
)
| 阶段 | 主要瓶颈 | 优化方向 |
|---|---|---|
| Prefill | 算力 | FlashAttention、并行度、量化 |
| Decode | 显存带宽 | KV Cache 复用、量化、batching |
2.2 工具
# 实时 GPU 监控
nvidia-smi dmon -s pucvmet
# Nsight Systems 性能分析
nsys profile -o report python infer.py
# PyTorch profiler
torch.profiler.profile(activities=[ProfilerActivity.CUDA])
2.3 瓶颈定位 checklist
- GPU 利用率 < 80%?→ batching 不够 / I/O 瓶颈
- 显存带宽接近峰值?→ decode 受限,考虑量化
- TTFT 高 / TPOT 低?→ prefill 慢,prompt 太长,加 chunked prefill
- 内存碎片严重?→ 启用 PagedAttention
三、KV Cache 优化
3.1 PagedAttention(vLLM 核心)
类比操作系统虚拟内存分页,把 KV Cache 切成固定大小的 block,按需分配:
传统:连续显存分配 → 碎片严重,浪费 60-80%
分页:固定 block → 几乎零碎片,2-4× 吞吐
3.2 Prefix Caching(前缀缓存)
相同 system prompt / few-shot 前缀复用 KV Cache:
# vLLM
from vllm import LLM
llm = LLM(model="...", enable_prefix_caching=True)
收益:长 system prompt 场景下 TTFT 降低 80%+。
3.3 KV Cache 量化
将 KV cache 从 FP16 量化到 FP8/INT4:
llm = LLM(model="...", kv_cache_dtype="fp8")
- FP8:精度损失小,显存减半
- INT4:再减半,精度损失可控(用 scale)
3.4 跨请求共享(RadixAttention)
SGLang 的 RadixTree 索引相同前缀,多用户多轮场景效果显著。
四、连续批处理(Continuous Batching)
4.1 静态批处理 vs 连续批处理
静态批处理(GPU 利用率低):
[req1: ████████████░░░░░░] ← req2 完成后必须等待 req1
[req2: ████░░░░░░░░░░░░░░]
[req3: ░░░░░░░░░░░░░░░░░░] ← 必须等本批结束才能加入
连续批处理(vLLM):
[req1: ████████████]
[req2: ████] [req4: █████] ← 完成立即被替换
[req3: ████████]
4.2 In-Flight Batching(TensorRT-LLM)
每一步迭代动态调整 batch 成员,已完成请求立即释放,新请求即时加入。
4.3 调度参数
LLM(
max_num_seqs=256, # 最大并发序列数
max_num_batched_tokens=8192, # 每步最多 token 数
max_model_len=4096,
)
调优经验:
max_num_batched_tokens太小 → prefill 慢- 太大 → OOM
- 通常设为 2×
max_model_len
五、量化技术
5.1 量化方法对比
| 方法 | 精度 | 速度 | 训练成本 | 适用 |
|---|---|---|---|---|
| FP16/BF16 | 100% | 1× | - | 基线 |
| FP8 (E4M3) | ~99% | 1.5-2× | 无 | H100/H200 |
| INT8 | ~98% | 1.5-2× | 校准 | 通用 |
| GPTQ (W4) | ~97% | 2-3× | 校准 | 离线压缩 |
| AWQ (W4) | ~97% | 2-3× | 校准 | 推荐 |
| GGUF (Q4_K) | ~96% | 2-3× | 转换 | CPU/Mac |
| INT4 | ~95% | 3-4× | 校准 | 极致压缩 |
5.2 GPTQ 量化
pip install auto-gptq
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
quant_config = BaseQuantizeConfig(
bits=4, group_size=128,
damp_percent=0.01, desc_act=False,
)
model = AutoGPTQForCausalLM.from_pretrained("meta-llama/Llama-3-8B", quant_config)
model.quantize(calibration_data)
model.save_quantized("./llama3-8b-gptq-w4")
5.3 AWQ 量化(推荐)
pip install autoawq
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer
model = AutoAWQForCausalLM.from_pretrained("meta-llama/Llama-3-8B")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3-8B")
quant_config = {"zero_point": True, "q_group_size": 128, "w_bit": 4, "version": "GEMM"}
model.quantize(tokenizer, quant_config=quant_config)
model.save_quantized("./llama3-8b-awq")
AWQ 在大多数任务上略优于 GPTQ。
5.4 FP8(H100/H200 专属)
# vLLM
llm = LLM(model="...", quantization="fp8")
# TensorRT-LLM
trtllm-build --quant_mode fp8 ...
5.5 GGUF(llama.cpp 生态)
# 转换
python convert.py model.bin --outtype f16 --outfile model.f16.gguf
./quantize model.f16.gguf model.q4_k.gguf q4_k_m
# 推理
./main -m model.q4_k.gguf -p "Hello"
六、推测解码(Speculative Decoding)
6.1 原理
用一个小模型 (draft) 先生成 N 个候选 token,再用大模型 (target) 一次性验证。被接受的部分免费,省去多次 decode。
Draft (1B): 生成 4 token → "the cat sat on"
Target (70B): 并行验证 → 接受 3 个 (前 3 正确)
最终: 一次 decode 步等于 3-4 个 token
6.2 加速比
- 任务越"可预测"(代码、JSON)加速越大:2-4×
- 创意写作较小:1.3-1.8×
6.3 vLLM 配置
llm = LLM(
model="meta-llama/Llama-3-70B",
speculative_config={
"model": "meta-llama/Llama-3.2-1B", # draft
"num_speculative_tokens": 5,
},
)
6.4 EAGLE / Medusa(无需独立 draft 模型)
- EAGLE:训练一个小的特征预测 head,复用主模型隐状态
- Medusa:多个 head 并行预测多 token
vLLM 支持:
speculative_config={"method": "eagle3", "model": "yuhuili/EAGLE3-LLaMA3.1-Instruct-8B"}
七、注意力优化
7.1 FlashAttention
- v1:减少 HBM 读写
- v2:更好并行度
- v3:H100 上利用 TMA + WGMMA,Hopper 专属
# 大多数引擎默认启用,PyTorch 中:
import torch
torch.nn.functional.scaled_dot_product_attention(q, k, v) # 自动用 flash
7.2 Grouped-Query Attention (GQA)
多个 Q head 共享 KV head:
| 模型 | KV head |
|---|---|
| Llama-3-8B | 8 (32 Q) |
| Llama-3-70B | 8 (64 Q) |
KV Cache 减少 4-8×,几乎无精度损失。新模型设计标配。
7.3 MLA(Multi-head Latent Attention)
DeepSeek 提出,把 KV 投影到低秩潜在空间,KV Cache 再缩 5-10×。
7.4 Sliding Window Attention
仅关注最近 N token(Mistral 4K 窗口):
config.sliding_window = 4096
适合长文本但不需全局注意的场景。
7.5 Chunked Prefill
将长 prompt 切块逐步 prefill,与 decode 交错调度,降低 TTFT 抖动:
LLM(model="...", enable_chunked_prefill=True, max_num_batched_tokens=2048)
八、推理引擎对比
| 引擎 | 主推 | 强项 | 弱项 |
|---|---|---|---|
| vLLM | 通用 | PagedAttention、社区活跃 | TRT 不及在 NVIDIA 上的极致 |
| TensorRT-LLM | NVIDIA | 极致延迟、FP8 | 编译复杂、依赖重 |
| SGLang | 通用 | RadixAttention、structured output | 较新 |
| LMDeploy | 国产 | 中文模型友好、TurboMind 内核 | 生态规模小于 vLLM |
| llama.cpp | CPU/Mac | 无 GPU、GGUF | 不适合大并发 |
| HuggingFace TGI | 通用 | 集成 HF 生态 | 性能弱于 vLLM |
| MLC-LLM | 移动/Web | 跨设备、WebGPU | 调优门槛高 |
8.1 选择建议
是否要求极致延迟(金融/广告)?─→ TensorRT-LLM
│
否
│
是否需要 structured output?──→ SGLang
│
否
│
是否中文模型为主?───────────→ LMDeploy
│
否
│
→ vLLM (默认推荐)
九、vLLM 实战
pip install vllm
9.1 离线推理
from vllm import LLM, SamplingParams
llm = LLM(
model="meta-llama/Llama-3-8B-Instruct",
tensor_parallel_size=2,
dtype="bfloat16",
gpu_memory_utilization=0.90,
max_model_len=8192,
enable_prefix_caching=True,
)
params = SamplingParams(temperature=0.7, max_tokens=512)
outputs = llm.generate(["你好,介绍一下你自己"], params)
print(outputs[0].outputs[0].text)
9.2 OpenAI 兼容 API
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3-8B-Instruct \
--tensor-parallel-size 2 \
--port 8000 \
--max-model-len 8192 \
--enable-prefix-caching \
--gpu-memory-utilization 0.90
调用:
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
resp = client.chat.completions.create(
model="meta-llama/Llama-3-8B-Instruct",
messages=[{"role": "user", "content": "你好"}],
)
9.3 高吞吐配置
--max-num-batched-tokens 16384 \
--max-num-seqs 256 \
--enable-chunked-prefill \
--quantization fp8 \
--kv-cache-dtype fp8
9.4 LoRA 多租户
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3-8B \
--enable-lora \
--lora-modules sql=/lora/sql math=/lora/math
9.5 关键参数速查
| 参数 | 含义 | 默认 |
|---|---|---|
gpu_memory_utilization | 占用 GPU 显存比例 | 0.9 |
max_num_seqs | 最大并发序列 | 256 |
max_num_batched_tokens | 单步最大 token | auto |
tensor_parallel_size | TP 并行度 | 1 |
pipeline_parallel_size | PP 并行度 | 1 |
enable_prefix_caching | 前缀缓存 | False |
enable_chunked_prefill | 分块 prefill | False |
quantization | 量化 | None |
kv_cache_dtype | KV 量化 | auto |
swap_space | CPU offload (GB) | 4 |
十、TensorRT-LLM 实战
10.1 安装
pip install tensorrt-llm
# 或使用 NGC 镜像
docker pull nvcr.io/nvidia/tensorrt-llm/release:latest
10.2 编译模型
# 1. 转换 HF 模型 → TRT-LLM 中间格式
python convert_checkpoint.py \
--model_dir ./Llama-3-8B \
--output_dir ./trtllm_ckpt \
--dtype bfloat16 \
--tp_size 2
# 2. 构建引擎
trtllm-build \
--checkpoint_dir ./trtllm_ckpt \
--output_dir ./trtllm_engines \
--gemm_plugin bfloat16 \
--max_batch_size 64 \
--max_input_len 4096 \
--max_output_len 1024 \
--use_paged_context_fmha enable \
--use_fp8_context_fmha enable
10.3 推理
from tensorrt_llm import LLM, SamplingParams
llm = LLM(model="./trtllm_engines")
out = llm.generate(["Hello"], SamplingParams(max_tokens=100))
10.4 关键优化
--use_paged_context_fmha:分页上下文 attention--use_fp8_context_fmha:FP8 attention(H100)--multi_block_mode:长序列优化--use_custom_all_reduce:自定义 NCCL all-reduce
10.5 Triton 部署
# 拉取 Triton 镜像
docker pull nvcr.io/nvidia/tritonserver:24.09-trtllm-python-py3
# 启动
tritonserver --model-repository=/models
十一、SGLang 与 LMDeploy
11.1 SGLang
pip install "sglang[all]"
python -m sglang.launch_server \
--model meta-llama/Llama-3-8B-Instruct \
--tp 2 \
--enable-radix-cache \
--port 30000
特色:
- RadixAttention:跨请求共享前缀 KV
- Structured output:内置 grammar/regex/json schema 约束
- Constrained decoding 性能优于其他引擎
from openai import OpenAI
client = OpenAI(base_url="http://localhost:30000/v1", api_key="x")
# JSON Schema 约束
client.chat.completions.create(
model="...",
messages=[...],
extra_body={"response_format": {
"type": "json_schema",
"json_schema": {"schema": {...}}
}},
)
11.2 LMDeploy
pip install lmdeploy
lmdeploy serve api_server \
internlm/internlm2-chat-7b \
--backend turbomind \
--tp 2 \
--quant-policy 8 \
--server-port 23333
特色:
- TurboMind 内核:中文模型 (InternLM/Qwen) 性能优秀
- W4A16 量化:精度+速度平衡好
- PyTorch backend:兼容性好
十二、分布式推理
12.1 并行策略
| 策略 | 切分 | 通信 | 适用 |
|---|---|---|---|
| TP(Tensor Parallel) | 层内权重 | All-Reduce 频繁 | 单机多卡 |
| PP(Pipeline Parallel) | 层间 | 阶段流水 | 跨机 |
| EP(Expert Parallel) | MoE 专家 | All-to-All | MoE 模型 |
| DP(Data Parallel) | 请求维度 | 无 | 横向扩展 |
| SP(Sequence Parallel) | 序列维度 | 长序列 | 长上下文 |
12.2 选择策略
单机 8×H100,70B 模型 → TP=8
多机 70B 模型 → TP=8 + PP=2
MoE 模型 → TP + EP
吞吐扩展 → DP 多副本
12.3 vLLM 多机部署
# 节点 0
ray start --head --port=6379
# 节点 1+
ray start --address='HEAD_IP:6379'
# 启动
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3-70B \
--tensor-parallel-size 8 \
--pipeline-parallel-size 2
12.4 NCCL 调优
export NCCL_IB_DISABLE=0 # 启用 InfiniBand
export NCCL_NET_GDR_LEVEL=2 # GPUDirect RDMA
export NCCL_P2P_DISABLE=0 # 启用 P2P
export NCCL_DEBUG=INFO # 排错时
十三、性能基准测试
13.1 vLLM benchmark
python benchmarks/benchmark_serving.py \
--backend vllm \
--model meta-llama/Llama-3-8B-Instruct \
--dataset-name sharegpt \
--dataset-path ShareGPT_V3.json \
--num-prompts 1000 \
--request-rate 16
13.2 自定义 benchmark
import asyncio, time, statistics, httpx
async def bench(url, prompt, n_concurrent=32, n_requests=200):
sem = asyncio.Semaphore(n_concurrent)
latencies = []
async def one():
async with sem:
t0 = time.perf_counter()
async with httpx.AsyncClient(timeout=120) as c:
r = await c.post(url, json={
"model": "...", "messages": [{"role": "user", "content": prompt}],
"max_tokens": 256, "stream": False,
})
latencies.append(time.perf_counter() - t0)
t0 = time.perf_counter()
await asyncio.gather(*[one() for _ in range(n_requests)])
total = time.perf_counter() - t0
print(f"QPS: {n_requests/total:.2f}")
print(f"Latency p50/p95/p99: "
f"{statistics.median(latencies):.2f}/"
f"{statistics.quantiles(latencies, n=20)[18]:.2f}/"
f"{statistics.quantiles(latencies, n=100)[98]:.2f}s")
asyncio.run(bench("http://localhost:8000/v1/chat/completions", "你好"))
13.3 关键测试维度
- 并发:1, 8, 32, 128, 256
- prompt 长度:128, 1k, 4k tokens
- 生成长度:128, 512, 2048 tokens
- 混合负载:模拟真实分布(ShareGPT/long-tail)
13.4 SLA 指标
TTFT p99 < 500ms
TPOT p99 < 50ms (即 20 tok/s/请求)
Throughput > 1000 tok/s/GPU
十四、生产部署
14.1 Dockerfile
FROM nvcr.io/nvidia/pytorch:24.09-py3
RUN pip install vllm==0.6.3
COPY entrypoint.sh /
EXPOSE 8000
CMD ["/entrypoint.sh"]
#!/bin/bash
exec python -m vllm.entrypoints.openai.api_server \
--model "$MODEL_PATH" \
--tensor-parallel-size "${TP:-2}" \
--max-model-len "${MAX_LEN:-8192}" \
--gpu-memory-utilization 0.90 \
--enable-prefix-caching
14.2 K8s 部署
apiVersion: apps/v1
kind: Deployment
metadata: { name: vllm }
spec:
replicas: 2
selector: { matchLabels: { app: vllm } }
template:
metadata: { labels: { app: vllm } }
spec:
containers:
- name: vllm
image: registry/vllm:latest
resources:
limits:
nvidia.com/gpu: "2"
memory: 64Gi
env:
- { name: MODEL_PATH, value: /models/llama3-8b }
- { name: TP, value: "2" }
volumeMounts:
- { name: models, mountPath: /models }
- { name: shm, mountPath: /dev/shm }
readinessProbe:
httpGet: { path: /health, port: 8000 }
initialDelaySeconds: 120
volumes:
- { name: models, persistentVolumeClaim: { claimName: model-pvc } }
- { name: shm, emptyDir: { medium: Memory, sizeLimit: 16Gi } }
14.3 自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: vllm }
spec:
scaleTargetRef: { kind: Deployment, name: vllm }
minReplicas: 2
maxReplicas: 10
metrics:
- type: Pods
pods:
metric: { name: vllm:num_requests_running }
target: { type: AverageValue, averageValue: "200" }
14.4 灰度发布
- 蓝绿:新旧模型并行,流量切换
- A/B:基于 user-id 哈希分流
- 金丝雀:1% → 10% → 100%
14.5 模型加载加速
# safetensors 加载比 .bin 快 3-5×
# 用 NVMe 本地盘缓存 HF 模型
HF_HOME=/local-nvme/hf-cache vllm serve ...
# Tensorizer 进一步加速
from tensorizer import TensorSerializer, TensorDeserializer
十五、常见问题
15.1 OOM
- 降低
gpu_memory_utilization到 0.85 - 减小
max_model_len - 启用 KV cache 量化(
kv_cache_dtype=fp8) - 减小
max_num_seqs
15.2 TTFT 太高
- 启用
enable_chunked_prefill - 启用
enable_prefix_caching(system prompt 较长时) - 减少
max_num_batched_tokens(避免 prefill 排队过久)
15.3 吞吐上不去
- GPU 利用率 < 70% → 加大 batch
- 利用率 > 95% → 上 TP / 加卡 / 量化
- I/O 瓶颈 → tokenizer 进程化、HTTP 连接池
15.4 长尾延迟(p99 高)
- 启用 chunked prefill
- 隔离长请求(独立 endpoint)
- 限制
max_tokens
15.5 输出质量下降
量化/draft 模型可能引入精度损失:
- 跑 lm-eval-harness 验证
- AWQ 一般优于 GPTQ
- speculative 仅影响速度,不影响输出(数学等价)
15.6 多机 NCCL 卡死
- 检查所有节点 IB 网络互通
NCCL_DEBUG=INFO看具体卡在哪步- 防火墙是否阻断
15.7 显存碎片导致逐渐变慢
- 用 PagedAttention 引擎(vLLM/TRT-LLM)
- 定期重启 worker
附录:速查
A.1 加速手段优先级
- 量化(FP8/AWQ)→ 显存减半,速度 1.5-2×
- prefix caching → system prompt 重的场景,TTFT 大降
- continuous batching → 默认开(vLLM/TRT-LLM)
- chunked prefill → 长 prompt 平滑 TTFT
- speculative decoding → 进一步 1.5-3× 解码加速
- TP/PP → 模型放不下时再考虑
A.2 不同规模选型
| 规模 | 推荐 |
|---|---|
| 7-13B | vLLM + AWQ + 1×A10/A100 |
| 30-70B | vLLM TP=4 + FP8 + 4×A100/H100 |
| 100B+ | TRT-LLM TP=8 + PP,多机 |
| MoE | SGLang/vLLM + EP |
A.3 关键环境变量
CUDA_VISIBLE_DEVICES=0,1
NCCL_IB_DISABLE=0
VLLM_WORKER_MULTIPROC_METHOD=spawn
HF_HUB_OFFLINE=1 # 避免每次启动联网
A.4 资源链接
- vLLM:docs.vllm.ai
- TensorRT-LLM:nvidia.github.io/TensorRT-LL…
- SGLang:docs.sglang.ai
- LMDeploy:lmdeploy.readthedocs.io
- llama.cpp:github.com/ggml-org/ll…