Prhub

#26812 Add a periodic full-radix-tree KV-canary sweep

原始 PR 作者 fzyzcjy 合并时间 2026-05-31 09:56 文件变更 22 提交数 1 评论 1 代码增减 +797 / -35

执行摘要

为 KV-canary 添加定期全 radix 树扫描

常规 KV-canary 每步只验证当前请求的 HEAD/TAIL 槽位,但缓存在 radix 树中长期不活跃的 KV 槽位可能发生静默损坏而不被察觉。定期全树扫描填补了这一可观测性盲区,确保所有缓存 KV 的完整性得到周期性验证。

本 PR 设计清晰,模块划分合理,单元测试覆盖全面,推荐详细了解 radix 树遍历和 SWA 索引映射的实现细节,这些设计模式在类似的可观测性模块中有借鉴意义。建议在合并后关注 long-running 场景下的性能表现。

讨论亮点

本 PR 无实际 review 讨论,仅有一条来自 gemini-code-assist 的配额提醒,未涉及技术内容。

实现拆解

  1. 配置入口(server_args.py:新增 ServerArgs.kv_canary_sweep_interval 参数,通过 CanaryConfig.sweep_interval 传递到下游。
  2. Radix 树遍历器(radix_cache_walker.py:实现 walk_radix_cache_for_canary 函数,递归遍历 radix 树所有非空节点,输出平铺的 slot_indicespositionsprev_slot_indices 张量。支持 unlocked_only(跳过锁定节点)和 swa_resident_only(跳过 SWA 墓碑节点)两种过滤模式。
  3. 扫描计划构造器(sweep_plan_builder.pybuild_verify_plan_radix_sweep 函数接收遍历结果,构造 VerifyPlan 用于 kernel 执行。处理 SWA 池的索引映射:通过 _swa_translate 将 full 池索引转换为 SWA 池索引,并保留 evicted 槽位(值为 0)作为 padding 哨兵。
  4. 扫描编排器(runner/sweep.pySweepOrchestrator 管理扫描节奏。maybe_run_sweep 在每步 _post_ops_outside_graph 中被调用,检查自上次扫描是否已超过 sweep_interval 步,若是则遍历所有 buffer_group,为每个 group 构建扫描计划并发射 sweep kernel。attach_radix_cache 由调度器在 radix cache 构建完成后注入。
  5. Kernel 启动路径扩展(endpoint.pykernel_launcher.py:新增 launch_sweeplaunch_endpoints_sweep,并引入 SWEEP_K_FULLSWEEP_V_FULLSWEEP_K_SWASWEEP_V_SWACanaryLaunchTag 枚举值,确保扫描 kernel 的调用可追踪。
  6. 测试(3 个单元测试文件)test_self_unit_radix_walker.py 测试遍历器的各种树结构和过滤选项;test_self_unit_sweep_plan_builder.py 验证扫描计划的构建和 SWA 翻译;test_self_unit_runner_sweep.py 验证扫描编排的节奏、kernel 启动和 plan 分配逻辑。test_self_unit_endpoint.py 增加了 sweep kernel 的专用测试用例。
文件 模块 状态 重要度
python/sglang/srt/kv_canary/radix_cache_walker.py Radix 遍历 added 9.01
python/sglang/srt/kv_canary/runner/sweep.py 扫描调度 added 8.75
python/sglang/srt/kv_canary/sweep_plan_builder.py 扫描计划 added 8.09
test/registered/kv_canary/test_self_unit_radix_walker.py 单元测试 added 7.84
test/registered/kv_canary/test_self_unit_sweep_plan_builder.py 单元测试 added 7.72
test/registered/kv_canary/test_self_unit_runner_sweep.py 单元测试 added 7.71

关键符号

SweepOrchestrator.maybe_run_sweep walk_radix_cache_for_canary build_verify_plan_radix_sweep _walk_radix_subtree launch_endpoints_sweep _swa_translate attach_radix_cache

关键源码片段

python/sglang/srt/kv_canary/runner/sweep.py core-logic

扫描编排器,管理扫描节奏:在每步 forward 后检查是否达到扫描间隔,若满足则触发所有 buffer group 的扫描计划构建和 kernel 发射。

from __future__ import annotations
import logging
from collections.abc import Callable
from typing import TYPE_CHECKING, Optionalfrom sglang.srt.kv_canary.buffer_group import CanaryBufferGroup, PoolKind
from sglang.srt.kv_canary.config import CanaryConfig
from sglang.srt.kv_canary.endpoint import CanaryEndpoint
from sglang.srt.kv_canary.runner.kernel_launcher import launch_endpoints_sweep
from sglang.srt.kv_canary.state import CanaryDeviceState
from sglang.srt.kv_canary.sweep_plan_builder import build_verify_plan_radix_sweepif TYPE_CHECKING:
    from sglang.srt.mem_cache.base_prefix_cache import BasePrefixCachelogger = logging.getLogger(__name__)
​
​
class SweepOrchestrator:
    """扫描编排器,控制定期全 radix 树扫描的节奏与执行"""
​
    def __init__(
        self,
        *,
        config: CanaryConfig,
        device_state: CanaryDeviceState,
        buffer_groups: tuple[CanaryBufferGroup, ...],
        endpoints: tuple[CanaryEndpoint, ...],
        swa_window_size: int,
        outer_step_counter_getter: Callable[[], int],
    ) -> None:
        self._config = config
        self._device_state = device_state
        self._buffer_groups = buffer_groups
        self._endpoints = endpoints
        self._swa_window_size = swa_window_size
        self._outer_step_counter_getter = outer_step_counter_getter
        # radix cache 在调度器构建后才可用,通过 attach_radix_cache 注入
        self._radix_cache: Optional["BasePrefixCache"] = None
​
        self._last_sweep_step: int = -1 # 上次扫描时的 outer step
        self._sweep_passes: int = 0 # 成功扫描次数
​
    @property
    def sweep_passes(self) -> int:
        """返回已成功扫描的次数"""
        return self._sweep_passes
​
    def attach_radix_cache(self, radix_cache: "BasePrefixCache") -> None:
        """注入 radix cache 引用,由调度器在树缓存构建完成后调用"""
        self._radix_cache = radix_cache
​
    def maybe_run_sweep(self) -> None:
        """检查是否需要进行扫描,若是则执行"""
        # 扫描间隔为 0 表示禁用
        if self._config.sweep_interval == 0:
            return
        outer_step_counter = self._outer_step_counter_getter()
        # 检查是否达到间隔步数(首次无条件执行)
        if (
            self._last_sweep_step >= 0
            and outer_step_counter - self._last_sweep_step < self._config.sweep_interval
        ):
            return
        self._last_sweep_step = outer_step_counter
​
        # 尚未注入 radix cache 时跳过
        if self._radix_cache is None:
            return
​
        violation_log = self._device_state.violation_log
        # 对每个 buffer group 构建扫描计划并发射 kernel
        for group in self._buffer_groups:
            # SWA group 使用 SWA window size,非 SWA group 使用 0
            window = self._swa_window_size if group.kind is PoolKind.SWA else 0
            verify_plan = build_verify_plan_radix_sweep(
                radix_cache=self._radix_cache,
                swa_window_size=window,
                full_to_swa_index_mapping=group.swa_index_lut,
            )
            launch_endpoints_sweep(
                endpoints=self._endpoints,
                group=group,
                verify_plan=verify_plan,
                violation_log=violation_log,
            )
​
        self._sweep_passes += 1
        logger.info(
            "[canary] sweep succeeded %d times (last_step=%d)",
            self._sweep_passes,
            outer_step_counter,
        )

评论区精华

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

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

风险与影响

  • 性能:扫描 kernel 每 N 步运行一次,会增加 GPU 执行负载。间隔 N 可配置,建议生产环境中选择较大的 N 或在低峰期运行。
  • 内存:遍历 radix 树可能产生较大的 VerifyPlan(与缓存槽位数线性相关),在大规模缓存场景下需关注显存占用峰值。
  • 兼容性:新功能默认关闭(sweep_interval=0),不影响现有 KV-canary 行为。开启扫描需同时启用 --kv-canary,否则扫描被静默跳过。
  • 耦合风险SweepOrchestrator 与 radix cache 的具体实现(RadixCacheSWARadixCache)直接耦合,若未来引入新的缓存类型需同步修改遍历器。

对用户:新增配置项 --kv-canary-sweep-interval,默认关闭。开启后会在指定间隔执行全缓存验证,增加可观测性但引入额外 GPU 开销。对系统:扩展了 KV-canary 的内部架构,新增模块化组件(遍历器、计划构造器、编排器),为后续更多验证模式(如增量扫描)提供了扩展点。对团队:需要通过性能测试确定合适的扫描间隔默认值,并维护新增组件的单元测试。

新增配置项 性能影响(扫描负载) 与 radix cache 耦合 需同步启用 --kv-canary

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论