批处理与多用户
一次一个请求是每个桌面会话的起点——而它浪费一块 GPU。服务的全部游戏是批处理:让一次穿过权重的传播同时服务多个请求。本页覆盖为什么有效、连续批处理和页注意力实际是什么、何时需要真正的服务引擎、以及怎么配容量。
为什么串行服务浪费 GPU
回忆速度公式:每个解码词元读取 essentially 全部活跃权重一次(速度)。服务一条流时、GPU 为一个用户的一枚词元做整次读取。现在把八条流批进同一次前向传播:权重读一次、用于八个序列——额外算术几乎免费、因为解码受带宽约束而非算力约束。单流速度几乎不降而总吞吐几乎线性攀升、直到你饱和带宽或 KV 内存。那一个事实就是本地服务的全部经济学。
静态 vs 连续批处理
朴素版本——静态批处理——把同时到达的请求分组、跑整批直到每个成员完成。它有效、但糟糕:
| 静态批处理 | 连续批处理 | |
|---|---|---|
| 批的形成 | 一次、当组集齐时 | 每个解码步重新评估 |
| 中途加入 | 否——等下一批 | 是、槽位随请求到来填充 |
| 长批中的短请求 | 阻塞到最长的完成 | 立即完成并释放槽位 |
| 尾延迟 | 差(队头阻塞) | 好 |
连续(迭代级)批处理——vLLM 和 SGLang 的默认——就是那些引擎在真实流量下挺住而朴素服务器垮掉的原因。
页注意力:修复 KV 碎片
每个活跃请求需要 KV 缓存内存(见 KV 缓存)。老办法预先保留每个请求的最大上下文——于是用 2k 词元的聊天可能占着保留的 32k 块、锁死、别人用不了。KV 池大部分闲坐。页注意力以按需分配的固定大小块存储 KV、像 OS 给内存分页那样:浪费从多数(vLLM 作者在论文中报告 60–80%)掉到几个百分点、并发序列装下数倍、吞吐随之。同一想法、现在是服务引擎的标配。
对你的成本:用户侧什么都没有——它是一次分配器改动;你只是在同一 GPU 上看到更高的并发容量。
何时需要真正的服务引擎
| 工作负载 | 引擎 |
|---|---|
| 你加家人、几个顺序聊天 | Ollama / LM Studio——已经够好 |
| 几个开发者并发磨蹭 | 带并行槽位的 llama-server、或 Ollama 并行环境变量 |
| 产品流量、团队聊天、真实用户 | vLLM 或 SGLang |
| 共享长系统提示词的智能体机群 | SGLang(前缀缓存)或 vLLM |
本论坛的游戏角是最后一行的典范:国际象棋和 janggi 对局跑多个智能体、每个每秒左右请求一步——小提示词、多流、共享系统提示词。那正是想要带批处理的服务引擎、而不是循环跑 ollama run 的工作负载(见 智能体)。
吞吐 vs 延迟
每个旋钮都在两者间交易:更大批次抬高总 tok/s 同时略降单流速度、排队在负载下抬高 TTFT。一个人的编程助手要并发封在 1–2、让人的流永不排队。三十人的聊天服务要批次塞满。调优前先决定你是哪个(TTFT 与解码作为分开的测量见 服务)。
最接近免费午餐的是前缀缓存(SGLang):重复的长提示词变成近零预填充、而这正是多数智能体工作负载。
实用旋钮
# llama.cpp:并行解码槽位(上下文被切分到各槽位)
llama-server -m model.gguf -c 32768 -np 4
# Ollama:每模型并行请求数(设置后重启服务)
export OLLAMA_NUM_PARALLEL=4
# vLLM:要紧的那两个
vllm serve model --max-num-seqs 32 --gpu-memory-utilization 0.90
排队发生在所有这些的上游:每个槽位忙时、新请求等待。盯队列深度和 TTFT、不盯感觉。
上游也要设限:带连接上限的反向代理快速而诚实地失败、深队列缓慢而神秘地失败。
容量规划,粗略地
请求在权重之外的花费是 KV 缓存、逐词元、贯穿其整个上下文:
KV bytes/token ≈ 2 × layers × kv_heads × head_dim × bytes_per_value
算例,典型 8B 稠密模型(32 层、8 个 KV 头、头维度 128、fp16 值):
2 × 32 × 8 × 128 × 2 B ≈ 每词元 131 KB → 2k 词元的对话 ≈ 256 MiB 的 KV → 十个这样的聊天 ≈ 在 ~5 GB 权重之上再加 ~2.5 GB。
(那个 2 是 K 和 V;见 KV 缓存)。长上下文智能体因此每个请求远贵于聊天。粗略舒适表、重度对冲——聊天长度上下文、仅数量级:
| GPU | 模型 | 粗略并发轻聊天 |
|---|---|---|
| 8 GB | 7–8B Q4 | 1–3 |
| 24 GB | 8B Q4 | ~10–30 |
| 24 GB | 32B Q4 | ~3–8 |
| 48 GB | 70B Q4 | ~5–15 |
用你的真实提示词测:上下文长度比任何其他变量更能移动这些数字。
你饱和了的信号
- TTFT 随白天推进从毫秒爬到秒。
- 队列深度持续高于零;请求在首词元前等待。
- 批次塞紧时单流 tok/s 下垂。
- vLLM 日志显示抢占或 KV 重算——内存压力、不是模型慢。
任一出现:封上下文、量化 KV 缓存、或加 GPU——按这个便宜顺序——赶在用户大声抱怨之前。
跨一天画 TTFT 和队列深度——平稳爬升意味着容量、锯齿意味着你可用队列吸收的突发。
租 vs 买,速写
截至本文写作、租一台 24GB 级 GPU 大约 $0.50–2/小时、一张二手 24GB 卡几百美元——盈亏平衡在实际生成的 300–1,000 小时附近。本地赢在隐私、延迟、无速率限制(框架见 为什么本地);租赁赢在爆发性需求和没有消费卡装得下的 80GB 级模型(什么装在哪见 显存计算)。多数人高估自己的时长——决定前先记录真实的一周。