Prhub

#27612 [router] Add /flush_cache endpoint to experimental sgl-router

原始 PR 作者 Kangyan-Zhou 合并时间 2026-06-09 09:53 文件变更 4 提交数 1 评论 1 代码增减 +409 / -0

执行摘要

给实验性路由器添加 /flush_cache 端点

根据 PR body 的描述,添加该端点的动机是 'Add an endpoint to flush the cache for all the workers to the experimental router',即提供一个管理接口,允许运维人员一键刷新所有 worker 的 KV 缓存,避免逐个手动操作。

值得精读。该 PR 实现清晰,设计决策明确(如绕过断路器、并发限制、错误报告格式)。对于需要扩展类似管理端点的开发者,是很好的参考。

讨论亮点

当前 PR 没有 review 评论,讨论主要集中于 PR body 中说明的设计决策,例如绕过断路器(circuit breaker)直接使用共享 reqwest client,以及无法从 HTTP 响应区分 flush 是立即执行还是延迟执行的问题。

实现拆解

  1. 新增路由处理文件 experimental/sgl-router/src/server/routes/cache.rs,定义了 FlushCacheResultFailedWorker 序列化结构体,实现 flush_cache 异步处理函数和 fan_out_flush 并发扇出辅助函数。
  2. 扩展 WorkerRegistryexperimental/sgl-router/src/workers/registry.rs 中添加 pub fn all(&self) -> Vec<Arc<Worker>> 方法,返回所有注册 worker(不分模型和模式)的快照,并为此新增了两个单元测试。
  3. 挂载路由experimental/sgl-router/src/server/app.rsbuild_router 中通过 .route("/flush_cache", post(crate::server::routes::cache::flush_cache)) 注册新端点。
  4. 导出模块experimental/sgl-router/src/server/routes/mod.rs 中添加 pub mod cache; 声明,使 cache 模块对外可见。
  5. 测试覆盖cache.rs 中包含了 10 个与 flush_cache 相关的测试,涵盖全部成功、部分失败、空 fleet、不可达 worker、非 5xx 状态码、尾部斜杠 URL 以及不同模式 worker 的场景。
文件 模块 状态 重要度
experimental/sgl-router/src/server/routes/cache.rs 路由器 added 9.36
experimental/sgl-router/src/workers/registry.rs 路由器 modified 7.38
experimental/sgl-router/src/server/app.rs 路由器 modified 5.18
experimental/sgl-router/src/server/routes/mod.rs 路由器 modified 4.65

关键符号

flush_cache fan_out_flush all from_outcomes FlushCacheResult::from_outcomes

关键源码片段

experimental/sgl-router/src/workers/registry.rs core-logic

基础数据结构扩展:新增 `all()` 方法,支持全量 worker 快照,是 fan-out 的前提。

/// Snapshot of every registered worker, across all models and modes.
/// Used by fleet-wide admin fan-out (e.g. `/flush_cache`) that targets
/// every worker the router knows about rather than one model's pool.
/// Order is unspecified (iterates the underlying `DashMap`).
pub fn all(&self) -> Vec<Arc<Worker>> {
    self.by_id.iter().map(|e| Arc::clone(e.value())).collect()
}

对应的测试:
#[test]
fn all_returns_every_worker_across_models_and_modes() {
    let r = WorkerRegistry::default();
    let _ = r.add(spec("w1", WorkerMode::Plain, &["m1"]));
    let _ = r.add(spec("p", WorkerMode::Prefill, &["m2"]));
    let _ = r.add(spec("d", WorkerMode::Decode, &["m2"]));
    let mut ids: Vec<String> = r.all().into_iter().map(|w| w.id.0.clone()).collect();
    ids.sort();
    assert_eq!(ids, vec!["d", "p", "w1"]);
}#[test]
fn all_is_empty_for_fresh_registry() {
    assert!(WorkerRegistry::default().all().is_empty());
}

评论区精华

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

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

风险与影响

  1. 状态一致性风险flush_cache 绕过断路器直接发送请求,若大量 worker 处于断路器打开状态,扇出可能造成请求堆积或超时,且无法恢复断路器状态。
  2. 延迟可见性:SGLang worker 的 /flush_cache 在等待请求完成时返回 200 但可能延迟执行,而本端点只依赖 HTTP 状态码,运维人员可能误以为立即生效。
  3. 并发开销:使用 buffer_unordered(32) 限制并发,但对于数千 worker 的大集群,超时和错误处理可能仍会带来瞬时压力。
  4. 连接复用:直接使用共享 reqwest::Client,若该 client 的 keep-alive 策略不当,可能影响其他正常请求。

影响范围:仅影响 experimental/sgl-router 模块,新增的管理端点对外暴露,需要认证/授权措施(当前未实现)。
影响程度:中等偏低。新功能为可选操作,不影响核心请求路由路径,但提供了一项重要的运维能力。若不暴露在公网,风险可控。

绕过断路器可能影响一致性 无法区分延迟刷新 无大规模集群并发测试

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论