重计算CPU卸载指南¶
概述¶
RecomputeCPUOffloadConnector 用于保存被解码端重计算调度器抢占的请求的KV缓存。当HBM KV块不足时,RecomputeScheduler 可能会抢占正在运行的解码请求。如果没有此连接器,请求将回退到原始重计算路径,并可能被发送回预填充节点重新执行预填充。启用重计算CPU卸载后,已计算的KV块会在HBM块被重用前从HBM复制到CPU DRAM,并在请求再次被调度时复制回HBM。
此功能专为在线P/D分离部署场景设计,其中解码节点针对解码吞吐量进行了调优,无法在抢占后高效地重计算长预填充。该功能为可选启用,并优先保证正确性。
在典型的解码部署中,max_num_batched_tokens 通常设置为 max_num_seqs * (1 + num_spec_tokens) 左右,使得解码节点主要调度每个请求的一个新token(如果启用了MTP,则加上推测token)。这对解码来说是高效的,但对于抢占后重计算长提示词来说则太小。重计算CPU卸载避免了在KV状态可以本地保存时将此类请求发送回完整的提示词重计算路径。
关键概念¶
- 重计算抢占:当解码端HBM KV缓存耗尽时,
RecomputeScheduler可以抢占正在运行的请求,并在之后恢复它。 - CPU DRAM保存:
RecomputeCPUOffloadConnector将被抢占请求的已计算KV块存储在CPU内存中。 - H2D恢复:当被抢占的请求再次被调度时,连接器在模型前向传播前恢复已保存的KV块。
- 回退行为:如果未配置连接器、未启用重计算调度器或CPU卸载容量不足,vLLM 将回退到原始重计算行为。
MultiConnector集成:在P/D分离部署中,使用MultiConnector将P/D连接器(如MooncakeConnectorV1)与解码节点上的RecomputeCPUOffloadConnector结合使用。
配置参数¶
RecomputeCPUOffloadConnector 通过 kv-transfer-config 进行配置。
| 参数 | 描述 |
|---|---|
kv_connector |
必须设置为 RecomputeCPUOffloadConnector。 |
kv_role |
在解码节点上设置为 kv_consumer。 |
cpu_bytes_to_use_per_rank |
可选且推荐。每个rank/卡用于重计算卸载的CPU内存预算(字节)。如果设置,它将覆盖 cpu_bytes_to_use / world_size。 |
cpu_bytes_to_use |
可选。此vLLM实例的总CPU内存预算(字节)。连接器将其除以 world_size 以获得每个rank的预算。这不如 cpu_bytes_to_use_per_rank 直接,并且在DP部署中更容易配置错误。默认总值为8 GiB。 |
enable_offload_prefix_caching |
可选。为具有相同前缀缓存哈希的完整哈希块启用CPU块共享。默认值为 false;除非明确测试前缀共享,否则保持禁用状态。 |
当您希望每个rank/卡使用相同的卸载容量时,请优先使用 cpu_bytes_to_use_per_rank。例如,将 cpu_bytes_to_use_per_rank 设置为 17179869184 以分配每个rank/卡16 GiB。
如果使用 cpu_bytes_to_use,请记住它会被 world_size 除。在典型的P/D解码部署中,这意味着该值会被活跃的解码DP大小除。例如,启动DP2TP8解码服务时,将 cpu_bytes_to_use 设置为16 GiB会给每个DP rank的卡大约8 GiB的重计算卸载空间。为避免歧义,新部署请使用 cpu_bytes_to_use_per_rank。
scheduler_config.recompute_scheduler_enable must also be enabled in additional-config on
P/D-disaggregated Decode nodes:
`scheduler_config.recompute_scheduler_enable` is only valid in P/D-disaggregated mode
(`kv_role` is `kv_producer` or `kv_consumer`). Do not enable it in PD-mixed
mode (`kv_role` is `kv_both`).
Docker共享内存¶
重计算CPU卸载会为卸载的KV块分配固定的CPU张量。在Docker中运行时,请确保容器的共享内存足够大。如果 --shm-size 太小,每个卡较大的卸载预算(例如每卡16 GiB)可能无法分配CPU张量,并可能导致服务在启动时OOM或挂起。
对于具有较大重计算卸载预算的典型A3部署,请在启动容器时设置 --shm-size=1024g。以下代码片段遵循DeepSeek-V4-Flash教程中使用的Docker风格:
export IMAGE=quay.io/ascend/vllm-ascend:|vllm_ascend_version|-a3
docker run --rm \
--name vllm-ascend \
--shm-size=1024g \
--net=host \
--device /dev/davinci0 \
--device /dev/davinci1 \
--device /dev/davinci2 \
--device /dev/davinci3 \
--device /dev/davinci4 \
--device /dev/davinci5 \
--device /dev/davinci6 \
--device /dev/davinci7 \
--device /dev/davinci8 \
--device /dev/davinci9 \
--device /dev/davinci10 \
--device /dev/davinci11 \
--device /dev/davinci12 \
--device /dev/davinci13 \
--device /dev/davinci14 \
--device /dev/davinci15 \
--device /dev/davinci_manager \
--device /dev/devmm_svm \
--device /dev/hisi_hdc \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /usr/local/Ascend/driver/tools/hccn_tool:/usr/local/Ascend/driver/tools/hccn_tool \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /etc/hccn.conf:/etc/hccn.conf \
-it $IMAGE bash
与P/D分离部署一起使用¶
在解码节点上,配置 MultiConnector,同时包含P/D连接器和 RecomputeCPUOffloadConnector。P/D连接器处理从预填充到解码的KV传输,而 RecomputeCPUOffloadConnector 处理解码端的抢占保存和恢复。
以下示例使用 MooncakeConnectorV1 进行P/D KV传输。
python3 -m vllm.entrypoints.openai.api_server \
--model /path/to/model \
--port 8200 \
--trust-remote-code \
--enforce-eager \
--tensor-parallel-size 1 \
--data-parallel-size 1 \
--max-model-len 32768 \
--block-size 128 \
--max-num-batched-tokens 4096 \
--additional-config '{"scheduler_config":{"recompute_scheduler_enable":true}}' \
--kv-transfer-config \
'{
"kv_connector": "MultiConnector",
"kv_role": "kv_consumer",
"kv_connector_extra_config": {
"connectors": [
{
"kv_connector": "MooncakeConnectorV1",
"kv_role": "kv_consumer",
"kv_port": "28000",
"kv_connector_extra_config": {
"prefill": {
"dp_size": 1,
"tp_size": 1
},
"decode": {
"dp_size": 1,
"tp_size": 1
}
}
},
{
"kv_connector": "RecomputeCPUOffloadConnector",
"kv_role": "kv_consumer",
"kv_connector_extra_config": {
"cpu_bytes_to_use_per_rank": 17179869184,
}
}
]
}
}'
对于预填充节点,保持正常的P/D连接器配置,例如将 MooncakeConnectorV1 设置为 kv_role 的 kv_producer。
当P/D连接器也需要 kv_load_failure_policy 时,请在顶层 MultiConnector 的 kv-transfer-config 中配置它,而不是在子连接器内部。
独立连接器示例¶
RecomputeCPUOffloadConnector 必须与 vLLM-Ascend 的 RecomputeScheduler 一起使用。由于 RecomputeScheduler 仅在P/D分离部署的解码节点上受支持,因此重计算CPU卸载目前也仅适用于P/D分离部署的解码节点。
以下独立的连接器配置仅作为在P/D分离的Decode节点上验证重计算-卸载路径的最小配置片段。它并非PD混合部署模式。在PD混合或普通非P/D部署中,请勿启用重计算CPU卸载;引擎将使用正常的vLLM重计算行为。
from vllm.config import KVTransferConfig
kv_transfer_config = KVTransferConfig(
kv_connector="RecomputeCPUOffloadConnector",
kv_role="kv_consumer",
kv_connector_extra_config={
"cpu_bytes_to_use_per_rank": 17179869184,
"enable_offload_prefix_caching": False,
},
)
对于在线服务:
vllm serve /path/to/model \
--additional-config '{"scheduler_config":{"recompute_scheduler_enable":true}}' \
--kv-transfer-config '{
"kv_connector": "RecomputeCPUOffloadConnector",
"kv_role": "kv_consumer",
"kv_connector_extra_config": {
"cpu_bytes_to_use_per_rank": 17179869184,
"enable_offload_prefix_caching": false
}
}'
工作原理¶
- 当
RecomputeScheduler无法分配足够的HBM KV块时,它会选择一个Decode端正在运行的请求进行抢占。 - 在请求的HBM块被重用之前,调度器调用连接器的抢占钩子。如果CPU块足够,连接器记录HBM块到CPU块的映射。
- 模型运行器在更新工作器状态之前调用
handle_preemptions()。工作器将选定的KV块从HBM复制到固定的CPU张量。 - 在所有工作器报告存储完成后,被抢占的请求变为可恢复状态。
- 当请求再次被调度时,连接器报告可以从CPU内存恢复的token数量。
- 调度器分配新的HBM块,连接器构建CPU块到HBM块的重载映射。
- 在模型前向传播之前,工作器将恢复的KV块复制回HBM。前向传播从恢复的KV状态继续执行。
滑动窗口与MTP支持¶
滑动窗口模型可能包含注意力窗口外token的空块ID逻辑块表。连接器保留逻辑块位置而非压缩非零块ID,因此像[0, 0, 20, 21]这样的块表在CPU端保持为[0, 0, cpu_20, cpu_21]的对齐形式。仅传输非零块。
启用MTP或推测解码时,调度器可能分配预读块。重载路径将H2D范围裁剪为实际分配给恢复请求的GPU块表。
注意事项与限制¶
- This feature requires the vLLM V1 engine and the vLLM-Ascend recompute scheduler.
- The feature is only intended for Decode nodes in P/D disaggregation. It is not supported in PD-mixed or normal non-P/D deployments.
- Do not enable
scheduler_config.recompute_scheduler_enablein PD-mixed deployments. Without P/D-disaggregated Decode-sideRecomputeScheduler, recompute CPU offload is not active and vLLM follows the normal recompute path. - When running in Docker with a large per-rank offload budget, reserve enough
shared memory. For typical A3 deployments with 16 GiB per-card offload, use
--shm-size=1024g. enable_offload_prefix_cachingis experimental and disabled by default.- Current D2H and H2D transfers use basic torch copy operations. They are correctness-oriented and not yet optimized for transfer throughput.
- Qwen3.5 with async scheduling is not fully supported yet. Disable async scheduling when using recompute CPU offload with Qwen3.5 models.
- If CPU memory capacity is insufficient, the connector skips offload for that request and the scheduler falls back to the original recompute behavior.
常见问题¶
我应该配置多少CPU内存?¶
从能够容纳预期被抢占请求块数量的预算开始。优先使用cpu_bytes_to_use_per_rank,因为它直接控制每个rank/卡的卸载预算。例如,cpu_bytes_to_use_per_rank=17179869184为每个rank/卡提供16 GiB空间。
cpu_bytes_to_use除以world_size。在DP2TP8的Decode服务中,设置cpu_bytes_to_use=17179869184为每个DP rank的卡提供约8 GiB的卸载空间。如果日志显示CPU缓存空闲块不足,请增加预算。
如何知道卸载路径是否激活?¶
查找类似以下日志:
Recompute preemption offload enabled for request ...
Created recompute offload state for request ...
Prepared recompute offload H2D load for request ...
如果无法准备卸载,日志可能显示CPU缓存空闲块不足,请求将回退到原始的重计算路径。
这与KV缓存CPU卸载相同吗?¶
不。KV Cache CPU Offload是针对非活跃KV缓存块的前缀缓存卸载路径。RecomputeCPUOffloadConnector专门用于保存被Decode端重计算调度器抢占的请求的KV块。
参考¶
有关设计背景和实现细节,请参见 #10820: 重计算CPU卸载连接器。