Prhub

#46115 [Bugfix] MoRIIO toy P/D proxy: fix DP-rank index aliasing + harden for high-concurrency bursts

原始 PR 作者 edwinlim0919 合并时间 2026-07-18 03:35 文件变更 2 提交数 6 评论 13 代码增减 +268 / -13

执行摘要

修复 DP-rank 路由别名及高并发代理加固

在2P_DP8EP这种多预填充实例部署场景下,旧路由方案因索引别名导致半数GPU空闲,浪费资源。同时高并发请求时Quart的浅监听队列导致连接被RST,影响请求成功率。RFC #46107 中提出的异构TP↔DP路由也需要先修复此问题。

推荐阅读者关注flat_interleaved_dp_route的设计——使用单一槽位索引解决多实例路由别名问题,该模式可推广至其他需要均匀分配的场景。高并发serve加固示例展示了从Quart切换到Hypercorn的实践经验。

讨论亮点

审查者 @tjtanaa 指出测试文件中存在pre-commit问题(前缀提交格式不规范),作者已修复。审查者最终批准该PR。此外,作者在Issue评论中与 @simondanielsson 讨论了MoRIIO READ模式与vLLM-Router的兼容性问题,确认官方Router目前不支持MoRIIO READ模式。

实现拆解

  1. 引入 flat_interleaved_dp_route 函数examples/disaggregated/disaggregated_serving/moriio_toy_proxy_server.py):用单个计数器遍历所有(instance, dp_rank) 槽位,消除实例选择与DP-rank选择的关联性。
  2. 重构路由调用:将 handle_request 中对预填充和解码实例的路由改为统一使用新函数,并丢弃旧的 example_round_robin_dp_loader
  3. 高并发serve加固:将 app.run 替换为Hypercorn,设置 PROXY_LISTEN_BACKLOG=4096debug=False、长keep-alive,避免连接被重置。
  4. 新增单元测试tests/v1/kv_connector/unit/test_moriio_proxy_routing.py 模拟外部依赖并验证所有RFC角色的槽位均匀覆盖,包括回归测试(2实例×DP8必须路由全部8个rank)。
文件 模块 状态 重要度
examples/disaggregated/disaggregated_serving/moriio_toy_proxy_server.py 代理示例 modified 7.79
tests/v1/kv_connector/unit/test_moriio_proxy_routing.py 路由测试 added 7.7

关键符号

flat_interleaved_dp_route

关键源码片段

examples/disaggregated/disaggregated_serving/moriio_toy_proxy_server.py core-logic

核心修复文件:实现了新的路由函数 `flat_interleaved_dp_route`,替换了旧的有别名问题的 `example_round_robin_dp_loader`;同时将 Quart 调试服务器替换为 Hypercorn 以增强高并发处理能力。

def flat_interleaved_dp_route(request_number: int, instances: list) -> tuple:
    """
    Flat round-robin over the full (instance, dp_rank) slot space.
    使用单个索引 slot 同时决定 instance 和 dp_rank,消除别名问题。
    例如:inst0_r0, inst1_r0, inst0_r1, inst1_r1, ...
    当 dp_size == 1 时返回 dp_rank = None,避免无效范围。
    """
    n = len(instances) # 实例数
    dp = instances[0]["dp_size"] # 同角色内 dp_size 应一致
    slot = (request_number - 1) % (n * dp) # 单槽位计数器
    inst_idx = slot % n # 实例索引
    dp_rank = (slot // n) if dp > 1 else None # DP rank,TP 时返回 None
    return inst_idx, dp_rank
tests/v1/kv_connector/unit/test_moriio_proxy_routing.py test-coverage

新增完整单元测试,验证所有 RFC 角色形状的槽位均匀覆盖,并包含回归测试确保 2 实例 DP8 不遗漏任何 rank。测试通过桩模块隔离外部依赖,只测试真实导入的路由函数。

# 桩模块上下文管理器,用于加载代理模块时替换外部依赖
@contextlib.contextmanager
def _proxy_import_stubs():
    stubs = {
        "aiohttp": _module("aiohttp"),
        "quart": _module("quart", Quart=_QuartStub, ...),
        # ... 其他桩
    }
    # 将桩注入 sys.modules,加载后再恢复
    ...# 加载真实代理模块,获取 flat_interleaved_dp_route
@pytest.fixture(scope="module")
def route():
    return _load_proxy_module().flat_interleaved_dp_route# 测试:2 实例 xDP8 时所有 16 个槽位必须都被覆盖
@pytest.mark.parametrize("n_instances, dp_size", [(2, 8)])
def test_two_instance_dp8_gives_every_node_all_ranks(route, n_instances, dp_size):
    instances = _instances(n_instances, dp_size)
    assignments = [route(i, instances) for i in range(1, 17)] # 16 requests
    # 每个 instance 应分配所有 8 个 dp_rank
    for inst_idx in range(n_instances):
        ranks_assigned = {dp for inst, dp in assignments if inst == inst_idx}
        assert len(ranks_assigned) == dp_size, f"Instance {inst_idx} missing ranks"

评论区精华

Pre-commit 错误修复 style

审查者 @tjtanaa 指出测试文件中 pre-commit 检查失败,要求修复前缀提交格式。

结论:作者已修复并折叠到测试提交中。 · 已解决

MoRIIO READ 模式与 vLLM-Router 兼容性 question

作者 @edwinlim0919 测试发现官方 vLLM-Router 不支持 MoRIIO READ 模式,导致控制平面断言失败。@simondanielsson 提供了可能解决方案的链接。

结论:确认当前 vLLM-Router 不兼容 MoRIIO READ 模式,需等待后续支持。 · unresolved

风险与影响

低风险。变更仅影响示例代理文件及新增测试,不涉及核心库。新路由函数假设同一角色内dp_size一致,在异构部署中可能需调整,但当前用例均满足。高并发加固通过配置化参数PROXY_LISTEN_BACKLOG可调,默认4096适合大多数场景。

影响MoRIIO示例代理的用户,修复后DP多实例部署下GPU利用率从约50%提升至100%;高并发burst请求成功率从部分失败提升至100%。团队需注意与#45222的合并顺序,但无逻辑依赖。

示例文件变更 高并发路径

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论