执行摘要
- 一句话:为KV offload管理器添加标准化Telemetry接口
- 推荐动作:该PR值得深度阅读,特别是对设计可扩展监控系统的开发者。关键决策在于自描述扁平统计载荷的设计和deprecation迁移策略。建议结合RFC(#44008)形成的指标重设计思路来理解整体演进方向。
功能与动机
PR body明确指出需要为OffloadingManager接口标准化统计上报方式,以支持block-reuse频率追踪等可观测性需求。原本的OffloadingConnectorStats只硬编码了transfer_type→ops_list的结构,无法灵活扩展新的标量统计项;而当前设计需要新增一个通用的、可让OffloadingManager自定义指标的上报通道。
实现拆解
实现步骤:
- 在
vllm/v1/kv_offload/base.py中新增OffloadingMetricMetadata及其子类(Counter/Gauge/Histogram),并在OffloadingManager抽象类中增加get_stats()默认返回None,同时增加OffloadingSpec类的build_metric_definitions类方法。
- 在
vllm/distributed/kv_transfer/kv_connector/v1/offloading/common.py中新增DirectionalTransferStats和TransferStats两个@dataclass,分别记录load/store方向的字节、耗时和size列表,支持aggregate和is_empty,并将transfer_stats字段插入OffloadingWorkerMetadata中,使得工人端的传输统计能够随元数据上报至调度器。
- 在
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。
- 在
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()的结果。
FilteredOffloadingManager(在cpu/manager.py中作为内部装饰器)的get_stats()返回stores_skipped计数,其定义在CPUOffloadingSpec.build_metric_definitions()中注册。
- 测试配套:
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实现提供了标准化扩展点。
# 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中最核心的讨论包括:
- 数据结构扁平化还是嵌套 → 最终采用扁平键结构(如
xfer:cpu_to_gpu_total_bytes前缀),而不是嵌套的transfers/gauges两层字典。此决策由markmc提出,orozery和Srinivasoo7采纳。
- stores_skipped应为Counter还是Gauge → markmc指出这是一个单调递增计数,Prometheus术语上应该是Counter;最终实现中将其作为Counter定义。
- Deprecation政策 → orozery最初倾向于直接切换新指标,但markmc引用了官方deprecation policy要求保留旧指标一个周期。最终在
_DEPRECATED_CONNECTOR_METRIC_DEFINITIONS中保留了旧名称,通过相同数据源同时更新新旧两组Prometheus指标。
- 动态指标定义 → orozery坚持不应硬编码Manager指标在connector metrics中,应通过
OffloadingManager.get_metric_definitions()类方法动态注册。最终设计采用了build_metric_definitions类方法,并由OffloadPromMetrics在__init__时遍历所有指标定义并创建对应的Prometheus metric对象。
- 序列化元数据 → 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讨论,它直接关联。
参与讨论