# PR #35669 完整报告

- 仓库：`vllm-project/vllm`
- 标题：Feature/offloading manager stats
- 合并时间：2026-06-10 20:44
- 原文链接：http://prhub.com.cn/vllm-project/vllm/pull/35669

---

# 执行摘要

- 一句话：为 KV offload 管理器添加标准化 Telemetry 接口
- 推荐动作：该 PR 值得深度阅读，特别是对设计可扩展监控系统的开发者。关键决策在于自描述扁平统计载荷的设计和 deprecation 迁移策略。建议结合 RFC（#44008）形成的指标重设计思路来理解整体演进方向。

# 功能与动机

PR body 明确指出需要为 OffloadingManager 接口标准化统计上报方式，以支持 block-reuse 频率追踪等可观测性需求。原本的 OffloadingConnectorStats 只硬编码了 transfer_type→ops_list 的结构，无法灵活扩展新的标量统计项；而当前设计需要新增一个通用的、可让 OffloadingManager 自定义指标的上报通道。

# 实现拆解

实现步骤：
1. 在 `vllm/v1/kv_offload/base.py` 中新增 `OffloadingMetricMetadata` 及其子类（Counter/Gauge/Histogram），并在 `OffloadingManager` 抽象类中增加 `get_stats()` 默认返回 None，同时增加 `OffloadingSpec` 类的 `build_metric_definitions` 类方法。
2. 在 `vllm/distributed/kv_transfer/kv_connector/v1/offloading/common.py` 中新增 `DirectionalTransferStats` 和 `TransferStats` 两个 @dataclass，分别记录 load/store 方向的字节、耗时和 size 列表，支持 `aggregate` 和 `is_empty`，并将 `transfer_stats` 字段插入 `OffloadingWorkerMetadata` 中，使得工人端的传输统计能够随元数据上报至调度器。
3. 在 `vllm/distributed/kv_transfer/kv_connector/v1/offloading/metrics.py` 中进行大规模重构：
 - 定义 `_TransferMetricName` 常量（如 load_bytes、load_time 等）作为扁平指标名称。
 - 定义 `_MetricType` 和 `_StatsKey` 以支持自描述的序列化格式，`OffloadingConnectorStats.data` 现在由 `{types: {name: type}, data: {name: value}}` 结构构成。
 - 添加 `get_connector_metric_definitions()` 返回 connector 固有的 6 个指标（load/store 的 bytes、time、size），以及遗留的 3 个 deprecated 指标（vllm:kv_offload_total_bytes 等）用于向后兼容迁移。
 - `OffloadPromMetrics.observe()` 新实现改为按 metric name 从 `self._offloading_manager_metric_metadata` 中查找类型，然后调用对应的 inc/observe/set。
4. 在 `vllm/distributed/kv_transfer/kv_connector/v1/offloading/scheduler.py` 中：
 - `OffloadingConnectorScheduler` 新增 `_connector_stats` 字段，`update_connector_output()` 中将工人上报的 TransferStats 拆解为 flat connector stats 并聚合。
 - 新增 `get_stats()` 方法，合并来自 `self._connector_stats` 和 `self.manager.get_stats()` 的结果。
5. `FilteredOffloadingManager`（在 `cpu/manager.py` 中作为内部装饰器）的 `get_stats()` 返回 stores_skipped 计数，其定义在 `CPUOffloadingSpec.build_metric_definitions()` 中注册。
6. 测试配套：`tests/v1/kv_connector/unit/offloading_connector/test_metrics.py` 彻底重写，添加了对 OffloadingConnectorStats 各种聚合语义、自描述载荷、deprecated 兼容过渡等的单元测试；`tests/v1/kv_connector/unit/test_offloading_connector.py` 新增 `test_cpu_offloading_metrics` 端到端测试，使用 LLM 实例实际运行并检查 Prometheus 注册表中的新指标；`tests/v1/kv_offload/cpu/test_manager.py` 增加 stores_skipped 计数器测试。

关键文件：
- `vllm/distributed/kv_transfer/kv_connector/v1/offloading/metrics.py`（模块 指标层；类别 source；类型 core-logic；符号 _TransferMetricName, _TransferType, get_connector_metric_definitions, _MetricType）: 核心指标文件，新增了扁平指标名称定义、自描述统计载荷结构、deprecated 指标兼容块，以及 OffloadPromMetrics 对动态指标定义的支持。占总变更行数约 65%。
- `vllm/v1/kv_offload/base.py`（模块 抽象层；类别 source；类型 core-logic；符号 OffloadingMetricMetadata, OffloadingCounterMetadata, OffloadingGaugeMetadata, OffloadingHistogramMetadata）: 抽象基类新增指标元数据类层次结构、get_stats 方法、OffloadingSpec 的 build_metric_definitions 类方法，为所有 OffloadingManager 实现提供了标准化扩展点。
- `vllm/distributed/kv_transfer/kv_connector/v1/offloading/common.py`（模块 工人统计；类别 source；类型 core-logic；符号 DirectionalTransferStats, TransferStats, OffloadingWorkerMetadata.transfer_stats）: 新增 DirectionalTransferStats 和 TransferStats 两个 dataclass，用于在工人端收集按方向分类的传输统计信息，并嵌入 OffloadingWorkerMetadata 随元数据上报。
- `vllm/distributed/kv_transfer/kv_connector/v1/offloading/scheduler.py`（模块 调度层；类别 source；类型 core-logic；符号 __init__, update_connector_output, get_stats）: 调度器侧集成：在 update_connector_output 中拆解工人上报的 TransferStats 为扁平 ConnectorStats；新增 get_stats() 方法合并管理器指标。
- `tests/v1/kv_connector/unit/offloading_connector/test_metrics.py`（模块 测试指标；类别 test；类型 test-coverage；符号 _FakeMetric, _FakeVllmConfig, _metric_metadata, test_build_kv_connector_stats_with_none）: 全面重写的单元测试，覆盖新的 OffloadingConnectorStats 各种聚合、扁平载荷序列化、deprecated 兼容等各类场景。
- `tests/v1/kv_connector/unit/test_offloading_connector.py`（模块 集成测试；类别 test；类型 test-coverage；符号 test_cpu_offloading_metrics, _get_counter_value, _get_histogram_count）: 新增端到端集成测试 test_cpu_offloading_metrics，使用 LLM 实例实际运行并验证 Prometheus 注册表中出现新的扁平指标和遗留指标。

关键符号：OffloadingManager.get_stats, OffloadingSpec.build_metric_definitions, OffloadingConnectorStats.increase_counter, OffloadingConnectorStats.set_gauge, OffloadingConnectorStats.observe_histogram, OffloadingConnectorStats.aggregate, OffloadingConnectorStats.reduce, OffloadingConnectorStats.reset, DirectionalTransferStats.aggregate, DirectionalTransferStats.record, TransferStats.aggregate, OffloadingWorkerMetadata.aggregate, OffloadingConnectorScheduler.__init__, OffloadingConnectorScheduler.update_connector_output, OffloadingConnectorScheduler.get_stats, OffloadPromMetrics.__init__, OffloadPromMetrics.observe, get_connector_metric_definitions, CPUOffloadingSpec.build_metric_definitions

## 关键源码片段

### `vllm/v1/kv_offload/base.py`

抽象基类新增指标元数据类层次结构、get_stats 方法、OffloadingSpec 的 build_metric_definitions 类方法，为所有 OffloadingManager 实现提供了标准化扩展点。

```python
# vllm/v1/kv_offload/base.py

@dataclass(frozen=True)
class OffloadingMetricMetadata:
    """所有指标元数据的基类：包含说明文字。"""
    documentation: str


@dataclass(frozen=True)
class OffloadingCounterMetadata(OffloadingMetricMetadata):
    """单调递增计数的元数据。"""
    pass


@dataclass(frozen=True)
class OffloadingGaugeMetadata(OffloadingMetricMetadata):
    """可上下波动的瞬时值的元数据。"""
    pass


@dataclass(frozen=True)
class OffloadingHistogramMetadata(OffloadingMetricMetadata):
    """分布直方图的元数据，可选 bucket 边界。"""
    buckets: tuple[float, ...] | None = None


class OffloadingManager(ABC):
    # ... 原有抽象方法 ...

    def get_stats(self) -> "OffloadingConnectorStats | None":
        """
        返回自上次调用后收集的统计信息，若未启用则返回 None。
        子类可以重写此方法来提供 Manager 特有的指标（如 stores_skipped）。
        """
        return None

    # ... shutdown 等方法 ...


class OffloadingSpec(ABC):
    @classmethod
    def build_metric_definitions(
        cls, vllm_config: "VllmConfig"
    ) -> dict[str, "OffloadingMetricMetadata"]:
        """
        返回此 Spec 所需的 Prometheus 指标定义字典。
        key 是 metric name，value 是对应的元数据对象。
        """
        return {}

    def __init__(self, vllm_config: "VllmConfig", kv_cache_config: "KVCacheConfig"):
        # ...

```

# 评论区精华

Review 中最核心的讨论包括：
1. **数据结构扁平化还是嵌套 **→ 最终采用扁平键结构（如 `xfer:cpu_to_gpu_total_bytes` 前缀），而不是嵌套的 `transfers/gauges` 两层字典。此决策由 markmc 提出，orozery 和 Srinivasoo7 采纳。
2. **stores_skipped 应为 Counter 还是 Gauge**→ markmc 指出这是一个单调递增计数，Prometheus 术语上应该是 Counter；最终实现中将其作为 Counter 定义。
3. **Deprecation 政策 **→ orozery 最初倾向于直接切换新指标，但 markmc 引用了官方 deprecation policy 要求保留旧指标一个周期。最终在 `_DEPRECATED_CONNECTOR_METRIC_DEFINITIONS` 中保留了旧名称，通过相同数据源同时更新新旧两组 Prometheus 指标。
4. **动态指标定义 **→ orozery 坚持不应硬编码 Manager 指标在 connector metrics 中，应通过 `OffloadingManager.get_metric_definitions()` 类方法动态注册。最终设计采用了 `build_metric_definitions` 类方法，并由 `OffloadPromMetrics` 在 `__init__` 时遍历所有指标定义并创建对应的 Prometheus metric 对象。
5. **序列化元数据 **→ orozery 发现指标元数据在 IPC 序列化时会丢失，为此将元数据作为 `self.data` 的一部分（`_StatsKey.TYPES` 字段）进行序列化，使得接收端无需预知定义即可解析统计载荷。

- 数据结构扁平化还是嵌套 (design): 采用自描述的扁平结构，顶层 data 包含 types 和 data 两个子键，类型信息随载荷序列化。
- stores_skipped 应为 Counter 还是 Gauge (correctness): 最终定义为 Counter，通过 increase_counter 方法上报。
- Deprecation 政策：是否需要保留旧指标 (design): 保留旧名称（vllm:kv_offload_total_bytes 等）作为 deprecated 指标，与新扁平指标并存，遵循 deprecation policy。
- 动态指标定义应放在 Manager 还是 Spec 上 (design): 采用 OffloadingSpec.build_metric_definitions 类方法作为唯一入口，Manager 不直接暴露指标定义。
- 指标元数据在 IPC 序列化中丢失 (correctness): 将类型元数据嵌入 data.types 字段，使得载荷完全自描述。

# 风险与影响

- 风险：技术风险：
 - 向后兼容风险：废弃的旧指标名称（vllm:kv_offload_total_bytes 等）目前同时被更新，但如果在测试覆盖不足的情况下，可能出现旧指标值与新指标值不一致。由于内部逻辑确保从同一份统计数据双写，风险可控。
 - 性能影响：每个 scheduler step 都需要序列化 / 反序列化统计载荷，增加了 IPC 大小。但统计数据通常较小（n 个 block 级别），且仅当有传输操作时才产生，所以影响可接受。
 - 聚合语义混淆：OffloadingConnectorStats 现在需要根据 _MetricType 执行不同的聚合（counter 求和、gauge 取最新、histogram 追加列表）。如果元数据与数据不一致（如未正确注册类型），聚合结果可能出错。已在测试中覆盖各类场景。
- 影响：影响范围：
 - 用户：如果监控了旧的 vllm:kv_offload_* 指标，将在 v0.16.x（假设）内继续看到兼容的值；新的扁平指标（vllm:kv_offload_load_bytes 等）将提供更明确的语义。新指标默认启用，用户无需配置即可获得 stores_skipped（当 store_threshold >=2 时）等新监控项。
 - 系统：内部统计数据结构完全改变，但封装在 OffloadingConnectorStats 类中，对外部模块（如 KVConnectorLogging）仅暴露 reduce() 的输出，不受影响。
 - 团队：后续新增 OffloadingManager 实现必须覆盖 get_stats() 和 build_metric_definitions 类方法，提供标准化接口。
 - 风险标记：核心路径变更 , IPC 序列化兼容性 , deprecated 指标双写维护

# 关联脉络

- PR #35342 Unknown (mentioned in PR body): 本 PR body 中提到 'Since we merged PR #35342'，表明 #35342 可能增加了 offloading manager 的基础设施，本 PR 在此基础上添加统计功能。尽管 #35342 不在提供的历史列表中，但基于 PR 讨论，它直接关联。