Prhub

#25184 [SMG] Fix cache-aware policy pool isolation in PD mode

原始 PR 作者 Kangyan-Zhou 合并时间 2026-05-14 11:07 文件变更 4 提交数 3 评论 1 代码增减 +744 / -72

执行摘要

修复 PD 模式下 cache-aware 策略池隔离 bug

在 PD 模式下,prefill 和 decode 工作者共享同一个 CacheAwarePolicy trie,该 trie 键仅包含 model_id。每个 select_worker 调用末尾的 tree.insert 导致针对同一 prompt 交替的 prefill 和 decode 请求互相覆盖租户条目,缓存感知路由退化为随机工作者选择(flip-flop)。

对于使用 sgl-model-gateway 且启用 PD 模式 + cache-aware 路由策略的团队,此 PR 必须合入以解决缓存路由失效问题。其设计决策(复合键隔离、独立策略实例)值得在高可用路由设计时参考。审查者可以重点关注 cache_aware.rs 中的键构造函数和 registry.rs 中的分发逻辑。

讨论亮点

本 PR 未产生实质 review 讨论,reviewer slin1237 直接批准了此 PR。PR 描述中详尽分析了根因和修复方案。

实现拆解

  1. 引入池隔离的 trie 键(cache_aware.rs):新增 pool_tagmake_tree_keytree_key_for_worker 三个辅助函数,将 trie 的键从单一的 model_id 改为 pool::model 复合字符串。修改 init_workersadd_workerremove_workerselect_worker 等方法,使其在访问 trie 时使用复合键;移除了不再需要的 add_worker_by_url 方法。
  2. 添加 PD 工作者移除分发(registry.rs):新增 remove_pd_worker_from_cache_aware 方法,根据 WorkerType 将移除请求分发给 prefill_policydecode_policy(而非统一的 model_policies),对 Regular 类型直接返回。
  3. 工作者注册时初始化 PD 池策略(update_policies.rs):在 per-model 的策略初始化循环之后,额外检查 prefill 和 decode 池是否配置了 cache_aware 策略,若是则调用 init_pd_cache_aware_policies 为两个池的 CacheAwarePolicy 实例播种 worker。
  4. 工作者移除时同步清理 PD 池(remove_from_policy_registry.rs):在原有的 remove_worker_from_cache_aware 调用之后,新增对 remove_pd_worker_from_cache_aware 的调用,确保 PD 池的 trie 也同步清理。
  5. 添加回归测试(cache_aware.rs tests 模块):新增三个测试用例:两个池分别使用独立策略时的隔离、单个共享策略回归场景(使用复合键仍保持隔离),以及 PD worker 移除后另一池的 trie 不受影响。
文件 模块 状态 重要度
sgl-model-gateway/src/policies/cache_aware.rs 策略层 modified 9.05
sgl-model-gateway/src/policies/registry.rs 策略层 modified 7.1
sgl-model-gateway/src/core/steps/worker/shared/update_policies.rs 工作流步骤 modified 6.13
sgl-model-gateway/src/core/steps/worker/local/remove_from_policy_registry.rs 工作流步骤 modified 5.31

关键符号

pool_tag make_tree_key tree_key_for_worker remove_pd_worker_from_cache_aware

关键源码片段

sgl-model-gateway/src/policies/cache_aware.rs data-contract

核心变更文件,引入池隔离的 trie 键,修改所有相关方法

/// 根据 WorkerType 返回池标签,用于构建隔离的 trie 键
fn pool_tag(worker_type: &WorkerType) -> &'static str {
    match worker_type {
        WorkerType::Regular => "regular",
        WorkerType::Prefill { .. } => "prefill",
        WorkerType::Decode => "decode",
    }
}/// 构建复合键 `pool::model`
fn make_tree_key(pool: &str, model: &str) -> String {
    format!("{}::{}", pool, model)
}/// 从 worker 直接获取其 trie 键
fn tree_key_for_worker(worker: &dyn Worker) -> String {
    make_tree_key(
        pool_tag(worker.worker_type()),
        normalize_model_key(worker.model_id()),
    )
}// 在 init_workers 中,改为按复合键分组
pub fn init_workers(&self, workers: &[Arc<dyn Worker>]) {
    // 按 (pool, model) 分组,确保每个池拥有独立的 trie
    let mut grouped: std::collections::HashMap<String, Vec<&Arc<dyn Worker>>> =
        std::collections::HashMap::new();
    for worker in workers {
        grouped
            .entry(tree_key_for_worker(worker.as_ref()))
            .or_default()
            .push(worker);
    }
    // 为每个复合键创建或获取对应的 trie 并插入所有 worker URL
    for (tree_key, pool_workers) in grouped {
        let tree = self
            .trees
            .entry(tree_key)
            .or_insert_with(|| Arc::new(Tree::new()));
        for worker in pool_workers {
            tree.insert("", worker.url());
        }
    }
}
sgl-model-gateway/src/policies/registry.rs data-contract

新增 PD 工作者从 cache-aware 策略中移除的分发方法

/// 根据 WorkerType 将 PD worker 从对应池的 cache-aware 策略中移除
pub fn remove_pd_worker_from_cache_aware(&self, worker: &dyn Worker) {
    // 根据 worker 类型选择正确的池策略实例
    let policy = match worker.worker_type() {
        crate::core::WorkerType::Prefill { .. } => self.prefill_policy.get(),
        crate::core::WorkerType::Decode => self.decode_policy.get(),
        crate::core::WorkerType::Regular => return, // 常规 worker 由 model_policies 处理
    };
    if let Some(policy) = policy {
        // 仅当策略为 cache_aware 时才执行移除
        if policy.name() == "cache_aware" {
            if let Some(cache_aware) = policy.as_any().downcast_ref::<CacheAwarePolicy>() {
                cache_aware.remove_worker(worker);
                debug!(
                    "已从 cache-aware 策略中移除 PD worker {} ({})",
                    worker.url(),
                    worker.worker_type()
                );
            }
        }
    }
}

评论区精华

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

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

风险与影响

  1. mesh 同步兼容性CacheAwarePolicyapply_remote_tree_operation 方法仍使用 model_id 作为键,若 mesh 同步侧的树操作也需适配复合键,可能出现键不匹配导致树状态不同步。当前 PR 未修改 mesh 同步相关代码,需确认网格集群中是否启用 PD + cache-aware 策略。
  2. 运行中升级兼容性:复合键的改变会导致内存中已有 trie 键与新键不匹配。重启 worker 后通过 init_workers 可重建 trie;但若使用持久化 trie(当前未启用),则需数据迁移。
  3. WorkerType 依赖remove_pd_worker_from_cache_aware 的正确性依赖 WorkerType 的正确设置,若 worker 类型设置错误可能导致清理遗漏或误清理。
  4. 性能影响:新增的字符串拼接和匹配操作对性能影响极小,可忽略。

影响范围限于启用了 PD 模式且配置了 cache_aware 路由策略的 SMG 用户。修复后,prefill 和 decode 池的缓存树互不干扰,缓存感知路由恢复正常,避免退化为随机选择。对常规(非 PD)模式无影响。团队在升级此 PR 后,若使用 PD + cache-aware 策略,建议重启所有 worker 以确保 trie 重建。影响程度中等。

mesh 同步兼容性 运行中升级需重启 WorkerType 依赖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论