# PR #45371 完整报告

- 仓库：`vllm-project/vllm`
- 标题：[Bugfix][KV Connector] Disable Mooncake TP put-striding when DCP > 1
- 合并时间：2026-06-19 06:13
- 原文链接：http://prhub.com.cn/vllm-project/vllm/pull/45371

---

# 执行摘要

- 一句话：禁用 DCP>1 时 Mooncake TP put-striding 避免 key 丢失
- 推荐动作：值得阅读并理解 DCP 与 TP 交互的设计取舍。对于维护分布式推理管线的团队，应关注类似 namespace 隔离问题。PR 附带良好的测试实践，值得参考。

# 功能与动机

运行 DCP + Mooncake offload 会产生 Mooncake OBJECT_NOT_FOUND (-704) 错误，且失败率等于 `1 - 1/put_step`（例如 TP=DCP=4 且使用 MLA 时 75% 的 key 失败）。根本原因是 `num_kv_head < tp_size` 时，TP rank 对相同 KV head 进行去重写入（striping），这仅在写入和读取来自同一个 key namespace 时才有效。DCP 分割了 TP 组，不同 rank 的 namespace 不同（`@dcpN` 后缀不同），导致写出的 key 集合不完整。

# 实现拆解

1. 在 `worker.py` 的 `__init__` 中，将 put-striding 的激活条件从 `self.num_kv_head < self.tp_size` 扩展为 `self.num_kv_head < self.tp_size and self.dcp_size <= 1`，并添加详细注释说明 DCP>1 时禁用 striping 的原因。
2. 修改测试辅助函数 `_patch_worker_runtime`，支持参数 `tp_rank`, `tp_size`, `dcp_size`，并正确构造 DCP group（`dcp_rank = tp_rank % dcp_size`）。
3. 新增测试函数 `test_worker_put_striding_covers_every_rank_get_namespace`，参数 `dcp_size=1` 和 `4`，在 `tp_size=4`、`num_kv_head=1` 场景下验证 striping 正确性。
4. 测试工具函数 `_make_vllm_config` 增加 `rank` 和 `decode_context_parallel_size` 参数。

关键文件：
- `vllm/distributed/kv_transfer/kv_connector/v1/mooncake/store/worker.py`（模块 KV 传输；类别 source；类型 core-logic）: 修复的核心文件，通过一行条件增加 DCP>1 守卫修复关键 key 丢失 bug
- `tests/v1/kv_connector/unit/test_mooncake_store_worker.py`（模块 测试；类别 test；类型 test-coverage；符号 _patch_worker_runtime, test_worker_put_striding_covers_every_rank_get_namespace）: 新增的回归测试，参数化验证 DCP 场景下 striping 正确性

关键符号：test_worker_put_striding_covers_every_rank_get_namespace

## 关键源码片段

### `vllm/distributed/kv_transfer/kv_connector/v1/mooncake/store/worker.py`

修复的核心文件，通过一行条件增加 DCP>1 守卫修复关键 key 丢失 bug

```python
if self.num_kv_head < self.tp_size and self.dcp_size <= 1:
    # Dedup: TP ranks holding the same KV heads stripe PUTs across
    # one shared key namespace. DCP 会将 TP 组分割，所以当 DCP > 1 时
    # 这些 rank 属于不同的 `@dcpN` namespace，striping 会导致 key 缺失
    # （GET 时 OBJECT_NOT_FOUND）。PCP 是 TP 的外层（pcp_rank 在 TP 组内不变）
    # 因此不需要额外防护。
    self.put_step = self.tp_size // self.num_kv_head
    self.head_or_tp_rank = self.tp_rank // self.put_step
else:
    self.head_or_tp_rank = self.tp_rank
    self.put_step = 1

```

### `tests/v1/kv_connector/unit/test_mooncake_store_worker.py`

新增的回归测试，参数化验证 DCP 场景下 striping 正确性

```python
@pytest.mark.parametrize('dcp_size', [1, 4])
def test_worker_put_striding_covers_every_rank_get_namespace(
    tmp_path, monkeypatch, dcp_size
):
    # Every key a rank GETs must have been PUT by some rank.
    tp_size = 4
    store = MagicMock()
    store.setup.return_value = 0
    _install_fake_mooncake(monkeypatch, store)
    # ... 配置 ...
    all_put_keys = set()
    for tp_rank in range(tp_size):
        _patch_worker_runtime(monkeypatch, tp_rank=tp_rank, tp_size=tp_size, dcp_size=dcp_size)
        # ... 模拟 PUT ...
        all_put_keys.update(keys)
    for tp_rank in range(tp_size):
        _patch_worker_runtime(monkeypatch, tp_rank=tp_rank, tp_size=tp_size, dcp_size=dcp_size)
        get_keys = ...
        for k in get_keys:
            assert k in all_put_keys

```

# 评论区精华

该 PR 无 review 讨论，直接获得 njhill 的 approved。

- 暂无高价值评论线程

# 风险与影响

- 风险：主要风险是回归：当 dcp_size=1 时，striding 行为与之前完全一致，已通过测试验证。当 dcp_size>1 时，禁用 striping 会导致每个 rank 写入所有属于它的 key，但不会引起重复。潜在性能影响：写入量不变。其他并行维度（如 PCP）已确认无影响。测试仅覆盖单元场景，缺少集成测试。
- 影响：直接影响使用 Mooncake KV offload 且 DCP 大于 1 的用户，修复了关键错误。影响范围窄（仅涉及 v1 引擎和 kv-connector 模块）。修复简单，风险低。
- 风险标记：仅有单元测试覆盖 , 分布式同步风险（已修复）, 潜在回归（已含测试验证）

# 关联脉络

- 暂无明显关联 PR