Prhub

#26881 [UnifiedTree]: Support l3 storage for swa and deepseek v4

原始 PR 作者 hzh0425 合并时间 2026-06-04 10:17 文件变更 9 提交数 15 评论 19 代码增减 +517 / -65

执行摘要

支持 SWA 和 DeepSeek V4 的 L3 存储

此项变更为 HiCache 的 UnifiedTree 缓存架构添加了 L3 存储层支持,使得 Sliding Window Attention (SWA) 和 DeepSeek V4 这两种特殊的 KV 缓存组件能够利用外部存储后端(文件、Mooncake)进行数据卸载和预取,从而突破 GPU 显存限制,提升长序列推理的缓存命中率。PR 标题和 body 未提供详细动机,但结合关联历史 PR(如 #27072、#27091),HiCache 团队正在系统性完善多级存储层级,此次补全了 SWA 和 DeepSeek V4 的覆盖。

值得精读。该 PR 是 HiCache 多级存储体系的重要拼图,展示了如何将两种特殊注意力组件(SWA 和 DeepSeek V4)集成到统一的 L3 存储架构中。swa_component.py 中的锁分离设计和 mooncake_store.py 的通用池注册重构具有参考价值。建议关注设计讨论中关于 is_rank_replicated 的重命名决策以及 _page_transfer 的顺序依赖问题。

讨论亮点

Review 中主要讨论如下:

  • mla_suffix 硬编码 (ispobock): 指出 storage_component_suffixes 中默认的 mla_suffix 看起来硬编码,仅因当前到达的池都是 MLA 模型才正确。作者 hzh0425 和 huangtingwei9988 参与讨论,最终未在此 PR 中修改,但作为 nit 记录。
  • 字符串属性名 vs 类型安全 (ispobock): 在 swa_component.py 中,使用 getattr/setattr 通过字符串 "host_value"/"value" 来分派设备/主机操作,失去类型检查。建议使用显式 if lock_host: 分支或 ComponentData 类型访问器。作者 hzh0425 回复 "fixed",在最终代码中改为了显式分支。
  • is_mla_backend 的范围 (hzh0425): 在 cache_controller.py 中,作者自己提出需要确认 is_mla_backend 的修改是否正确。ispobock 回复指出 DeepSeek V4 不是 MLA,建议改为 is_rank_replicated。作者采纳,添加 TODO 并在后续 PR 统一重命名。

实现拆解

  1. SWA 组件锁分离:在 swa_component.pyacquire_component_lockrelease_component_lock 中引入 lock_host 参数。当锁定主机时,使用 host_valuehost_lock_ref 字段,并操作 host_lru_lists 而非设备 LRU。这使 SWA 数据安全地在主机内存中维护 LRU,为卸载到 L3 做准备。
  2. 控制器传输顺序调整:在 hybrid_cache_controller.py 中,将 _page_transfer 中的 KV 池传输提前,确保基础 KV 数据到位后才处理额外池(如 SWA),防止因传输失败导致的数据错位。新增 pool_transfers_done 标记,供预取进度查询使用。
  3. Mooncake 存储后端增强:在 mooncake_store.py 中,修改 register_mem_pool_host 以跳过无 kv_buffer 的逻辑锚点池;重写 register_mem_host_pool_v2 以通用方式获取池缓冲区;重构 _get_hybrid_page_component_keys,通过注册池动态解析后缀,替代硬编码的 INDEXER 支持,并统一 MAMBA 和 DRAFT 的后缀生成逻辑。
  4. 侧边池命中策略配置:在 hybrid_pool_assembler.py 中,为 SWA 的 SidecarPoolSpec 设置 hit_policy=PoolHitPolicy.TRAILING_PAGES,优化预取行为;其他池使用默认的 ALL_PAGES。同时导入 PoolHitPolicy
  5. 存储配置修正:在 cache_controller.py_generate_storage_config 中,将 is_mla_backend 扩展为 is_rank_replicated,使 DeepSeek V4 也能被识别为 rank-replicated 模型,从而正确处理存储写回。添加 TODO 准备后续统一重命名。
  6. 单元测试:在 test_unified_radix_cache_unittest.py 中新增辅助函数 _path_chain_write_path_to_l3_flush_l3_backups_run_prefetch_to_completion_all_page_hashes,以及两个测试方法 test_hicache_l3_write_storagetest_hicache_l3_prefetch,验证文件后端的写入和预取完整性。
文件 模块 状态 重要度
python/sglang/srt/mem_cache/unified_cache_components/swa_component.py SWA 组件 modified 8.54
test/registered/unit/mem_cache/test_unified_radix_cache_unittest.py 测试套件 modified 7.71
python/sglang/srt/mem_cache/storage/mooncake_store/mooncake_store.py Mooncake 存储 modified 7.21
python/sglang/srt/mem_cache/hybrid_cache/hybrid_cache_controller.py 混合缓存 modified 6.89
python/sglang/srt/mem_cache/hybrid_cache/hybrid_pool_assembler.py 池组装器 modified 6.34
python/sglang/srt/managers/cache_controller.py 缓存管理 modified 6.06
python/sglang/srt/mem_cache/unified_radix_cache.py 缓存树 modified 5.9
python/sglang/srt/mem_cache/base_prefix_cache.py 基础缓存 modified 4.58
python/sglang/srt/mem_cache/memory_pool_host.py 主机池 modified 4.3

关键符号

_release_swa_host _attach_swa_host_value _commit_prefetch _path_chain _write_path_to_l3 _flush_l3_backups _run_prefetch_to_completion _all_page_hashes test_hicache_l3_write_storage test_hicache_l3_prefetch _init_hicache

关键源码片段

python/sglang/srt/mem_cache/unified_cache_components/swa_component.py core-logic

核心逻辑变更:为 SWA 组件添加 host 级锁和 LRU 支持,使数据能安全卸载到主机内存为 L3 做准备。

def acquire_component_lock(
    self,
    node: UnifiedTreeNode,
    result: IncLockRefResult,
    lock_host: bool = False,
) -> IncLockRefResult:
    ct = self.component_type
    root = self.cache.root_node
    sliding_window_size = self.sliding_window_size
    swa_lock_size = 0
    swa_uuid = None
    # 根据 lock_host 选择使用 host 还是 device 的 uuid 键
    uuid_key = "host_uuid" if lock_host else "uuid"
    # 选择对应的 LRU 列表:host 或 device 级别
    lru = self.cache.host_lru_lists[ct] if lock_host else self.cache.lru_lists[ct]
​
    cur = node
    while cur != root and swa_lock_size < sliding_window_size:
        comp = cur.component_data[ct]
        # 优先使用 host_value,若 lock_host 则检查 host_value,否则检查 value
        value = comp.host_value if lock_host else comp.value
        if value is None:
            # tombstone 节点跳过
            result.skip_lock_node_ids.setdefault(ct, set()).add(cur.id)
            cur = cur.parent
            continue
​
        ref = comp.host_lock_ref if lock_host else comp.lock_ref
        if ref == 0:
            if lock_host:
                # host 锁首次获取时从 host LRU 移除该节点
                if lru.in_list(cur):
                    lru.remove_node(cur)
            else:
                # device 锁首次获取时更新可驱逐 / 保护大小
                key_len = len(cur.key)
                self.cache.component_evictable_size_[ct] -= key_len
                self.cache.component_protected_size_[ct] += key_len
        if lock_host:
            comp.host_lock_ref = ref + 1
        else:
            comp.lock_ref = ref + 1
        swa_lock_size += len(value)
        if swa_lock_size >= sliding_window_size:
            if comp.metadata.get(uuid_key) is None:
                comp.metadata[uuid_key] = next_component_uuid()
            swa_uuid = comp.metadata[uuid_key]
        cur = cur.parent
​
    if lock_host:
        result.swa_uuid_for_host_lock = swa_uuid
    else:
        result.swa_uuid_for_lock = swa_uuid
    return result

(函数展示了 lock_host 分派逻辑,通过选择 host_value/value 和对应的 LRU 列表实现设备/主机锁分离。)

test/registered/unit/mem_cache/test_unified_radix_cache_unittest.py test-coverage

新增 L3 存储的单元测试,覆盖写入和预取路径,验证文件后端下的数据完整性。

def test_hicache_l3_write_storage(self):
    """D->H->L3 offload: every KV page lands in the file storage backend."""
    if self._skip_unsupported_hicache_test():
        return
    if self.cfg.has_mamba:
        self.skipTest("mamba L3 offload is out of scope for this unit fixture")
​
    # 创建临时目录用于文件后端
    storage_dir = tempfile.mkdtemp()
    self.addCleanup(shutil.rmtree, storage_dir, ignore_errors=True)
​
    tree, allocator, req_to_token_pool = build_fixture(self.cfg)
    # 初始化 HiCache,使用文件后端和极低预取阈值
    self._init_hicache(tree, storage_backend="file", storage_dir=storage_dir, prefetch_threshold=1)
​
    seq = self._make_seq(1, 4)
    self._insert(tree, allocator, req_to_token_pool, seq)
    m = tree.match_prefix(MatchPrefixParams(key=RadixKey(array("q", seq))))
    leaf = m.last_device_node
​
    # 先将数据从设备备份到主机
    self._backup_node(tree, leaf)
    self.assertTrue(leaf.hash_value)
    # 将路径上所有节点写入 L3 存储
    self._write_path_to_l3(tree, leaf)
    # 等待备份完成并释放锁
    self._flush_l3_backups(tree)
​
    # 验证所有 KV 页的哈希均存在于存储后端中
    backend = tree.cache_controller.storage_backend
    page_hashes = self._all_page_hashes(tree, leaf)
    self.assertEqual(len(page_hashes), len(seq) // self.cfg.page_size)
    self.assertEqual(backend.batch_exists(page_hashes), len(page_hashes))
    tree.sanity_check()

(测试代码展示了写入验证流程:在 UnifiedTree 上插入序列后,通过 _write_path_to_l3 触发 L3 卸载,最后用 batch_exists 确认所有页面已持久化。)

评论区精华

mla_suffix 默认值硬编码 设计

ispobock 指出 `storage_component_suffixes` 中默认的 mla_suffix 看起来硬编码,仅因当前到达的池都是 MLA 模型才正确。

结论:作为 nit 记录,未在此 PR 修改,留待后续统一处理。 · 待处理

字符串属性名 vs 类型安全 style

ispobock 建议使用显式 `if lock_host:` 分支代替 `getattr/setattr` 字符串操作,以保持类型检查。

结论:作者 hzh0425 回复 "fixed",最终代码采用了显式分支。 · 已解决

is_mla_backend 的范围 正确性

hzh0425 提出需要确认 `is_mla_backend` 的修改是否正确;ispobock 指出 DeepSeek V4 不是 MLA,建议改用 `is_rank_replicated`。

结论:作者采纳建议,添加 TODO 并在后续 PR 统一重命名。 · 已解决

风险与影响

  • 核心路径变更风险:SWA 组件的锁机制和 LRU 管理被显著修改,可能影响所有使用 SWA 的模型(如 DeepSeek V4+SWA 模式),若 host 锁与设备锁切换不当可能导致引用计数错误或主机内存泄漏。
  • Mooncake 存储后端兼容性:注册逻辑的改动可能影响现有 Mamba、Draft 等池的注册,特别是 register_mem_host_pool_v2 中通用的 get_buffers 获取方式需要保证所有池提供兼容接口。
  • 数据一致性风险_page_transfer 中 KV 池传输完成后才处理额外池,如果 KV 池传输部分成功(如超时),pool_transfers_done 标记可能被错误设置,导致预取方认为数据已就绪但实际不完整。
  • 测试覆盖不足:L3 测试仅覆盖文件后端,未覆盖 Mooncake 后端;且只测试了写入和预取基本路径,未测试边界情况如存储后端不可用、并发卸载等。
  • 性能影响:增加 host LRU 列表维护开销在网络传输瓶颈下可忽略,但过多的 host_lock_ref 原子操作可能增加锁争用。
  • 用户影响:使用 HiCache 并启用 --hicache 的用户,若其模型包含 SWA 或 DeepSeek V4 组件,将自动受益于 L3 存储扩展,无需额外配置。存储后端的配置(如文件路径、Mooncake 地址)需要在启动时指定。
  • 系统影响:增加了 UnifiedTree 缓存架构的完整性,SWA 和 DeepSeek V4 现在能够像 FULL 和 MAMBA 一样进行多级存储,减少了 GPU 显存压力,理论上支持更长序列的推理。
  • 团队影响:该 PR 是 HiCache 多级存储路线图中的关键一步,后续可能继续扩展至其他组件(如 MLA、Mamba 等)。代码中留下的 TODO 说明计划后续统一 is_rank_replicated 命名。
核心路径变更 主机锁机制引入 存储注册重构 缺少 Mooncake 后端测试 传输顺序依赖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论