Prhub

#35669 Feature/offloading manager stats

原始 PR 作者 Srinivasoo7 合并时间 2026-06-10 20:44 文件变更 14 提交数 27 评论 152 代码增减 +1200 / -213

执行摘要

为 KV offload 管理器添加标准化 Telemetry 接口

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

该PR值得深度阅读,特别是对设计可扩展监控系统的开发者。关键决策在于自描述扁平统计载荷的设计和deprecation迁移策略。建议结合RFC(#44008)形成的指标重设计思路来理解整体演进方向。

讨论亮点

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字段)进行序列化,使得接收端无需预知定义即可解析统计载荷。

实现拆解

实现步骤:

  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中新增DirectionalTransferStatsTransferStats两个@dataclass,分别记录load/store方向的字节、耗时和size列表,支持aggregateis_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_statsself.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 指标层 modified 8.84
vllm/v1/kv_offload/base.py 抽象层 modified 7.97
vllm/distributed/kv_transfer/kv_connector/v1/offloading/common.py 工人统计 modified 7.9
vllm/distributed/kv_transfer/kv_connector/v1/offloading/scheduler.py 调度层 modified 7.89
tests/v1/kv_connector/unit/offloading_connector/test_metrics.py 测试指标 modified 7.52
tests/v1/kv_connector/unit/test_offloading_connector.py 集成测试 modified 7.15

关键符号

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 core-logic

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

# 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"):
        # ...

评论区精华

数据结构扁平化还是嵌套 设计

orozery 提议使用嵌套的 transfers/gauges 两层字典,markmc 则建议编码在 key 前缀中(如 xfer:... 和 counter:...)。Srinivasoo7 最终采用扁平键方案,但后来 orozery 进一步改为完全扁平的独立 metric name 加 types 元数据,形成最终的 _StatsKey 方案。

结论:采用自描述的扁平结构,顶层 data 包含 types 和 data 两个子键,类型信息随载荷序列化。 · 已解决

stores_skipped 应为 Counter 还是 Gauge 正确性

markmc 指出 FilteredOffloadingManager 中的 stores_skipped 是单调递增计数,在 Prometheus 术语中应定义为 Counter 而非 Gauge。orozery 同意。

结论:最终定义为 Counter,通过 increase_counter 方法上报。 · 已解决

Deprecation 政策:是否需要保留旧指标 设计

orozery 最初认为没人依赖旧指标,可直接切换。markmc 引用了官方 deprecation policy,要求保留一个周期。Srinivasoo7 最终添加了 _DEPRECATED_CONNECTOR_METRIC_DEFINITIONS 块,在相同数据源上同时更新新旧两组 Prometheus 指标。

结论:保留旧名称(vllm:kv_offload_total_bytes 等)作为 deprecated 指标,与新扁平指标并存,遵循 deprecation policy。 · 已解决

动态指标定义应放在 Manager 还是 Spec 上 设计

orozery 坚持不应硬编码 Manager 指标,应通过 OffloadingManager 类方法动态注册。markmc 也赞同通过类方法获取定义,但建议用全局注册表的替代方案。最终设计为 OffloadingSpec 的 build_metric_definitions 类方法,再由 OffloadPromMetrics 在 __init__ 时遍历所有定义创建 prometheus metric。

结论:采用 OffloadingSpec.build_metric_definitions 类方法作为唯一入口,Manager 不直接暴露指标定义。 · 已解决

指标元数据在 IPC 序列化中丢失 正确性

orozery 发现在 e2e 测试中,metric metadata 未随 self.data 序列化,导致接收端无法解析载荷类型。他提议将元数据编码进 data 字典本身。最终修改了 OffloadingConnectorStats 的 data 结构,加入 _StatsKey.TYPES 子键保存 metric 类型。

结论:将类型元数据嵌入 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 指标双写维护

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论