执行摘要
- 一句话:TTFT 指标按流模式拆分
- 推荐动作:值得合入,改动清晰且符合监控最佳实践。建议补充一个单元测试验证标签写入,并在合并后通知运维团队更新 Dashboard 查询。
功能与动机
监控场景需要区分流式与非流式请求的首Token延迟,以便更准确地分析性能异常。PR body 明确说明“Split sglang:time_to_first_token_seconds by streaming mode so dashboards can compare TTFT for streaming and non-streaming requests”。
实现拆解
- metrics_collector.py:直方图初始化时将
"stream" 加入 labelnames;方法 observe_time_to_first_token 新增 stream: bool 参数,调用时根据其值将 stream 标签设为 "true" 或 "false"。
- tokenizer_manager.py:
collect_metrics 在调用 observe_time_to_first_token 时,通过 getattr(state.obj, "stream", False) 获取请求的流模式并传递。
- check_time_to_first_token_straggler 中固定使用
stream="true" 的桶,确保 straggler 检测只基于流式请求的分位数,避免非流式请求的分布影响异常判定。
关键文件:
python/sglang/srt/observability/metrics_collector.py(模块 可观测性;类别 source;类型 core-logic;符号 observe_time_to_first_token): 核心变更文件:TTFT 直方图增加 stream 标签,observe_time_to_first_token 方法签名和实现修改,straggler 检测适配。
python/sglang/srt/managers/tokenizer_manager.py(模块 调度器;类别 source;类型 core-logic): 调用方修改:从请求对象获取 stream 标志并传递。
关键符号:observe_time_to_first_token, check_time_to_first_token_straggler, collect_metrics
关键源码片段
python/sglang/srt/observability/metrics_collector.py
核心变更文件:TTFT 直方图增加 stream 标签,observe_time_to_first_token 方法签名和实现修改,straggler 检测适配。
def __init__(self, ...):
# ...
self.histogram_time_to_first_token = Histogram(
name="sglang:time_to_first_token_seconds",
documentation="Histogram of time to first token in seconds.",
# 新增 stream 标签,区分流式与非流式请求
labelnames=[*labels.keys(), "stream"],
buckets=bucket_time_to_first_token,
)
# ...
def observe_time_to_first_token(
self, labels: Dict[str, str], value: float, *, stream: bool
):
# 根据 stream 参数设置标签值 "true" 或 "false"
self.histogram_time_to_first_token.labels(
**labels, stream="true" if stream else "false"
).observe(value)
def check_time_to_first_token_straggler(self, value: float) -> bool:
# straggler 检测仅基于流式请求的分位数
his = self.histogram_time_to_first_token.labels(**self.labels, stream="true")
total_observations = sum(bucket._value for bucket in his._buckets)
if total_observations < 100:
return False
p99_threshold = total_observations * 0.99
cumulative_count = 0
for i, bucket in enumerate(his._buckets):
cumulative_count += bucket._value
if cumulative_count > p99_threshold:
return value >= his._upper_bounds[i]
return False
python/sglang/srt/managers/tokenizer_manager.py
调用方修改:从请求对象获取 stream 标志并传递。
def collect_metrics(self, state: ReqState, recv_obj: BatchStrOutput, i: int):
# ...
if not state.ttft_observed and self.disaggregation_mode != DisaggregationMode.PREFILL:
state.ttft_observed = True
state.last_completion_tokens = completion_tokens
self.metrics_collector.observe_time_to_first_token(
labels,
state.time_stats.get_first_token_latency(),
# 从请求对象获取 stream 标志,默认为 False
stream=getattr(state.obj, "stream", False),
)
# ...
评论区精华
无 Review 讨论。PR 提交后由 gemini-code-assist 发表了一个已弃用的自动评论,无实质内容。
风险与影响
- 风险:
- 回归风险低:变更量小(+12/-5),仅追加一个标签和传递一个布尔值,逻辑清晰。
- straggler 行为变化:
check_time_to_first_token_straggler 从使用无 stream 过滤的直方图改为固定 stream=true,若历史上 straggler 检测涵盖非流式请求,行为可能变窄,需确认是否预期。
- 缺少测试覆盖:PR 未新增对应测试用例,无法验证
stream 标签是否正确写入。
- 影响:影响范围小,仅修改可观测性模块。现有 Dashboard 若依赖原 sglang:time_to_first_token_seconds 无 stream 标签的时序,需更新 PromQL 以兼容新增标签(如加入 {stream="true"} 或 {stream="false"} 过滤)。
- 风险标记:缺少测试覆盖, straggler 行为变更
关联脉络
参与讨论