DeepInfer 的生产缺口:KV cache、PD 分离与负载均衡
DeepInfer 交付的是整个栈里“算 token”的那部分,服务于 DeepSeek V4.1-Flash。而一个服务业务还需要“记住、路由和均衡”的那部分。这篇笔记详细看这三块缺失的组件——以及它们为什么比看上去更难。
DeepInfer 是 DeepSeek 的 V4.1-Flash 推理引擎,不是一套完整的服务栈。README 的“未包含”清单很短:KV cache 系统、VE/Prefill/Decode 分离,以及跨数据并行副本的负载均衡。每一项都是一个子系统,而不是一个功能开关。它们合在一起,就是“跑一个模型”和“跑一个服务”的差别。
引擎与服务
引擎接收一批 token 化后的请求,返回生成的 token。服务则要接收来自大量用户的 HTTP 请求,做鉴权、路由,让上下文保持在热缓存中,执行配额,处理故障,最后还要计费。引擎是昂贵的算力,服务是昂贵的运维。
DeepInfer 是引擎。DeepSeek 的 Q&A 异常详细地描述了它周围的服务,这让缺口一目了然。下面逐一看最大的三块。
KV cache:让长上下文变得可负担的那层记忆
模型读入 prompt 时,会为每个 token、每一层存下 key 和 value。正是这份缓存让 decode 能在生成下一个 token 时不必重读整个 prompt。跨请求复用前缀,是服务中最大的成本杠杆之一:一段很长的系统提示、一份共享文档,或者一段多轮 agent 历史,可以只算一次,复用很多次。
朴素做法——在显存里放一个字典——在规模化时会崩溃。显存相对需求太小,一条缓存可能需要被另一台机器访问,而计算节点比存储节点更容易故障。DeepSeek 的生产设计分成三层:
| 层级 | 存放什么 | 介质 | 生命周期 / 策略 |
|---|---|---|---|
| 在途 | 活跃 block KV + state KV | GPU HBM | 请求生命周期 |
| SWA 池 | 活跃会话的滑动窗口 KV | 主机 DRAM(每台机器 10%) | 分钟级;TTL 约 180 秒 |
| 持久化 block KV | 用于复用的 prefix 缓存 | 专用 3FS 集群 | agent 流量 3 天,chatbot 流量 7 天 |
生产数字大到足以改变你对这个问题的认知:
- 约 100 PiB 的 SSD 用于 KV cache。
- 每块 GPU 约 14.4 TB 逻辑 KV;物理容量更大。
- 每 8 块 GPU 约 400 Gbps 互联带宽。
- 3FS 采用 10+2 纠删码;每个 EC 组可同时容忍两个节点故障。
- 峰值聚合读约 10 TiB/s;写约 850 GiB/s。
为什么用专用存储集群,而不是本地内存或分层缓存?Q&A 给了三个理由:
- 任何 prefill 机器都能命中任何前缀。如果缓存是本地化的,路由就必须做 prefix 亲和,这与负载均衡相冲突。
- 存储和计算可以独立扩展。你可以只加缓存容量而不加 GPU,反之亦然。
- 计算节点故障不会丢失缓存。据 DeepSeek 说,计算节点的故障率比存储节点高一个数量级。
一次缓存命中分三段:匹配、取回、换入。只有匹配在关键路径上;从 3FS 取回到主机共享内存由独立进程异步完成,而从共享内存换入 HBM 则与前向计算逐层重叠。DeepSeek 的换入走 GDR/RDMA,因为 CUDA copy engine 处理细粒度 KV block 拷贝效率不高。
如果要自己搭这套东西,你需要 prefix 匹配、元数据服务、分布式存储、淘汰/TTL、跨机器传输、容错,以及一套与负载均衡配合的路由策略。这是一个存储团队的工作量,不是一个周末项目。
3FS 的设计、100 PiB 这个数字,以及 3/7 天 TTL,描述的都是 DeepSeek 的生产系统。DeepInfer 的发布不包含 KV cache 系统。没有它你也能跑离线推理;但只靠这个仓库,你无法复现生产环境的缓存行为。
Prefill/decode 分离:两种负载,两个池
Prefill 和 decode 的瓶颈不同。Prefill 受算力限制:它一次处理大量 prompt token,受益于大矩阵乘法。Decode 受显存带宽限制:每一步为每个请求生成一个 token,并读取 KV cache。把它们放在同一个池里,就不得不在硬件、并行方式和批量大小上做折中。
分离就是把它们拆成两个池:
- Prefill 池:8 卡机器,EP2–8 / DP2–8,按非缓存 token 数定容。
- Decode 池:64–128 卡超节点,EP64–128 / DP64–128(Wide-EP),按运行中的请求数定容。
- 视觉编码器:每个实例一块 GPU,通常用较便宜的卡。
- 存储:专用 KV cache 节点,与计算分离。
DeepSeek 称 P:D 比例约为 1:1,并把 64 块 prefill + 64 块 decode GPU 称为最小的高效单元。1P + 1D 也能部署,但推荐的 decode 布局是 EP64 及以上。
难的是交接。请求到达、完成 prefill、产出 KV cache,然后必须被路由到一个能看见这份缓存的 decode 引擎。这需要一条传输路径、一份记录缓存位置的目录,以及一个同时考虑缓存位置和 decode 负载的路由决策。DeepSeek 为每 8 块 GPU 预留约 400 Gbps 互联带宽,并指出 P 和 D 可以位于相邻数据中心,但要付出一定的可靠性代价。
发布说明称分离方面“大部分所需的引擎功能已经实现”,但完整方案并未包含。如果你想要生产形态,那你就是在自建编排层。
负载均衡:两个维度,四类均衡器
DeepSeek 描述了四类均衡器:prefill、decode、视觉编码器和专家并行。
Prefill 负载均衡器
请求按总上下文长度分成四档:<16K、16–64K、64–256K 和 ≥256K。分配给每一档的引擎数量,根据上一轮的算力配额需求重新分配。在一个 DP 组内,每个请求发往当前配额负载最低的 rank。在一块 GPU 内,请求按 FIFO 出队,chunk 大小则由时间预算反解,使用一个拟合出的二次成本模型。
这比轮询精细得多,因为 prefill 成本并不随请求数线性增长;一个 256K token 的 prompt 就能压过一整批短请求。
Decode 负载均衡器
Decode 路由平衡两个维度:请求数(决定每步批量大小)和 KV cache 总长度(决定注意力开销)。启发式规则是把短请求发给并发低但 KV 长度大的 GPU,把长请求发给 KV 长度小的 GPU。目标是让批量和注意力工作量同时保持均衡。
专家并行负载均衡器
EPLB 增加冗余专家,并根据近期负载周期性地把专家重新分配到 GPU。DeepSeek 报告 decode 的 moe_lb 约为 1.090——最慢的 rank 比平均多做约 9% 的工作。prefill 的数字在英文 Q&A 和中文文章之间略有差异,但机制相同。
80% 的现实校准
Q&A 里最有价值的一句,可能是这句:生产环境的负载均衡达到理想均衡离线基准的约 80%。
这意味着,即便是 DeepSeek,有定制均衡器、完全掌控整个栈,也只能达到离线基准吞吐的约 80%。一个把简单路由器接到 DeepInfer 上的团队,不该期待更好。这也意味着离线 Pareto 图是上界:它们是在受控环境中测的,不是在生产的路由偏斜下。
这不是批评,而是一次校准:分布式服务本来就很脏,最后那 20% 恰恰是大量工程所在。
自建还是采购
如果你需要一个可用的 API 服务,大致有三条路:
| 路径 | 你能得到什么 | 你需要自己承担什么 |
|---|---|---|
| 使用成熟的服务框架(vLLM、SGLang、TensorRT-LLM) | API 层、批处理、缓存、广泛的模型支持 | 对 DeepSeek 专用调优的控制更少;需确认 V4.1-Flash 支持 |
| 在 DeepInfer 之上自建 | DeepSeek 的算子与调度 | KV cache、PD 分离、负载均衡、API、鉴权、计费、可观测性 |
| 等 DeepSeek 开放更多 | 一套可能更完整的栈 | 时间表不确定;Q&A 没有给出日期 |
对多数团队来说,第一条路更务实。DeepInfer 适合那些有硬件、有相应负载、也有工程能力自持服务层的团队——或者想学习 DeepSeek 做法的工程师。
DeepInfer 开放的是引擎;服务仍然是一个自建项目。这次发布的价值,恰恰在于它让这个区分清晰可见,而不是藏在 demo 后面。