Prhub

#32638 test: fix NIXL EP Mooncake FT test

原始 PR 作者 zackyoray 合并时间 2026-08-06 18:00 文件变更 1 提交数 1 评论 2 代码增减 +28 / -3

执行摘要

修复 NIXL Mooncake 弹性 EP 故障测试的进程击杀与恢复验证

PR body 指出该测试需要 kill 实际的 DP scheduler。旧代码 pkill 目标进程名 sglang::scheduler_DP1_TP8_EP8 与实际进程布局不符,故障注入并未真正生效;同时 os.system 的 pkill 没有锚定,匹配范围过宽,测试既可能漏杀也可能误杀。

该 PR 值得测试与 EP 相关同学快速浏览:展示了如何通过精确 pkill 与引导请求让故障注入测试变得可复现。但整体是测试修复,不涉及核心代码,不必精读。

讨论亮点

UNIDY2002 在批准时提到:"I encountered the same case on the Mooncake side as well, and this solution looks sound to me." 说明他在 Mooncake 侧也遇到过同类问题,并认可该修复方案。ShangmingCai 先评论 LGTM,随后正式批准,无其他技术争议。

实现拆解

  1. 调整启动配置:在 TestNixlMoeMooncakeElasticEP.server_args 中追加 --moe-dense-tp-size 1 与 --enable-dp-lm-head,使目标进程名变成 sglang::scheduler_DP1_TP1_EP1,与进程实际命名保持一致。
  2. 精确进程击杀:用 subprocess.run(["pkill", "-f", f"^{self.pkill_process_1}$"], check=True) 替换 os.system 调用,正则锚定首尾,check=True 保证进程存在,若未命中直接报错,避免静默失败。
  3. 故障后引导请求:在运行 GSM8K 评测前,先向 {self.base_url}/generate 发送一个 max_new_tokens=1、routed_dp_rank=0 的最小请求,让控制器学习 post-fault active rank mask,再开始并发负载,避免评测期间因掩码未就绪而失败。
  4. 测试配套:仅修改此测试文件,未改动源码、配置或其他测试;原有断言 metrics["score"] > 0.60 保持不变。
文件 模块 状态 重要度
test/manual/ep/test_nixl_ep.py 弹性 EP modified 5.21

关键符号

TestNixlMoeMooncakeElasticEP.test_gsm8k_fault_1

关键源码片段

test/manual/ep/test_nixl_ep.py test-coverage

唯一变更文件,核心修复 NIXL Mooncake 弹性 EP 故障测试的进程击杀目标与恢复验证流程。

class TestNixlMoeMooncakeElasticEP(_EPTestBase):
    # 通过显式配置 MoE dense TP size 与 DP LM head,
    # 使故障目标的 scheduler 进程名变为 "sglang::scheduler_DP1_TP1_EP1",
    # 与原实现中的错误进程名 "sglang::scheduler_DP1_TP8_EP8" 对齐。
    server_args = [
        *NIXL_COMMON,
        *DP_ATTN,
        *ELASTIC_MOONCAKE,
        "--moe-dense-tp-size",
        "1",
        "--enable-dp-lm-head",
    ]
​
    # 使用 ^...$ 锚定进程名,避免 pkill 误杀同名前缀的其他进程
    pkill_process_1 = "sglang::scheduler_DP1_TP1_EP1"
​
    def test_gsm8k_fault_1(self):
        # check=True 强制 pkill 至少命中一个进程,
        # 若进程名因配置变化失效,测试会立即失败而不是静默通过
        subprocess.run(
            ["pkill", "-f", f"^{self.pkill_process_1}$"],
            check=True,
        )
        # 先向幸存 rank 发送一次最小 forward(bootstrap),
        # 让控制器在并发负载前学习 post-fault active rank mask
        response = requests.post(
            f"{self.base_url}/generate",
            json={
                "text": "Hello",
                "sampling_params": {"max_new_tokens": 1},
                "routed_dp_rank": 0,
            },
            timeout=120,
        )
        self.assertEqual(response.status_code, 200, response.text)
        metrics = self._run_gsm8k()
        self.assertGreater(metrics["score"], 0.60)

评论区精华

修复方案可靠性 设计

UNIDY2002 表示在 Mooncake 侧也遇到同样情况,该方案看起来可靠;ShangmingCai 评论 LGTM 后批准。

结论:方案获维护者认可并合并。 · 已解决

风险与影响

本 PR 只改测试,无产品代码风险。测试依赖真实 RDMA 设备与 NIXL/Mooncake 环境,只能在 test/manual/ep 手动测试目录中运行;pkill 通过精确正则锚定进程名,若进程名因后续配置变化而改变,check=True 会直接导致测试失败,需要同步更新进程名。bootstrap 请求增加了一次推理调用,略微延长测试时间。

影响范围限于 test/manual/ep/test_nixl_ep.py 的 Mooncake 弹性 EP 用例,不会影响默认 CI 或产品端。对验证 NIXL + Mooncake 容灾能力的团队而言,该用例从"可能未真正注入故障"变为"确定性故障注入 + 恢复验证",提升了该场景测试的可信度。

依赖真实 RDMA 环境 pkill 进程名强耦合 仅 manual 测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论