Prhub

#45371 [Bugfix][KV Connector] Disable Mooncake TP put-striding when DCP > 1

原始 PR 作者 ivanium 合并时间 2026-06-19 06:13 文件变更 2 提交数 5 评论 0 代码增减 +87 / -8

执行摘要

禁用 DCP>1 时 Mooncake TP put-striding 避免 key 丢失

运行 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 集合不完整。

值得阅读并理解 DCP 与 TP 交互的设计取舍。对于维护分布式推理管线的团队,应关注类似 namespace 隔离问题。PR 附带良好的测试实践,值得参考。

讨论亮点

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

实现拆解

  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=14,在 tp_size=4num_kv_head=1 场景下验证 striping 正确性。
  4. 测试工具函数 _make_vllm_config 增加 rankdecode_context_parallel_size 参数。
文件 模块 状态 重要度
vllm/distributed/kv_transfer/kv_connector/v1/mooncake/store/worker.py KV 传输 modified 5.67
tests/v1/kv_connector/unit/test_mooncake_store_worker.py 测试 modified 6.02

关键符号

test_worker_put_striding_covers_every_rank_get_namespace

关键源码片段

vllm/distributed/kv_transfer/kv_connector/v1/mooncake/store/worker.py core-logic

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

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 test-coverage

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

@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

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

主要风险是回归:当 dcp_size=1 时,striding 行为与之前完全一致,已通过测试验证。当 dcp_size>1 时,禁用 striping 会导致每个 rank 写入所有属于它的 key,但不会引起重复。潜在性能影响:写入量不变。其他并行维度(如 PCP)已确认无影响。测试仅覆盖单元场景,缺少集成测试。

直接影响使用 Mooncake KV offload 且 DCP 大于 1 的用户,修复了关键错误。影响范围窄(仅涉及 v1 引擎和 kv-connector 模块)。修复简单,风险低。

仅有单元测试覆盖 分布式同步风险(已修复) 潜在回归(已含测试验证)

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论