Prhub

#36150 fix(mini-lb): forward the flush_cache timeout param to workers

原始 PR 作者 ShangmingCai 合并时间 2026-08-24 15:32 文件变更 1 提交数 1 评论 11 代码增减 +8 / -2

执行摘要

修复 mini-lb 转发 flush_cache 的 timeout 参数,恢复延迟排空路径

PR body 指出 mini_lb 的 /flush_cache handler 原本 "took no parameters and posted to a bare {server}/flush_cache, dropping any ?timeout= the caller sent"。而调度器侧 scheduler_components/flush_wrapper.py 将缺失或非正的 timeout 视为 "flush now, skip the idle check",直接执行 _flush_cache(),导致 SchedulerFlushWrapper 基于 is_fully_idle() 的延迟路径(已纳入 disagg_prefill_inflight_queue、disagg_decode_transfer_queue 及 prealloc/retracted 队列)完全不可达。实际后果是破坏性 KV-cache flush 落在在途 PD 传输上:MooncakeKVManager 读到刚释放的 buffer 而失败,再经单次失败永久拉黑 peer session 的机制放大为 86.9% 空响应、吞吐从 9,994 tok/s 跌到 2,039 tok/s。

PR body 值得精读:对"参数丢弃 → scheduler 立即 flush → KV 释放 → Mooncake 单次失败永久拉黑"的跨层根因分析是高质量排障范例,量化数据(12 次真实失败放大为约 1465 个请求失败,吞吐 2,039→9,994 tok/s)很有说服力。作者主动更正 PR 归因的严谨做法也值得参考。代码本身仅 8 行改动、阅读成本极低;管理上应跟进三个遗留项:#36152 的真实修复、Rust router 同缺陷、Mooncake 黑名单与恢复探针策略。

讨论亮点

没有 review 评论,讨论集中在 issue 评论区,核心是作者自己的归因更正:PR body 声称的 CI 失败其实不是本 PR 修复的——PD disaggregation 测试由 PDDisaggregationServerBase.launch_lb 传 --mini-lb 前置的是另一处 mini_lb,experimental/sgl-router 不在该路径上。作者明确说 "The defect here is real and independent",真实修复在 #36152。此外作者多次发起 /rerun-test,github-actions 回报 8-gpu-h20 上 dp_attention 测试通过。

实现拆解

  1. 变更入口:仅 1 个文件,sgl-model-gateway/bindings/python/src/sglang_router/mini_lb.py,改动 +8/-2。

  2. 签名改造:/flush_cache handler 从无参的 flush_cache() 改为 flush_cache(timeout: Optional[float] = None),使 FastAPI 能把 ?timeout=60 绑定为 60.0,缺省时为 None。

  3. 转发逻辑:构造 params = None if timeout is None else {"timeout": timeout};遍历 chain(lb.prefill_urls, lb.decode_urls) 时把 params 传给 aiohttp ClientSession.post。关键设计是仅在调用方提供 timeout 时拼接 query string,省略时 params 为 None、aiohttp 不产生查询串,旧调用方行为完全不变。

  4. 测试配套:没有新增测试文件。mini_lb 无 in-tree 单测框架,作者用行为验证(FastAPI 参数绑定、aiohttp 查询串拼接、ruff/black/py_compile 检查)取代,并多次 /rerun-test 运行 test/registered/disaggregation/test_disaggregation_dp_attention.py,最终在 8-gpu-h20 上通过。

文件 模块 状态 重要度
sgl-model-gateway/bindings/python/src/sglang_router/mini_lb.py 负载均衡 modified 6.52

关键符号

flush_cache

关键源码片段

sgl-model-gateway/bindings/python/src/sglang_router/mini_lb.py data-contract

本 PR 唯一改动文件:/flush_cache handler 从无参改为接受可选 timeout 参数,并在调用方提供时通过 aiohttp params 转发给全部 prefill/decode worker,是修复的核心。

# sgl-model-gateway/bindings/python/src/sglang_router/mini_lb.py
# /flush_cache 在 FastAPI 应用中注册为 POST 端点。@app.post("/flush_cache")
async def flush_cache(timeout: Optional[float] = None):
    # 关键语义:调度器的 SchedulerFlushWrapper 会把 timeout_s <= 0 解释为
    # " 立即 flush、跳过 idle 检查 ",因此这里绝不能丢弃调用方传入的 timeout,
    # 否则上游只会在 PD KV 传输进行中释放缓存,导致真实的传输失败并被
    # MooncakeKVManager 拉黑 peer session。
    # timeout 未提供时保持旧行为:params 为 None,aiohttp 不拼接 query string。
    params = None if timeout is None else {"timeout": timeout}
​
    async with aiohttp.ClientSession() as session:
        # 对 prefill 与 decode 全量 worker 做扇出,逐台转发 flush_cache 请求。
        tasks = []
        for server in chain(lb.prefill_urls, lb.decode_urls):
            tasks.append(session.post(f"{server}/flush_cache", params=params))
        for i, response in enumerate(asyncio.as_completed(tasks)):
            await response
    return Response(status_code=200)

评论区精华

PR 归因更正:本修复并非 dp_attention CI 失败的真因 question

ShangmingCai 在评论区更正 PR body 的 framing:PD disaggregation 测试通过 PDDisaggregationServerBase.launch_lb 传 --mini-lb 前置的是另一处 mini_lb,experimental/sgl-router 不在此路径,因此本 PR 不应被归因为修复 test_disaggregation_dp_attention.py 的失败;真实修复在 #36152。作者同时强调本缺陷独立且真实地存在。

结论:本 PR 修复独立缺陷,不改变 dp_attention 失败归因;读者应把 #36152 视为该 CI 失败的实际修复。 · 已解决

测试覆盖与验证方式:mini_lb 无 in-tree 测试框架 测试

作者说明 mini_lb 没有单元测试 harness,修复以行为验证(FastAPI 绑定 ?timeout=60 得 60.0、无参数得 None、aiohttp params 拼接结果)代替提交测试,并表示欢迎维护者要求引入 harness。

结论:本次以行为验证代替单测,未新增测试文件;后续可考虑为 mini_lb 建立测试框架。 · 已解决

风险与影响

  1. 兼容性风险低:timeout 缺省时 params 为 None,行为与旧版一致。
  2. 测试缺失:mini_lb 无 in-tree 测试框架,修复依赖手工行为验证,同类缺陷后续可能再次放行。
  3. Rust router(experimental/sgl-router/src/server/routes/cache.rs)存在同一个缺陷——无 query extractor、裸 worker URL,PR 明确留给后续单独修复,因此被该 router 前置的部署仍会命中同样的 race。
  4. 调度器 timeout_s <= 0 的立即 flush fast path 仍是 footgun:任何其他省略 timeout 的调用方依然会触发立即 flush,语义设计未改变。
  5. MooncakeKVManager 单次 ret != 0 永久拉黑 peer session、恢复探针默认关闭(30s 间隔)的放大机制未在本 PR 处理,偶发失败仍可能被放大为大规模请求失败。

用户侧:经该 router 的 Python binding(sglang_router/mini_lb.py)前置的 PD 部署,flush_cache 的 timeout 语义得到修复,SchedulerFlushWrapper 的延迟排空路径(is_fully_idle 门控,含 disagg_prefill_inflight_queue、disagg_decode_transfer_queue、prealloc/retracted 队列)变为可达,避免 KV flush 打断在途传输。系统侧:影响面限于 admin 端点的一次查询参数透传,不涉及模型输出、kernel 或 forward 路径,属于低风险小改动。团队侧:作者在 PR body 和评论区厘清了从参数丢弃到 Mooncake 黑名单放大的完整缺陷链,为后续修复 Rust router 同缺陷和黑名单恢复策略提供了分析基础。

无自动化测试覆盖 Rust router 同缺陷未修 调度器立即 flush fast path 仍是陷阱 Mooncake 黑名单放大未处理

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论