同一张 RTX 4090、同一个 Qwen2.5-7B,吞吐能差 22 倍,首字延迟能差 215 倍 —— 全看你怎么发请求。
这一阶段做了两件事:先从模型结构把关键常数算出来,再用压测逐一验证。
| 算 | 1 份逐层结构拆解:76 亿参数摊开,推出每 token 的 KV 占用(56 KiB)和计算量 |
| 测 | 10 组压测、7,594 条请求,vLLM 与 llama.cpp 对比,两轮跨机器独立复现 |
| 对账 | 手算的 KV 池容量与 vLLM 启动日志差 0.03%,KV 占用的线性拟合与理论差 0.045% |
| 问题 | 答案 | 报告 |
|---|---|---|
| 这张卡能扛多少并发? | 不用压测,可以算:KV 池 ÷(每 token 56 KiB × 上下文长度)。实测与理论差 0.045% | KV 的线性 |
| 并发加到多少开始亏? | 吞吐到 64 并发都还在涨,但从 8 并发起,延迟尾部就裂开了(p99 ITL 17.6 → 102.1 ms) | 并发曲线 |
| 首字延迟慢,该换卡吗? | 不该。过载时 98.9% 的首字延迟是在排队,真正计算只要 1.1 秒。要的是限流,不是更快的卡 | TTFT 解剖 |
| 显存(KV 池)压爆会怎样? | 超卖 4.4 倍、抢占 38 次,零失败,输出一个 token 不少。代价全部记在延迟上 | 断崖 |
| 量化省下了什么? | 省字节(单流快 2.71 倍),省不了调度(64 并发时 roofline 达成率 vLLM 81% vs llama.cpp 25%) | llama.cpp 压测 |
| 选 vLLM 还是 llama.cpp? | 看延迟预算,不看并发数:p99 首字延迟要求比 730 ms 紧选 llama.cpp,比它松选 vLLM | 选型指南 |
还有两条反直觉的观察:
报告是自包含的单页 HTML,经 GitHub Pages 渲染,点开即读。
先读理论底座: Qwen2.5-7B 结构拆解 —— 后面所有压测用到的两个常数(每 token 56 KiB 的 KV、每 token 13–14 GFLOP)都是在这里从模型结构算出来的。
第二轮压测(最终版,建议从 06 读起):
| # | 报告 | 一句话 |
|---|---|---|
| 06 | 选型指南 | 分界线是 p99 首字延迟 ≈ 730 ms,不是并发数 |
| 01 | 并发曲线 | 拐点在 8 并发,卡住它的是调度器而不是显存 |
| 02 | TTFT 解剖 | 首字延迟拆成排队 / prefill / 前端三段,排队是主因 |
| 03 | KV 的线性 | KV 占用严格线性(R²=0.99993),容量可以算 |
| 04 | 断崖 | 超卖 4.4 倍仍零失败,抢占是一个稳定的控制环 |
| 05 | llama.cpp 压测 | 量化让单流快 2.71 倍,但批处理效率差 3 倍多 |
第一轮保留了全过程,包括后来被第二轮修正的判断: 并发曲线 · TTFT 解剖 · KV 的线性 · 断崖 · llama.cpp 与选型
p99 TTFT < X 写进配置文档,比写 max-num-seqs = N 有意义得多。Maximum concurrency for N tokens per request 那一行,两轮实测只比它高 5–7%。--max-model-len 比加卡便宜。 8192 → 4096,可同时驻留的请求数直接翻倍。--max-num-seqs 设成真实容量。 留着默认值 128,调度器会先放进太多请求、再靠抢占踢出去 —— 38 次抢占全是这么来的。ITL p50(解码健不健康)、waiting 队列长度(容量够不够)、num_preemptions_total(有没有在白白重算)。一句话诊断:ITL 正常、TTFT 爆炸 → 容量不够在排队;ITL 也慢 → 解码本身有问题。
--ignore-eos 在两个引擎上行为不一致(工作量差 1.35%)。Results/。完整命令串(开机 → 装环境 → 起服务 → 验证 → 压测 + 采样 → 切换引擎 → 收工)见
Scripts/第二轮测试脚本.md。三条关键规矩:
--temperature 0、--random-range-ratio 0、每档独立 seed。01-decode-latency-anatomy/
├── Reports/ 12 份 HTML:结构拆解 + 第二轮 6 份 + 第一轮 5 份
├── Results/ 原始数据,94 个文件,一条没删
└── Scripts/ 第二轮测试脚本.md(可复制粘贴)
| GPU | NVIDIA RTX 4090 · 24 GB(vast.ai 按小时租用)· CUDA 13.0 |
| 模型 | Qwen2.5-7B-Instruct(vLLM 用 bf16,llama.cpp 用 Q4_K_M) |
| 引擎 | vLLM 0.27.1(V1 engine)· llama.cpp eab8ee41f |
| 负载 | 1024 输入 / 256 输出(主线)· 输入 256→4096 扫描 · 6144 / 2048 过载 |