DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

SGLang 缓存回载报错

SGLang 旧版在 EAGLE 与 LMCache MP 模式下,外部 KV 回载后报 pool memory leak detected。核对页大小、重复计数路径及统一缓存实现的版本边界。

SGLang 第一次请求正常,重复同一段前缀、从 LMCache 回载 KV 后,调度器却报:

ValueError: pool memory leak detected!

如果日志里的 available + evictable 反而大于 total,先核对旧版 LMCache 与 EAGLE 的组合。这个故障已有 SGLang 0.5.20 部署反馈,出在缓存树重复计算同一段 KV,不应直接按普通显存不足处理。

哪种缓存命中会触发

需要同时满足:启用了 EAGLE 或 EAGLE3 推测解码,LMCache 使用外部 daemon 的 MP 模式,page_size > 1,并且请求真正从外部存储回载了已有前缀。

只有 --enable-lmcache,或者重复请求仅命中了 GPU 内的前缀缓存,还不足以对应本问题。应结合既有日志确认外部 KV 的 RETRIEVE 或 load-back 路径。若预热请求已经命中了旧缓存,错误也可能在启动时出现,不能仅凭发生时间排除它。

保留当前软件版本、镜像、模型与 draft 模型、页大小和 LMCache 配置。故障反馈中的环境包含 ROCm,但已核对的根因在 radix key 的表示与计数路径;没有依据把所有 ROCm 崩溃都归到这里。

旧实现把同一段 KV 记了两次

0.5.20 的 lmc_radix_cache.py 中,match_prefix 先复制页对齐的 key,再调用基础缓存的匹配逻辑。EAGLE 路径会把基础 key 转为 bigram 表示,提前复制出的 key 却没有跟着改变。

正常写入缓存树的 key 已经是 bigram;回载标记仍保留普通 token 表示。两者不能匹配到同一个节点,回载时便可能为同一段 token 再挂一个 radix 节点,并再次增加 evictable 计数。调度器下一次检查池状态,发现可用与可回收之和超过总量,才抛出上面的错误。

这解释了为什么冷请求可以完成,暖缓存回载却失败。增大显存预算或缩短输入,不能修正 key 的不一致。关闭池检查也只是隐藏了计数错误。

核对实际装入的缓存实现

已核对的正式版 0.5.21 使用 lmcache_unified_radix_cache.py,移除了旧的 lmc_radix_cache.py。新实现创建回载 key 时明确设置 is_bigram=self.tree_core.is_eagle,后续切片保留该标记,避免了旧实现先复制、后转换造成的不一致。

旧部署应选择包含这套修复、又与模型和 LMCache 兼容的发行版。切换前保存可回退的镜像与配置,核对实际加载的模块路径;自建镜像或下游 fork 即使显示了新版版本号,也可能仍带着旧文件。不能把此故障写成所有 0.5.x 或正式版 0.5.21 都存在的问题。

暂时无法升级时,可在获准的测试环境中分别关闭 EAGLE、停用外部 LMCache,判断是否确实由这一组合触发。它们会改变推理与缓存行为,不能未经评估直接套到生产。page_size=1 在旧实现中能避开这处切片差异,但模型和后端是否支持该设置还要单独核对,不作为通用修复建议。

不需要为了这处计数缺陷删除整个外部 KV 存储,也不要复制未经合入的零散补丁替代正式实现。

验收必须覆盖外部回载

只看服务启动成功,或只发一个冷请求,会漏掉触发路径。应在获准的测试环境中覆盖前缀首次存储和后续真实外部回载,确认没有再次出现池计数错误;同时检查未命中与命中缓存时的模型输出,保留原模型、精度和 draft 配置作为对照。

若已经使用统一缓存实现,仍出现 pool memory leak detected!,应重新收集完整池状态与调用路径。这个报错是池一致性检查的结果,其他分配、释放或缓存所有权问题也可能触发,不能因为报错相同就继续沿用旧 radix key 的结论。