TT Lab
博客

한국어 日本語 中文

开始
博客

博客

当文档仍在引用 vLLM 已删除的指标名称时:llm-d 文档 PR 在短短 2 小时 9 分钟内成功合并的全过程

结果:已合并(2026-10-17 03:08, llm-d/llm-d#2835). 事实上,这些数据取自 GitHub 的 PR、评审与检查记录,llm-d 源码(PR 基于的提交 696b5e81)、vLLM 源码(发布标签)、llm-d 自动扩缩器源码(标签 v0.9.0),以及我们留下的实测原始数据。时间均为韩国时间。截至 2026-10-17,尚无包含此变更的 llm-d 版本发布(最新版本为 v0.10.0,发布于 2026-09-29)。

目录

一句话总结

PR llm-d/llm-d#2835 docs: replace vLLM metric names that current vLLM no longer exports
修改内容 仅修改了两个文档和一个仪表盘 JSON 中的指标名称。增加 6 行,删除 6 行
反应 无评审机器人·无行内评论。两个批准(一个无言批准, /lgtm 一个批准),一个站点预览机器人评论
结果 PR 公开 10-17 00:59 → 合并 03:08,约 2 小时 9 分钟。通过 squash 方式合并单个提交(我们的账号为作者)
vLLM 이 지운 이름, 문서에는 남은 이름 vLLM 소스의 폐기 주석과 v0.31.0 /metrics 실측 ① vllm:gpu_prefix_cache_hit_rate V0 엔진의 적중률 게이지 · fairness 가이드 표 0.8 폐기 예고 0.9 숨김 0.10 삭제 가이드가 검증한 0.26 에서도 이미 없음 바꾼 것: rate(hits_total) / rate(queries_total) ② vllm:time_per_output_token_seconds WVA 문서 2곳 · 대시보드 쿼리 3개 0.11 이름 바뀜 0.12 숨김 0.15 삭제 주석은 「0.13 에서 삭제」, 실제로는 0.14 까지 숨김 바꾼 것: vllm:inter_token_latency_seconds ③ v0.31.0 /metrics(작은 무작위 모델, 요청 5개) 옛 이름 둘로 시작하는 줄 0줄 prefix_cache_hits_total / queries_total 640 / 805 inter_token_latency_seconds_count 75 없는 이름을 부르는 쿼리는 오류 없이 빈 결과를 돌려준다 대시보드를 Grafana 에 올려 보지는 않았다(미실측)
图:vLLM 删除的两个名称的生命周期与 v0.31.0 /metrics 实测

1. 问题所在:我们观察到的现象

首先坦白说明,TT Lab 集群中并没有 llm-d。这次的问题并非运营故障,而是在学习过程中遇到的。在阅读围绕 vLLM 引擎的各种项目(production-stack、LMCache、llm-d)的代码时,我们追踪了“引擎定义的指标名称是如何扩散到其他仓库的查询中的”,相关内容已整理在 《阅读开源架构》第 4 篇中。

为了避免仅通过文档字面量比对指标名称,我们在提交 PR 前夕,将 vLLM v0.31.0(vllm/vllm-openai 镜像,当时的最新版本)作为一次性 Pod 运行在小型集群的单个 GPU 节点上(8GB 级别 GPU),并拉取了 /metrics 。为了避免下载任何额外内容,我们仅使用创建了配置文件的随机权重模型(Qwen2 架构,2 层,hidden 256, --load-format dummy),并发送了 5 个前 160 个 token 相同的请求(每个请求生成 16 个 token)。在其输出中,并没有出现 llm-d 文档所引用的名称。

llm-d 文档引用的名称 出处 v0.31.0 /metrics
vllm:gpu_prefix_cache_hit_rate turn-priority-fairness 指南的观测指标表 无
vllm:time_per_output_token_seconds 自动扩缩器 (WVA) 设计文档,指标列表一行与查询表一行 无
vllm:time_per_output_token_seconds_bucket DigitalOcean 仪表盘 “Time Per Output Token Latency” 面板的 3 个查询 无

在原始数据中,以这两个旧名称开头的行为 0 行,取而代之的是以下数值:

vllm:prefix_cache_queries_total{engine="0",model_name="tiny"} 805.0
vllm:prefix_cache_hits_total{engine="0",model_name="tiny"} 640.0
vllm:inter_token_latency_seconds_count{engine="0",model_name="tiny"} 75.0

这些数字与请求的形态完全吻合。5 个请求 × 161 个 token = 805 次查找,其中第一个请求全部未命中,其余四个请求各命中 160 个 token,共计 640 次命中(块大小 16,相同输出的 cache_config_info)。5 个分别生成 16 个 token 的请求,其 token 间的间隔为 15 × 5 = 75。命中率为 640 / 805 ≈ 0.795。

使用不存在的名称编写的 PromQL 不会报错,而是返回空结果(这也是 Prometheus 的常见行为)。按照指南输入查询的读者只会看到“什么都没有输出”,原因只能自己去寻找。仪表盘面板预计也会显示为空,不过我们没有将其上传到 Grafana 进行实际测试(未实测)。

以相同方式对 llm-d v0.10.0 标签的整个文档和指南进行扫描的结果也记录在第 4 篇中。 vllm: 在 71 个名称中,有 40 个存在于输出中,27 个是需要开启离线卸载(offload)或 NIXL 连接器才会出现的条件性指标,还有 4 个在 v0.31.0 的源码中没有定义。其中 4 个中的 3 个属于 time_per_output_token_seconds 系列。由于 PR 是基于 main 分支的,因此 v0.10.0 中尚不存在 fairness 指南。

2. 原因:源码中的哪一行出了问题

llm-d 的行号基于 PR 的基础提交 696b5e81 ,而 vLLM 基于发布标签。

引擎端:名称正如预告的那样消失了

vLLM 在删除指标时遵循一套明确的规则。根据 docs/usage/metrics.md 第 78–82 行 所述,它会在 X.Y 版本预告废弃,在 X.Y+1 版本中将其隐藏(--show-hidden-metrics-for-version=X.Y 可以使其恢复),并在 X.Y+2 版本中彻底删除。

引擎严格遵循了规则,有时甚至比规则更慷慨地保留了这些名称。问题在于, 读取这些名称的消费端位于其他仓库中。此外,源码中的计数器名称中虽然没有 _total ,但由于 prometheus_client 在导出时会自动添加前缀,因此在查询时必须写成 vllm:prefix_cache_hits_total 的形式。在使用 grep 检索源码并迁移名称时,这里往往是最容易混淆的地方。

消费端:代码跟上了,但文档留在了原地

3. 我们改了什么:diff 要点

我们仅修改了名称。文案、面板标题以及查询的其余部分均保持原样。

 # docs/architecture/autoscaling/wva.md
-- `vllm:time_per_output_token_seconds` -- ITL histogram (sum/count for average)
+- `vllm:inter_token_latency_seconds` -- ITL histogram (sum/count for average)
-| `avg_itl` | `rate(vllm:time_per_output_token_seconds_sum[1m]) / rate(..._count[1m])` | ...
+| `avg_itl` | `rate(vllm:inter_token_latency_seconds_sum[1m]) / rate(..._count[1m])` | ...

 # docs/infrastructure/providers/digitalocean/monitoring/inference-gateway-dashboard.json (3곳)
-"expr": "histogram_quantile(0.95, sum by(le) (rate(vllm:time_per_output_token_seconds_bucket[$__rate_interval])))",
+"expr": "histogram_quantile(0.95, sum by(le) (rate(vllm:inter_token_latency_seconds_bucket[$__rate_interval])))",

 # guides/turn-priority-fairness/README.md
-| `vllm:gpu_prefix_cache_hit_rate` | The mechanism the strategy is optimizing. |
+| `rate(vllm:prefix_cache_hits_total[5m]) / rate(vllm:prefix_cache_queries_total[5m])` | Prefix-cache hit ratio: the mechanism the strategy is optimizing. |

在命中率的位置,我们没有填入单个 Gauge 名称,而是填入了由两个计数器计算比例的表达式。这是因为没有同名的 Gauge 可供替换,这也是 vLLM 设计文档所推荐的写法。区间的 [5m] 则保持与设计文档中的示例一致。

PR 正文在一个表格中列出了文件、旧名称、新名称和原因,并直接附上了第 1 节中的 grep 输出的三行内容以及“旧名称为 0 行”的结论。同时注明了:“仪表盘 JSON 仍可正常解析,未在 Grafana 中实际上传测试,变动的仅是 histogram_quantile 三个表达式内部的名称,面板标题保持不变”。llm-d 的 CONTRIBUTING 规定,接受由 AI 协助的贡献时应遵循与其他贡献相同的标准,但提交者必须作为记录上的作者能够亲自解释相关内容。因此,我们在正文末尾添加了一句话,说明该内容是在 AI 的协助下编写并经过了亲自审查。我们提交了一个单独的 commit,并附上了仓库要求的 DCO 签名(Signed-off-by) 与 SSH 签名。检查项中也包含了对是否为签名提交的验证。

4. 反应:没有机器人,没有行内评论,耗时 2 小时 9 分钟

时间(10-17) 事件
00:45 Commit(DCO 签名·SSH 签名)
00:59 公开 PR
00:59 ~ 21 项检查:通过 12,跳过 9,失败 0
01:53 根目录 OWNERS 的一位批准者无言批准
01:56 站点预览机器人评论:“已使用此 commit 构建站点,请下载打开查看”
03:08 另一位维护者随 /lgtm 一同批准,11 秒后通过 squash 合并

通过的检查包括 DCO、签名提交验证、pre-commit、指南检查(CI Guides Check)、指南 dry-run 以及站点预览构建。跳过的 9 个属于镜像构建等操作,推测是因为属于仅修改文档的 PR 而被跳过。

与第 1 篇中的 SeaweedFS 不同,这里没有评审机器人介入;与第 2 篇中的 Grafana 图表不同,这里也没有一句 “Thanks!”。没有行内评论,没有提问,仅凭两个批准就顺利结束了。我们无需采取任何后续应对措施。合并提交 2b0b8de7 的作者是我们的账号,消息则是我们 commit 消息标题末尾附上了 PR 编号的内容。

还有一个结构相同的 PR。production-stack 的默认仪表盘也在调用已消失的 vllm:gpu_prefix_cache_* 名称,为此我们提交了 vllm-project/production-stack#1147 ,截至 2026-10-17 仍在进行中。

5. 收获:开源贡献技巧

Titi 的总结。 朋友改了名字,但通讯录里还留着旧名字。叫他却没有回应,大家都以为是“联系不上了” 呢。亲自呼喊了一声(0 行!),确认了新名字(75 行!),修改了通讯录里的三个地方后,仅仅两小时就盖上了“已采纳”的印章。 大家决定以后一定要小心,避免打错给名字相似的其他朋友。

链接

所有资料均于 2026-10-17 查阅。

登录后即可点赞

评论

还没有评论。

登录后即可发表评论