Prhub

#42206 [Metrics] Add group-aware KV cache capacity to vllm:cache_config_info

原始 PR 作者 chfeng-cs 合并时间 2026-06-12 19:49 文件变更 7 提交数 4 评论 19 代码增减 +75 / -26

执行摘要

为 vllm:cache_config_info 添加 group-aware KV cache 容量指标

Addresses the Prometheus vs. startup-log discrepancy for KV cache capacity in #42024. The startup log already reports the correct group-aware KV cache capacity for hybrid models, but Prometheus did not expose matching info in vllm:cache_config_info.

值得精读,特别是以下设计决策:

  • 如何将运行时计算的状态从 engine core 通过 ReadyResponse 同步到前端。
  • compute_hash 忽略字段的处理确保新增字段不影响编译图。
  • per-engine 与总和的取舍体现了对 DP 架构的正确建模。
讨论亮点

主要讨论集中在三个设计决策:

  • 不要新增独立 Prometheus gauge:markmc 要求避免增加新指标,而是将字段追加到已有的 vllm:cache_config_info,作者同意并移除独立 gauge。
  • 复用现有计算逻辑:markmc 建议重构 _report_kv_cache_config 为公共计算函数,作者实现 get_kv_cache_capacity 并在两处调用。
  • 测试文件选择:markmc 认为 AI 生成的完整单元测试过于臃肿,应集成到现有 test_metrics.py 中,作者移除独立测试文件并添加少量断言。
    此外,gemini-code-assist 指出 DP 模式下应跨 engine 求和,但作者坚持 per-engine 语义且 markmc 最终批准,未修改。

实现拆解

  1. 重构容量计算:将 _report_kv_cache_config 改为公开函数 get_kv_cache_capacity,返回 (num_tokens, max_concurrency) 元组;将日志调用移入 get_kv_cache_configs 中,避免重复。
  2. CacheConfig 新增字段:在 CacheConfig 中增加 kv_cache_size_tokenskv_cache_max_concurrency 两个 init=False 的字段,并在 compute_hash 的忽略因子中添加,避免影响编译哈希。
  3. engine core 初始化时填充:在 V1Engine._initialize_kv_caches 中分配 KV cache 后,调用 get_kv_cache_capacity 并写入 cache_config,随后在 process_input_sockets 中作为 EngineCoreReadyResponse 的一部分发送给前端。
  4. 前端同步:在 MPClient._apply_ready_response 中从 response 同步两个字段到本地 cache_config。采用先有值不覆盖的策略,且不跨 DP 累加(保持 per-engine 语义)。
  5. 测试配套:在 tests/entrypoints/serve/instrumentator/test_metrics.py 中增加对 vllm:cache_config_info 标签值的断言,验证两个字段不为空。同时微调 test_kv_cache_utils.py 适应重构。
文件 模块 状态 重要度
vllm/v1/core/kv_cache_utils.py 缓存工具 modified 7.56
vllm/v1/engine/core_client.py 客户端 modified 6.4
vllm/v1/engine/core.py 引擎核心 modified 6.02
vllm/config/cache.py 配置层 modified 5.57
vllm/v1/engine/__init__.py 协议定义 modified 5.33
tests/entrypoints/serve/instrumentator/test_metrics.py 指标测试 modified 4.78
tests/v1/core/test_kv_cache_utils.py 缓存测试 modified 4.26

关键符号

get_kv_cache_capacity _apply_ready_response _initialize_kv_caches process_input_sockets compute_hash

关键源码片段

vllm/v1/core/kv_cache_utils.py core-logic

核心计算逻辑:新增 `get_kv_cache_capacity` 函数,替代 `_report_kv_cache_config`;在 `get_kv_cache_configs` 中内联日志调用。

# 来源文件 : vllm/v1/core/kv_cache_utils.py# --- 核心计算函数:获取 group-aware KV cache 容量 ---
def get_kv_cache_capacity(
    vllm_config: VllmConfig, kv_cache_config: KVCacheConfig
) -> tuple[int, float]:
    """
    Get the group-aware KV cache token capacity and max concurrency.
    """
    max_model_len = vllm_config.model_config.max_model_len
    # 从 group-aware 并发度计算 tokens 容量
    max_concurrency = get_max_concurrency_for_kv_cache_config(
        vllm_config, kv_cache_config
    )
    # 容量(单位 : tokens)= max_concurrency * max_model_len
    return int(max_concurrency * max_model_len), max_concurrency# --- 在 get_kv_cache_configs 中替代旧 _report_kv_cache_config 调用 ---
if len(kv_cache_config.kv_cache_groups) > 0:
    max_model_len = vllm_config.model_config.max_model_len
    num_tokens, max_concurrency = get_kv_cache_capacity(
        vllm_config, kv_cache_config
    )
    logger.info_once("GPU KV cache size: %s tokens", f"{num_tokens:,}")
    logger.info_once(
        "Maximum concurrency for %s tokens per request: %.2fx",
        f"{max_model_len:,}",
        max_concurrency,
    )
vllm/v1/engine/core_client.py core-logic

前端同步关键:在 `_apply_ready_response` 中从 response 读取并写入 cache_config,采用 per-engine 语义。

# 来源文件 : vllm/v1/engine/core_client.py# --- 多点进程前端中同步 engine core 返回的 KV cache 容量 ---
def _apply_ready_response(self, payload: bytes) -> None:
    # ... 前置代码处理 num_gpu_blocks, block_size 同步 ...
    cache_config = vllm_config.cache_config
    cache_config.block_size = response.block_size
​
    # 不跨 DP 累加,保持 per-engine 值
    cache_config.kv_cache_size_tokens = (
        getattr(cache_config, "kv_cache_size_tokens", None)
        if getattr(cache_config, "kv_cache_size_tokens", None) is not None
        else response.kv_cache_size_tokens
    )
    cache_config.kv_cache_max_concurrency = (
        getattr(cache_config, "kv_cache_max_concurrency", None)
        if getattr(cache_config, "kv_cache_max_concurrency", None) is not None
        else response.kv_cache_max_concurrency
    )
    # ...

评论区精华

不要新增独立 Prometheus gauge,改为追加到 cache_config_info 设计

markmc: "Let's not add new metrics - add them to `vllm:cache_config_info`"

结论:作者移除独立 gauge 并改用 cache_config_info 扩展标签。 · 已解决

复用 _report_kv_cache_config 计算逻辑 设计

markmc: "I'd prefer this to reuse the `_report_kv_cache_config()` code somehow, even if it means a little refactoring"

结论:作者重构为公开函数 `get_kv_cache_capacity`,日志调用移至 `get_kv_cache_configs`。 · 已解决

测试应集成到现有 test_metrics.py 而非新建文件 测试

markmc: "I'd expect to see a pretty minimal test of `vllm:cache_config_info` in `tests/entrypoints/serve/instrumentator/test_metrics.py` rather than all of this"

结论:作者移除独立测试文件,在现有 test_metrics.py 中添加少量断言。 · 已解决

DP 模式下应跨 engine 求和还是保持 per-engine 正确性

gemini-code-assist: "The group-aware capacity metrics should be summed across DP engines, similar to how num_gpu_blocks is handled"

结论:作者坚持 per-engine 语义,注释说明不求和的原因,markmc 最终批准,未采纳求和建议。 · 已解决

风险与影响

  1. per-engine 值可能误导:在 DP 部署中,两个指标反映单个 engine 的容量而非集群总量,用户若将它们理解为全局容量会导致误判。代码注释和 commit message 已说明语义,但文档未同步更新。
  2. 仅 v1 路径生效:旧版 v0 engine 代码路径未覆盖,仍缺失这两个字段,向前兼容性良好但可能造成混淆。
  3. 核心路径变更_initialize_kv_caches_apply_ready_response 均在核心初始化/同步路径上,任何计算错误可能导致容量报告异常。
  4. 前端兼容性EngineCoreReadyResponse 新增可选字段,旧前端反序列化时需忽略额外字段,msgspec 默认忽略 unknown,风险较低。

用户:混合模型用户现在可以通过 Prometheus 直接查看准确的 KV cache 容量,无需手动计算。per-engine 语义需在文档中明确。
系统:无性能影响,仅增加一次同步调用和两个字段存储。
团队:为未来更细粒度的 KV cache 监控提供基础。

核心路径变更 per-engine 值需谨慎解释 v0 未覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论