执行摘要
- 一句话:支持 UnifiedRadixCache 的 L3 层级存储后端框架
- 推荐动作:建议重点关注
unified_radix_cache.py 中的预取和备份机制设计,以及 hybrid_cache_controller.py 的配置解析方式。这两个文件是 L3 存储的核心骨架。同时注意 host lock 的组件实现一致性,特别是后续 SWAComponent 的支持。测试用例 test_unified_radix_cache_kl_hicache_part2.py 是 Mamba 混合模型集成的良好参考。
功能与动机
从 PR Body 的 Todo 清单可见,主要驱动力是支持 L3 存储框架,并以此验证 GLM5.1 DSA Model、改进 MambaComponent(Qwen Hybrid Linear Model)、以及后续的 SWAComponent(DeepSeek-V4 Hybrid SWA and sparse model)。目标在于扩展现有 HiCache 容量,将不常用的 KV/Mamba 状态缓存在文件后端,从而在有限显存下支持更长的上下文或更大的模型。
实现拆解
-
扩展 UnifiedRadixCache 核心逻辑:在 unified_radix_cache.py 中新增 get_last_hash_value、get_prefix_hash_values 方法,支持节点哈希计算与路径构建;引入 write_backup_storage、prefetch_from_storage 等函数实现数据从设备到主机再到层级存储的异步写入与预取;新增 inc_host_lock_ref / dec_host_lock_ref 接口管理主机端锁定引用计数。
-
增强 HybridCacheController:在 hybrid_cache_controller.py 中新增 parse_storage_backend_extra_config 静态方法,支持从 JSON/TOML/YAML 文件解析存储后端配置;新增 _init_extra_host_mem_release_queues、append_host_mem_release 等函数实现额外的宿主内存释放队列;重写 _start_storage_threads 以启动这些队列的消费线程。
-
适配 Mamba 和 Full 组件:在 mamba_component.py 与 full_component.py 中修改 acquire_component_lock 和 release_component_lock 以支持 lock_host 参数,从而区分设备锁定和主机锁定;同时在 mamba_component.py 中新增 BACKUP_STORAGE 和 PREFETCH 阶段的传输构建逻辑。
-
重构测试框架:将原有的 GSM8KTwoPassMixin 重命名为 AccuracyTwoPassMixin,并泛化支持 MMLU 等多任务评估;新增 TestUnifiedMambaHiCacheL3 测试类(test_unified_radix_cache_kl_hicache_part2.py)验证 Mamba 模型与文件后端 L3 缓存的集成;修改 hybrid_pool_assembler.py 传递存储后端配置参数给缓存控制器。
-
配套调整:在 unified_cache_components/tree_component.py、swa_component.py、base_prefix_cache.py 中调整配置键传递;移除不再需要的测试用例。
关键文件:
python/sglang/srt/mem_cache/unified_radix_cache.py(模块 缓存层;类别 source;类型 dependency-wiring;符号 get_last_hash_value, get_prefix_hash_values, inc_host_lock_ref, dec_host_lock_ref): 核心变更文件,新增哈希方法、存储备份、预取、主机锁定等关键逻辑,是 L3 存储框架的主入口。
python/sglang/srt/mem_cache/hybrid_cache/hybrid_cache_controller.py(模块 缓存控制;类别 source;类型 entrypoint;符号 _start_storage_threads, parse_storage_backend_extra_config, clear_storage_backend, _init_extra_host_mem_release_queues): 作为缓存控制器的入口,新增配置解析、主机内存释放队列和存储线程管理,统一了不同组件(Full、Mamba、SWA)的存储后端行为。
python/sglang/srt/mem_cache/unified_cache_components/mamba_component.py(模块 Mamba缓存;类别 source;类型 dependency-wiring;符号 acquire_component_lock, release_component_lock, build_hicache_transfers): 实现了 Mamba 组件的主机锁定支持和新阶段的传输构建,是混合模型适配的关键一环。
test/registered/radix_cache/test_unified_radix_cache_kl_hicache_part2.py(模块 集成测试;类别 test;类型 test-coverage;符号 TestUnifiedMambaHiCacheL3, setUpClass, tearDownClass): 新增的 Mamba 混合模型 L3 缓存端到端测试,验证了文件后端与 UnifiedRadixCache 集成的正确性。
关键符号:get_last_hash_value, get_prefix_hash_values, inc_host_lock_ref, dec_host_lock_ref, write_backup_storage, prefetch_from_storage, _prefetch_timeout_check_linear_func, _start_storage_threads, parse_storage_backend_extra_config, clear_storage_backend, _init_extra_host_mem_release_queues, append_host_mem_release, acquire_component_lock, release_component_lock, build_hicache_transfers
关键源码片段
python/sglang/srt/mem_cache/unified_radix_cache.py
核心变更文件,新增哈希方法、存储备份、预取、主机锁定等关键逻辑,是 L3 存储框架的主入口。
# UnifiedTreeNode 类中的哈希相关方法
# 获取当前节点的最后一个哈希值(即该节点自身的哈希,而非路径)
def get_last_hash_value(self) -> Optional[str]:
# 如果 hash_value 为 None 或空列表,则返回 None
if self.hash_value is None or len(self.hash_value) == 0:
return None
# 返回列表中的最后一个元素
return self.hash_value[-1]
# 获取从根到指定节点(node)的完整哈希路径
# 使用 @lru_cache 避免递归重复计算,maxsize=1 表示只缓存最近一次结果
@lru_cache(maxsize=1)
def get_prefix_hash_values(self, node: Optional[UnifiedTreeNode]) -> list[str]:
# 如果 node 为 None 或没有 hash_value,返回空列表
if node is None or node.hash_value is None:
return []
# 递归获取父节点的前缀哈希,并拼接当前节点的 hash_value
return node.get_prefix_hash_values(node.parent) + node.hash_value
python/sglang/srt/mem_cache/hybrid_cache/hybrid_cache_controller.py
作为缓存控制器的入口,新增配置解析、主机内存释放队列和存储线程管理,统一了不同组件(Full、Mamba、SWA)的存储后端行为。
# 静态方法:解析存储后端额外配置
# 支持 JSON 字符串、@ 文件路径(JSON/TOML/YAML)
@staticmethod
def parse_storage_backend_extra_config(
storage_backend_extra_config: Optional[str],
) -> tuple[dict, int, float, float, bool]:
extra_config = {}
if storage_backend_extra_config:
if storage_backend_extra_config.startswith("@"):
# 文件方式:按扩展名选择解析器
path = storage_backend_extra_config[1:]
ext = os.path.splitext(path)[1].lower()
with open(path, "rb" if ext == ".toml" else "r") as f:
if ext == ".json":
extra_config = json.load(f)
elif ext == ".toml":
# 注意:tomllib 仅适用于 Python >= 3.11
import tomllib as toml_parser
extra_config = toml_parser.load(f)
elif ext in (".yaml", ".yml"):
import yaml
extra_config = yaml.safe_load(f)
else:
raise ValueError(f"Unsupported config file {path}")
else:
extra_config = json.loads(storage_backend_extra_config)
# 提取预定键,剩余部分作为额外配置
prefetch_threshold = extra_config.pop("prefetch_threshold", 256)
prefetch_timeout_base = extra_config.pop("prefetch_timeout_base", 1)
prefetch_timeout_per_ki_token = extra_config.pop("prefetch_timeout_per_ki_token", 0.25)
hicache_storage_pass_prefix_keys = extra_config.pop("hicache_storage_pass_prefix_keys", False)
# 类型校验
if not isinstance(prefetch_threshold, int):
raise ValueError(...)
# ... 省略类似校验
return (extra_config, prefetch_threshold, float(prefetch_timeout_base),
float(prefetch_timeout_per_ki_token), hicache_storage_pass_prefix_keys)
python/sglang/srt/mem_cache/unified_cache_components/mamba_component.py
实现了 Mamba 组件的主机锁定支持和新阶段的传输构建,是混合模型适配的关键一环。
# MambaComponent 中重写的 acquire_component_lock
# 新增 lock_host 参数用于锁定主机副本而非设备副本
def acquire_component_lock(
self,
node: UnifiedTreeNode,
result: IncLockRefResult,
lock_host: bool = False, # 新增参数
) -> IncLockRefResult:
ct = self.component_type
if node is self.cache.root_node:
return result
cd = node.component_data[ct]
# 根据 lock_host 选择是访问 host_value 还是 value
value = cd.host_value if lock_host else cd.value
if value is None:
result.skip_lock_node_ids.setdefault(ct, set()).add(node.id)
return result
if lock_host:
# 主机锁:从主机 LRU 中移除节点
if cd.host_lock_ref == 0:
host_lru = self.cache.host_lru_lists[ct]
if host_lru.in_list(node):
host_lru.remove_node(node)
cd.host_lock_ref += 1
else:
# 设备锁:调整 evictable/protected 大小
if cd.lock_ref == 0:
vlen = len(value)
self.cache.component_evictable_size_[ct] -= vlen
self.cache.component_protected_size_[ct] += vlen
cd.lock_ref += 1
return result
评论区精华
Review 中主要讨论如下:
风险与影响
- 风险:
- CPU tensor AllReduce 风险:若
write_backup_storage 等函数中的张量仍保留在 CPU 上,使用 NCCL TP 时将导致运行时错误。虽然 PR 已合并,但应确认生产环境中已正确设置设备。
- Python 版本兼容风险:
parse_storage_backend_extra_config 在 Python 3.9/3.10 下尝试 import tomllib 会失败,导致 TOML 配置解析不可用。
- 主机锁定引用计数:新增的
inc_host_lock_ref / dec_host_lock_ref 逻辑涉及多个组件(Full、Mamba、SWA),若某组件未正确实现,可能导致主机副本被提前释放或永远无法释放,引发数据损坏或内存泄漏。
- 预取超时策略:
_prefetch_timeout_check_linear_func 基于线性时间复杂度的超时检查,可能在高并发请求下成为性能瓶颈,且超时参数需要针对不同负载调优。
- 线程安全:新增的
extra_host_mem_release_queues 及消费线程在并发访问下存在竞态风险,需确保锁机制完整。
- 影响:用户影响:启用 --enable-hierarchical-cache 并设置 --hicache-storage-backend=file 的用户将自动获得 L3 存储能力;新的配置项(如 prefetch_threshold、prefetch_timeout_base)可通过 --hicache-storage-backend-extra-config 调整。
系统影响:增加了 3 个后台线程(用于存储 I/O 与主机内存释放),在低显存环境下可显著降低 cache miss 惩罚,但也会增加 CPU 和内存开销。混合模型(含 Mamba/SWA)的缓存策略得到统一管理,不再需要为不同组件单独维护存储逻辑。
团队影响:代码库复杂度提升,新增的 HybridCacheController 承担了更多职责;测试覆盖了 GLM5 和 Qwen-Next 两种混合模型,为后续扩展提供了参考基线。
- 风险标记:CPU tensor AllReduce 风险, Python 3.9 TOML 兼容, 主机锁定引用计数错误, 预取超时策略可能成为瓶颈
关联脉络
- PR #26301 [HiCache]: Check return code of cudaHostRegister: 同为 HiCache 改进系列的 PR,修复了
cudaHostRegister 返回值检查问题,与当前 PR 的 L3 存储后端共享内存管理基础设施。
参与讨论