Prhub

#25631 Move idle-metrics logging to SchedulerMetricsReporter

原始 PR 作者 fzyzcjy 合并时间 2026-05-18 18:42 文件变更 3 提交数 1 评论 1 代码增减 +44 / -61

执行摘要

将空闲指标日志移至 MetricsReporter 组件

该 PR 是调度器重构链的一部分,旨在逐步将 Scheduler 类的混合职责拆解为独立的组件类。_maybe_log_idle_metrics 原本位于 SchedulerRuntimeCheckerMixin 中,该混入类混合了运行时检查与指标记录双重职责。将其移至 SchedulerMetricsReporter 使得指标收集逻辑更加内聚,并让 SchedulerRuntimeCheckerMixin 可以最终被移除(后续 PR)。

作为重构序列中的一环,推荐阅读以理解团队如何将大混入类拆解为细粒度组件。SchedulerMetricsReporter 中的 _maybe_log_idle_metrics 方法展示了组件如何通过 self.scheduler 反向引用调度器状态,是一种常见的组件交互模式。

讨论亮点

该 PR 无 review 评论(review 数为 0),提交信息明确描述为纯重定位,无行为变化。

实现拆解

  1. metrics_reporter.py 中新增 _maybe_log_idle_metrics 方法:复制原方法主体,将所有 self.X 状态访问替换为 self.scheduler.X(如 self.scheduler.running_batchself.scheduler.waiting_queue 等),因为 SchedulerMetricsReporter 持有指向调度器的反向引用。
  2. scheduler_runtime_checker_mixin.py 中删除整个文件和类:由于方法已移出,该文件不再需要,彻底删除。
  3. scheduler.py 中进行三处配套调整:删除导入 SchedulerRuntimeCheckerMixin;从 Scheduler 类的基类列表中移除 SchedulerRuntimeCheckerMixin;在 on_idle() 中将 self._maybe_log_idle_metrics() 改为 self.metrics_reporter._maybe_log_idle_metrics()
文件 模块 状态 重要度
python/sglang/srt/managers/scheduler_runtime_checker_mixin.py 调度器 removed 7.58
python/sglang/srt/managers/scheduler_components/metrics_reporter.py 调度器 modified 7.28
python/sglang/srt/managers/scheduler.py 调度器 modified 5.0

关键符号

_maybe_log_idle_metrics

关键源码片段

python/sglang/srt/managers/scheduler_components/metrics_reporter.py core-logic

新增 _maybe_log_idle_metrics 方法,核心迁移目标文件。

# 此方法从 SchedulerRuntimeCheckerMixin 原样迁移至 SchedulerMetricsReporter ,
# 唯一变化是所有 self.X 状态引用改为 self.scheduler.X (因为
# SchedulerMetricsReporter 通过 self.scheduler 持有调度器引用),池统计
# 方法调用改为 self.scheduler.pool_stats_observer.X() 形式。
def _maybe_log_idle_metrics(self):
    """Collect and log metrics every 30 seconds during idle."""
    if (
        not self.current_scheduler_metrics_enabled
        or time.perf_counter() <= self.metrics_collector.last_log_time + 30
    ):
        return
​
    self.scheduler.pool_stats_observer.get_pool_stats().update_scheduler_stats(
        self.stats
    )
    self.stats.num_streaming_sessions = (
        self.scheduler.pool_stats_observer.streaming_session_count()
    )
    self.stats.streaming_session_held_tokens = (
        self.scheduler.pool_stats_observer.session_held_tokens()
    )
​
    priority_enabled = self.scheduler.enable_priority_scheduling
    self.stats.num_running_reqs = QueueCount.from_reqs(
        self.scheduler.running_batch.reqs, priority_enabled
    )
    self.stats.gen_throughput = 0
    self.stats.num_queue_reqs = QueueCount.from_reqs(
        self.scheduler.waiting_queue, priority_enabled
    )
    self.stats.num_grammar_queue_reqs = len(self.scheduler.grammar_manager)
​
    if self.scheduler.disaggregation_mode == DisaggregationMode.PREFILL:
        self.stats.num_prefill_bootstrap_queue_reqs = QueueCount.from_reqs(
            self.scheduler.disagg_prefill_bootstrap_queue.queue, priority_enabled
        )
        self.stats.num_prefill_inflight_queue_reqs = QueueCount.from_reqs(
            self.scheduler.disagg_prefill_inflight_queue, priority_enabled
        )
    if self.scheduler.disaggregation_mode == DisaggregationMode.DECODE:
        self.stats.num_decode_prealloc_queue_reqs = QueueCount.from_reqs(
            self.scheduler.disagg_decode_prealloc_queue.queue, priority_enabled
        )
        self.stats.num_decode_transfer_queue_reqs = QueueCount.from_reqs(
            self.scheduler.disagg_decode_transfer_queue.queue, priority_enabled
        )
​
    self.metrics_collector.log_stats(self.stats)

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

由于是纯代码移动,几乎不存在回归风险。主要风险在于对调度器状态的间接访问(self.scheduler.X)可能存在遗漏或不一致的属性名,但通过逐一检查原方法与迁移后方法的每一行可确保一致性。未涉及性能关键路径,且已通过 CI(虽然 pr-test 显示缺少 run-ci 标签,但作者认为无风险直接合入)。

对最终用户无影响,因为无行为变更。对开发团队而言,这是调度器架构重构的一步,有利于后续维护和代码可读性。SchedulerRuntimeCheckerMixin 文件被删除,相关依赖的开发者需注意该混入类已不再存在。

低风险纯重构

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论