[Bug] TieringOffloadingSpec fs-tier lookup succeeds but never triggers a promotion job (active_promotion_jobs stays 0)

该现象出现在 vLLM 使用 OffloadingConnector + TieringOffloadingSpec 的 "fs" 二级缓存、两个独立引擎实例共享同一 root_dir 时:B 实例查询 A 写入的前缀后, vllm:kv_offload_tiering_active_promoti

快速结论:该现象出现在 vLLM 使用 OffloadingConnector + TieringOffloadingSpec 的 "fs" 二级缓存、两个独立引擎实例共享同一 root_dir 时:B 实例查询 A 写入的前缀后,vllm:kv_offload_tiering_active_promotion_jobs:('1:fs',) 始终为 0,B 回退到全量重算。优先排查的是:把 active_promotion_jobs 当成”是否发生 promotion”的判据是否成立,以及 chunk_queries/lookup_async_delay_seconds 是否被误读为命中证据。

适用环境:vLLM 0.31.0(镜像 vllm/vllm-openai:v0.31.0);模型 meta-llama/Llama-3.1-8B-Instruct;两个实例各 1 张 GPU、位于不同主机;--block-size 64;两侧均设置 PYTHONHASHSEED=123。原始报告使用 3FS over FUSE 挂载,后续复测改用普通共享 POSIX 网络文件系统(非 3FS)。

最快修复方案:暂无确认的一步修复方案。Issue 最终未复现该问题,原报告中的若干判据被作者本人撤回;在更新后的共享 POSIX 复测中,lookup 命中 67/67、read_bytes 达到 562,036,736,external_prefix_cache_hits 为 4,288(= 67 × 64),promotion 路径本身工作正常。

注意事项:本次复测不在 3FS 上进行(作者因无关的 3FS RDMA 问题无法重跑),因此 3FS/FUSE 场景下的行为仍属未验证;维护者的本地探针也只覆盖本地文件系统上的源码级测试,不代表 Llama 服务部署或 3FS 环境的完整复现。

问题场景

用户在 vLLM 中启用 KV 缓存分层卸载:双实例(native1 / native2)各启动一个引擎,均配置 OffloadingConnector、kv_role: kv_both,并通过 kv_connector_extra_config 指定 TieringOffloadingSpec,cpu_bytes_to_use 为 10737418240、block_size 为 64,二级层为 {"type":"fs","root_dir":"","n_read_threads":16,"n_write_threads":16}。先由实例 A 写入一个新前缀,等待约 20 秒后由实例 B 以相同前缀首次查询,期望 B 从 fs 层提升(promotion)数据而非重算。

报错原文

[Bug] TieringOffloadingSpec fs-tier lookup succeeds but never triggers a promotion job (active_promotion_jobs stays 0)

vllm:kv_offload_tiering_active_promotion_jobs:('1:fs',)  # stayed at 0 for the entire test

ERROR [thread_pool.py:181] Job 0 block I/O failed: [Errno 17] File exists:
.../1870b67d5b659d799e715c585ce8d3e9e0a4e8e2c01131bcc00f51eb23bde6af.bin

原因分析

按 Issue 最终结论,原报告的核心判断不成立,已由报告作者逐条更正:

  • 不能以 active_promotion_jobs 判断是否发生 promotion。它是当前进行中任务的瞬时计数,请求结束后回落为 0 属正常。维护者与作者一致确认:该 gauge 只反映仍在运行的 job。复测中 B 在请求期间约每 20 ms 采样,90 次里 7 次大于 0、72 次里 7 次大于 0,峰值为 1,请求前后均为 0。
  • chunk_queries 与 lookup_async_delay_seconds 不能作为命中证据。二者在 miss 时同样会记录,因此原报告”lookup 确实找到了条目”的说法缺乏证据;3FS 那次运行也没有记录 chunk_hits、read_bytes 或 promotion_allocation_failures。
  • 路径与哈希未出现不匹配。独立初始化的进程在 PYTHONHASHSEED=123 下生成相同的哈希与文件名,A 存储的 67 个文件与 B 查询的 67 个路径完全一致,全部命中。
  • 并发写导致的 EEXIST 属于另一条问题(由 #61390 覆盖):内容寻址块已被另一写入方落盘时,被计为 cascade_job_failure,而非按”去重后无需操作”处理。

综上,在共享 POSIX 文件系统上,未复现”lookup 成功但不触发 promotion”的主问题;3FS 挂载下是否仍存在差异,可能原因尚未隔离。

环境排查

  • vLLM 版本是否为 0.31.0(或对应镜像),以及是否包含 #61390 相关修复。
  • 两个实例的 PYTHONHASHSEED 是否严格一致(复测使用 123)。
  • --block-size、模型路径、--kv-transfer-config 的 cpu_bytes_to_use、block_size 和 secondary_tiers 参数是否两侧完全一致。
  • root_dir 是否为两侧可见且可读写的同一挂载;3FS over FUSE 与普通 POSIX 网络文件系统需分开验证。
  • GPU 数量、是否启用 --enable-prefix-caching --enforce-eager,以及主机间网络文件系统的读写可见性延迟。
  • 指标采样方式:是否在 active_promotion_jobs 的采样中覆盖了请求运行期间,而非只读请求前后的值。

解决步骤

  1. 先纠正判据:不要只看请求结束后的 active_promotion_jobs,改为在请求执行期间高频采样;同时收集 chunk_queries、chunk_hits、read_bytes、promotion_allocation_failures、promotion_job_failures、cascade_job_failures、external_prefix_cache_hits 与 GPU prefix_cache_hits 的增量。
  2. 确认 A 写入的文件名与 B 查询的文件名是否一一对应(可优先尝试增加仅记录日志的 lookup 包装,不改变返回值),排除 key/path 不一致。
  3. 核对两侧 PYTHONHASHSEED、--block-size 与 kv-transfer-config 是否逐字一致。
  4. 在普通共享 POSIX 文件系统上复跑一次单前缀的两实例测试,记录上述指标与请求后新增 .bin 文件数;若 0 个新增且 external_prefix_cache_hits 等于命中块数,则说明 fs 层复用生效。
  5. 若仅在 3FS over FUSE 下复现,将问题限定到文件系统语义层排查;否则继续对照 chunk_hits 与 read_bytes 判断是未命中、命中但受限于 CPU 容量,还是命中但指标采样未覆盖。
  6. 遇到并发写 EEXIST 报错时,按 #61390 追踪写入侧去重逻辑,不要与 promotion 问题混为一谈。

验证方法

在 B 首次请求同一前缀期间,若 active_promotion_jobs 出现非零采样(复测中峰值为 1)、chunk_hits 等于 chunk_queries、read_bytes 与 A 的 write_bytes 一致(复测均为 562,036,736)、external_prefix_cache_hits 等于命中块数 × 64(复测为 4,288),且 B 未新增任何 .bin 文件、各类 failure 计数为 0,即可确认 fs 层 lookup 与 promotion 链路正常。注意该结论仅在复测所用的共享 POSIX 文件系统上成立。

参考来源

vllm-project/vllm #61373

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29398

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注