跳转至

KVPP(实验性)

概述

KVPP(KV 流水线并行)针对非混合 MLA/SFA 模型,将原本会在 TP rank 之间按层复制的历史 KV 缓存进行分布式存储。这降低了每个 rank 的持久缓存存储占用,使相同的 HBM 容量能够容纳更多上下文 token 或并发请求。

当某一层执行时,负责其缓存的 rank 会将完整缓存广播给组内其他 rank。模型计算保留其 TP/EP/PP 配置。启用 PP 时,每个阶段在各自的缓存副本组内分配缓存并广播。该组跨越 TP rank;当在 Model Runner V2 上启用 PCP 时,跨越 PCP × TP rank;并且从不跨越 DP 副本或 PP 阶段。

KVPP 中的流水线并行指 KV 缓存的存储与通信,而模型计算保持上述并行配置。关于底层的按层 KV 存储概念,请参见 Z.ai 的 大规模编码智能体服务扩展的痛点:从 GLM-5 大规模调试中获得的经验 中的 LayerSplit。

使用场景

KVPP 面向长上下文推理和并发服务负载,适用于重复 KV 缓存限制可用缓存容量的场景。对于具有可复用长前缀的负载,它也可以与前缀缓存和 KV 池化结合使用。

在 950DT 产品上,使用 TP8 + EP 的单八设备节点运行 GLM-5.2-W4A8C8 时,实测 KV 缓存容量为 6.25×;使用 TP8 + PP2 + EP(38/40 层)的双八设备节点运行 GLM-5.2-W8A8C8-mxfp8 时,实测 KV 缓存容量为 5.35×。每项比较均使用相同模型、硬件和内存预算,并分别关闭和开启 KVPP。这些容量比率仅适用于性能部分中的配置;它们不是吞吐量倍数,也不保证适用于其他模型。

支持的场景

支持的模型

KVPP 支持在 Model Runner V1 和 V2 上使用非混合 MLA 和 SFA 模型。将 KVPP 与 PCP 结合使用需要 Model Runner V2。

注意力后端 KVPP 支持 模型范围
MLA ✅ 支持 使用 MLA 的非混合模型
SFA ✅ 支持 使用 SFA 的非混合模型,例如 GLM-5.2

模型还必须满足 vLLM Ascend 的硬件、量化和注意力后端要求。

支持的功能

下表列出了与 KVPP 组合的单个功能。这并不意味着所有列出的功能都可以同时启用。

功能或组合 支持 条件和限制
Eager 模式 ✅ 支持 使用 --enforce-eager。
Graph 模式 ❌ 不支持 KVPP 当前要求使用 Eager 模式。
TP ✅ 支持 KV 缓存在每个缓存副本组内按层分配。
EP ✅ 支持 需要支持 EP 的 MoE 模型。
PP ✅ 支持 每个 PP 阶段独立分配并广播其缓存。
分块预填充 ✅ 支持 可与 KVPP 结合使用。
前缀缓存 ✅ 支持 可与 KVPP 结合使用。
异步调度 ✅ 支持 可与 KVPP 结合使用。
LI-C8 和 SFA-C8 缓存布局 ✅ 支持 分配遵循实际的 KV 缓存规格。
固定步长 MTP ✅ 支持 MTP 缓存独立分配,并排除在 KVPP 层划分之外。
可变步长 MTP 和其他投机解码方法 ❌ 不支持 仅支持固定步长 MTP。
PCP ✅ 支持 需要 Model Runner V2;缓存在 PCP × TP rank 之间共享。
DCP ❌ 不支持 当前不能与 KVPP 结合使用。
P/D 分离 ✅ 支持 使用 MooncakeConnectorV2(实验性);仅在预填充节点上启用 KVPP。
KV 池化 ✅ 支持 使用 AscendStoreConnector、kv_producer 或 kv_both 的 Memcache,以及异步整块加载。
PCP + P/D 分离 + KVPP ❌ 不支持 MooncakeConnectorV2 尚不支持 PCP。
PCP + KV 池化 + KVPP ❌ 不支持 PCP 和 KV 池化可分别与 KVPP 结合使用,但三者组合不支持。
  • ✅ 支持:在所述条件下,该功能组合受支持。
  • ❌ 不支持:该组合当前不受支持。

使用

通过 --additional-config 中的 enable_kvpp 启用 KVPP,并使用 Eager 模式:

vllm serve <model-path> \
    --tensor-parallel-size 2 \
    --enforce-eager \
    --additional-config '{"enable_kvpp": true}'

将 <model-path> 替换为受支持的 MLA/SFA 模型路径,并根据模型大小和可用设备选择 TP。KVPP 组大小遵循 TP × PCP,无需单独设置。禁用 PCP 时,TP=1 无法在 rank 之间提供缓存共享收益。

如果启动命令已包含 --additional-config,请将 enable_kvpp 合并到现有 JSON 对象中。

组合功能

KVPP 可与 EP、PP、分块预填充、前缀缓存和异步调度结合使用。以下示例使用支持 EP 的 MoE 模型:

vllm serve <model-path> \
    --tensor-parallel-size 2 \
    --enable-expert-parallel \
    --enable-chunked-prefill \
    --enable-prefix-caching \
    --async-scheduling \
    --max-num-batched-tokens 32768 \
    --max-num-seqs 12 \
    --enforce-eager \
    --additional-config '{"enable_kvpp": true}'

根据设备容量和负载调整 token 预算和最大序列数。

对于 PCP,请设置 VLLM_USE_V2_MODEL_RUNNER=1,并在启动配置中添加 --prefill-context-parallel-size。KVPP 在 PCP × TP rank 之间共享缓存;Model Runner V1 不支持 KVPP 与 PCP 结合使用。

对于 PP,请将 enable_kvpp 添加到现有 PP 启动配置中。每个阶段独立分配其缓存。KVPP 不会改变 PP 层划分。

固定步长 MTP 可与 KVPP 结合使用,但 MTP 缓存仍独立分配,并排除在 KVPP 层划分之外。请按照模型特定的配置要求设置 MTP 启动参数。

配置参数

参数 默认值 描述
additional_config.enable_kvpp false 启用 KVPP;组大小遵循 TP × PCP。
--enforce-eager 未启用 启用 KVPP 时必需;当前不支持图执行。

KVPP 会完整广播每一层一次。无需配置广播粒度或单独的 KVPP 并行大小。

KV 传输配置

PD 分离

KVPP 通过 MooncakeConnectorV2 支持 P/D 分离(实验性)。连接器代码已合并,但尚未发布。

在预填充节点上使用 kv_producer,在解码节点上使用 kv_consumer 配合 MooncakeConnectorV2。仅在预填充节点上启用 KVPP。MTP 缓存仍保持复制,并随持久目标缓存一起传输。

# Prefill node: include {"enable_kvpp": true} in --additional-config.
--kv-transfer-config '{"kv_connector":"MooncakeConnectorV2","kv_role":"kv_producer","kv_port":37000}'

# Decode node: leave KVPP disabled.
--kv-transfer-config '{"kv_connector":"MooncakeConnectorV2","kv_role":"kv_consumer","kv_port":37010}'

每个 worker 使用由 kv_port 及其并行 rank 推导出的握手端口。当两个节点运行在同一主机上时,请选择不重叠的端口范围。

Memcache 池化

对于 Memcache 池化,KVPP 支持 kv_producer 和 kv_both。kv_consumer 尚未测试,不在已验证的支持范围内。

按照 KV 池 中的说明配置 memcache SDK 和 MetaService,然后添加:

--kv-transfer-config '{"kv_connector":"AscendStoreConnector","kv_role":"kv_producer","kv_connector_extra_config":{"lookup_rpc_port":"0","backend":"memcache","use_layerwise":false,"load_async":true}}'

示例使用 kv_producer;也可以将 kv_role 设置为 kv_both。在此池化配置中,两种角色都会保存和加载前缀。保持 use_layerwise=false、load_async=true 和 discard_partial_chunks=true(默认值)。KVPP 不支持逐层池化、KV 事件和消费者写回。

每个 TP rank 为每个 token 块保存一个完整对象,其中包含其持久目标层及其自身的 MTP 缓存。暂存缓冲区被排除。加载会恢复这些相同的持久缓冲区;当某层执行时,现有的 KVPP 广播为其他 rank 提供数据。池查找需要所有 PP 阶段中每个非空的所有者分片。

性能

以下在 950DT 产品上对 GLM-5.2 的测量结果展示了其对缓存容量、首 token 时间(TTFT)和预填充吞吐量的影响。单节点和双节点部署使用不同的量化权重;请在每种部署内比较 KVPP 开启和关闭的情况。

测试配置

设置 单节点 双节点 PP
硬件 一个节点,配备 8 个 950DT 产品 两个节点,每个节点配备 8 个 950DT 产品
模型 GLM-5.2-W4A8C8 GLM-5.2-W8A8C8-mxfp8
并行 TP8 + EP TP8 + PP2 + EP,38/40 层划分
通用设置 DSA-CP、分块预填充、前缀缓存、异步调度、LI-C8、Model Runner V1、立即执行模式 与单节点相同
调度和内存 max_num_batched_tokens=32768、max_num_seqs=12、gpu_memory_utilization=0.90 与单节点相同

未启用 MTP 和 SFA-C8。以下所有测量均使用 32K 调度 token 预算。

KV 缓存容量

服务在未覆盖块数的情况下自动计算容量。单节点数值来自池化测试配置;双节点数值来自非池化服务启动日志。

部署 KVPP 禁用(token) KVPP 启用(token) 容量倍数 相同 token 容量下等效的 KV 内存节省
单节点 235,008 1,467,904 6.25× 83.99%
双节点 PP 555,392 2,972,416 5.35× 81.32%

等效 KV 内存节省是根据容量比估算的,并不代表总 HBM 使用量有相同幅度的减少。每个 rank 仍然需要两个暂存缓冲区和独立的 MTP 缓存,因此容量收益取决于层数、TP 大小、PP 划分以及每层缓存大小。

首 token 时间

此测试测量长输入、零前缀命中、低并发的请求。单节点部署使用 GLM-5.2-W4A8C8,配备 8 个 950DT 产品,采用 TP8 + EP。双节点部署使用 GLM-5.2-W8A8C8-mxfp8,每个节点配备 8 个 950DT 产品,采用 TP8 + PP2 + EP(38/40 层)。其他服务设置遵循上述测试配置。

输入长度为 32K、64K 和 128K token。前缀缓存命中率为 0%,输出 1 个 token。每个结果是客户端并发为 1 时 4 个请求的平均 TTFT。正值表示延迟增加。

部署 输入长度 KVPP 禁用 KVPP 启用 TTFT 变化
单节点 32K 2.623 s 2.614 s -0.33%
单节点 64K 5.295 s 5.375 s +1.52%
单节点 128K 10.901 s 11.268 s +3.36%
双节点 PP 32K 2.900 s 2.905 s +0.19%
双节点 PP 64K 4.503 s 4.887 s +8.53%
双节点 PP 128K 7.805 s 8.665 s +11.01%

非池化预填充吞吐量

每次运行包含 40 个请求,客户端并发为 12,每个请求输入 128K token,输出 1 个 token。两种配置中均禁用了 KV 池化。

部署 前缀缓存命中率 KVPP 禁用(输入 token/s) KVPP 启用(输入 token/s) 吞吐量变化
单节点 0% 12,492.4 12,205.7 -2.30%
单节点 90% 116,516.2 110,224.8 -5.40%
双节点 PP 0% 21,395.2 18,742.3 -12.40%
双节点 PP 90% 177,375.4 154,717.3 -12.77%

所有 90% 场景中的实际命中率为 89.9414%。在这些工作负载下,KVPP 增加了缓存容量,但引入了广播开销;非池化吞吐量没有提升。

使用建议

首先评估 KVPP 在受 KV 缓存容量限制的工作负载上的表现。使用真实的输入长度、并发和前缀分布,比较 KVPP 开启和关闭时的容量、TTFT 和吞吐量,然后选择满足服务延迟要求的配置。

广播会传输某一层所有已分配的逻辑块,而不会针对活跃请求进行过滤,因此增加缓存容量也会增加广播量。预取可以将部分通信与计算重叠,但其收益仍取决于工作负载。当缓存容量已经足够时,请使用实测的延迟和吞吐量来决定是否启用 KVPP。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 vl/vllm-ascend