결과: 병합 (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).
목차
- 한 줄 요약
- 1. 무엇이 문제였나: 우리가 본 증상
- 2. 원인: 소스의 어느 줄인가
- 3. 무엇을 바꿨나: diff 요지
- 4. 반응: 봇도 줄 댓글도 없이 2시간 9분
- 5. 배운 것: 오픈소스 기여 요령
- 링크
한 줄 요약
| 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 로 병합(우리 계정이 저자) |
1. 무엇이 문제였나: 우리가 본 증상
먼저 솔직히 적습니다. TT Lab 클러스터에는 llm-d 가 없습니다. 이번 문제는 운영 장애가 아니라 공부에서 만났습니다. vLLM 엔진을 둘러싼 프로젝트들(production-stack, LMCache, llm-d)의 코드를 읽으면서 「엔진이 정의한 메트릭 이름이 다른 저장소의 쿼리로 어떻게 퍼지는가」를 따라갔고, 그 내용은 「오픈소스 구조 읽기」 4편에 정리했습니다.
이름을 문서 문장만으로 대조하지 않으려고, PR 을 올리기 직전에 vLLM v0.31.0(vllm/vllm-openai 이미지, 당시 최신 릴리스)을 작은
클러스터의 GPU 노드 하나(8GB급 GPU)에 1회용 파드로 띄워 /metrics 를 받았습니다. 무엇도 새로 내려받지 않으려고 설정 파일만 만든
무작위 가중치 모델(Qwen2 구조, 2층, hidden 256, --load-format dummy)을 올리고, 앞부분 160토큰이 같은 요청 5개(각 16토큰 생성)를
보냈습니다. 그 출력에 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토큰 = 805 조회이고, 첫 요청은 모두 놓치고 나머지 넷이 160토큰씩 적중해 640 입니다
(블록 크기 16, 같은 출력의 cache_config_info). 16토큰씩 만든 요청 5개의 토큰 사이 간격은 15 × 5 = 75 입니다. 적중률은 640 / 805 ≈ 0.795
입니다.
없는 이름으로 쓴 PromQL 은 오류를 내지 않고 빈 결과를 돌려줍니다(Prometheus 의 일반적인 동작). 가이드를 따라 쿼리를 친 독자는 「아무것도 안 나온다」만 보고, 이유는 스스로 찾아야 합니다. 대시보드 패널도 비어 보일 것으로 보이지만 Grafana 에 올려 보지는 않았습니다(미실측).
같은 방식으로 llm-d v0.10.0 태그의 문서·가이드 전체를 훑은 결과도 4편에 있습니다. vllm: 이름 71개 중 40개는 출력에 있었고,
27개는 오프로드·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 에서 지웁니다.
vllm:gpu_prefix_cache_hit_rate는 V0 엔진의 게이지입니다. v0.9.0 의vllm/engine/metrics.py119–128행 에 「0.8 에서 폐기, V1 에서는 조회·적중 카운터로 대체」, 「0.9 에서 숨김, 0.10 에서 삭제 예정」이라는 주석과 함께 숨김 상태로 있고, v0.10.0 의 같은 파일에는 정의가 없습니다. V1 엔진은 적중률 대신 카운터 둘vllm:prefix_cache_queries·vllm:prefix_cache_hits를 냅니다. 설계 문서(docs/design/metrics.md437–447행)는 그 이유를 「게이지로 비율을 고정하지 말고, 사용자가rate(…[5m])처럼 원하는 구간으로 비율을 내게 하자」고 설명합니다. 눈여겨볼 점은 fairness 가이드 머리의 기준 환경이 vLLM 0.26 이라는 것입니다. 가이드가 검증된 판에서도 이 게이지는 이미 없었습니다.vllm:time_per_output_token_seconds는 V1 엔진의 히스토그램입니다. v0.11.0 의vllm/v1/metrics/loggers.py387–388행 주석이 「0.11 에서 폐기,vllm:inter_token_latency_seconds로 이름 바뀜」이라고 적고, v0.12.0(689–692행) 에서는 숨김으로 바뀌며 「0.13.0 에서 삭제」라는 할 일이 붙습니다. 실제로는 v0.14.0(718–721행) 까지 숨김으로 남았고, v0.15.0(2026-01-29 릴리스)의 같은 파일에는 정의가 없습니다. 지금 이름은vllm:inter_token_latency_seconds입니다.
엔진은 규칙대로, 때로는 규칙보다 넉넉하게 이름을 거뒀습니다. 문제는 그 이름을 읽는 쪽이 다른 저장소에 있다는 것입니다.
하나 더, 소스의 카운터 이름에는 _total 이 없지만 prometheus_client 가 내보낼 때 붙이므로 쿼리에는 vllm:prefix_cache_hits_total
처럼 써야 합니다. 소스를 grep 해서 이름을 옮길 때 자주 헷갈리는 자리입니다.
소비자 쪽: 코드는 따라갔고 문서만 남았다
- 오토스케일러 설계 문서
docs/architecture/autoscaling/wva.md는 144행의 지표 목록과 210행 의avg_itl쿼리에 옛 이름을 적고 있었습니다. 그런데 이 문서가 설명하는 수집기 코드(저장소 이름은 지금 llm-d-autoscaling) v0.9.0 의internal/collector/registration/queueing_model.go70행 은 이미vllm:inter_token_latency_seconds_sum·_count를 묻고 있습니다. 문서가 코드와 달랐습니다. - DigitalOcean 대시보드 JSON 의 「Time Per Output Token Latency」 패널은 p95·p90·p50 쿼리
(1544행,
1559행,
1575행)
가 모두
vllm:time_per_output_token_seconds_bucket을histogram_quantile에 넣고 있었습니다. - fairness 가이드의 관측 표 663행
은 「전략이 최적화하는 메커니즘」으로
vllm:gpu_prefix_cache_hit_rate를 보라고 했습니다.
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. |
적중률 자리에는 게이지 이름 하나 대신 카운터 둘의 비율 식을 넣었습니다. 바꿀 같은 이름의 게이지가 없기 때문이고, vLLM 설계 문서가
권하는 모양이기도 합니다. 구간 [5m] 은 설계 문서의 예와 같게 두었습니다.
PR 본문에는 파일·옛 이름·새 이름·이유를 한 표에 넣고, 1절의 grep 출력 세 줄과 「옛 이름 0줄」을 그대로 붙였습니다. 「대시보드 JSON
은 여전히 파싱된다, Grafana 에 올려 보지는 않았다, 바뀐 것은 histogram_quantile 세 식 안의 이름뿐이고 패널 제목은 그대로다」라고
못 한 것도 적었습니다. llm-d 의 CONTRIBUTING 은 AI 도움을 받은 기여를 다른 기여와 같은 기준으로 받되, 올린 사람이 기록상 저자로서
내용을 직접 설명할 수 있어야 한다고 적습니다. 그래서 본문 끝에 AI 도움을 받아 쓰고 직접 검토했다는 문장을 넣었습니다. 커밋은
하나이고, 저장소 규칙인 DCO 서명(Signed-off-by)과 SSH 서명을 붙였습니다. 검사에도 서명된 커밋인지 보는 항목이 있습니다.
4. 반응: 봇도 줄 댓글도 없이 2시간 9분
| 시각(10-17) | 일 |
|---|---|
| 00:45 | 커밋(DCO 서명·SSH 서명) |
| 00:59 | PR 공개 |
| 00:59 ~ | 검사 21개: 통과 12, 건너뜀 9, 실패 0 |
| 01:53 | 루트 OWNERS 의 승인자 한 명이 말 없이 승인 |
| 01:56 | 사이트 미리보기 봇이 「이 커밋으로 사이트를 빌드했다, 내려받아 열어 보라」고 댓글 |
| 03:08 | 다른 메인테이너가 /lgtm 과 함께 승인, 11초 뒤 squash 병합 |
통과한 검사에는 DCO, 서명된 커밋 확인, pre-commit, 가이드 검사(CI Guides Check), 가이드 dry-run, 사이트 미리보기 빌드가 있습니다. 건너뛴 9개는 이미지 빌드 같은 작업으로, 문서만 바뀐 PR 이라 건너뛴 것으로 보입니다.
1편의 SeaweedFS 처럼 리뷰 봇이 붙지 않았고, 2편의 Grafana 차트처럼 「Thanks!」 한 마디도 없었습니다. 줄 댓글도 질문도 없이 승인
둘로 끝났습니다. 우리가 따로 대응할 일은 없었습니다. 병합 커밋 2b0b8de7
의 저자는 우리 계정이고, 메시지는 우리 커밋 메시지 제목 끝에 PR 번호가 붙은 것입니다.
같은 모양의 PR 이 하나 더 있습니다. production-stack 의 기본 대시보드도 사라진 vllm:gpu_prefix_cache_* 이름을 부르고 있어
vllm-project/production-stack#1147 을 보냈고, 2026-10-17 기준 진행 중입니다.
5. 배운 것: 오픈소스 기여 요령
- 이름 하나는 여러 저장소에 퍼집니다. 엔진은 폐기 예고·숨김·삭제를 규칙대로 했지만, 그 규칙은 엔진 저장소 안에서만 지켜집니다.
가이드·설계 문서·대시보드 JSON 은 다른 저장소에 있고, 이름이 틀려도 실패하지 않고 비어 있을 뿐입니다. 엔진의
/metrics한 번과 소비자 쪽vllm:이름 목록 한 번이면 이런 자리를 찾을 수 있습니다. - 대체 이름은 추측하지 말고 코드에서 찾습니다. WVA 문서의 대체 이름은 그 문서가 설명하는 수집기 코드가 이미 쓰고 있었습니다. 「문서가 코드와 다르다」를 코드 줄로 보이면, 메인테이너가 따로 확인할 것이 거의 없습니다.
- 비슷한 이름을 조심합니다. v0.31.0 에는
vllm:request_time_per_output_token_seconds라는 다른 히스토그램이 있습니다. 같은 원자료에서time_per_output_token_seconds를 줄 머리 고정 없이 grep 하면 27줄이 나오고,^vllm:time_per_output_token_seconds로 고정하면 0줄입니다. 게다가 소스의 설명은 하나가 「토큰 사이 지연」, 다른 하나가 「요청 하나의 출력 토큰당 시간」이라 뜻도 다릅니다. 「이름이 비슷하니 이것으로 바꾸자」는 틀린 PR 이 되기 쉬운 자리입니다. - 잰 것과 못 잰 것을 같은 무게로 적습니다. Grafana 에 올려 보지 않았다는 문장이 PR 을 약하게 만들지 않았습니다. 메인테이너는 무엇이 확인되었고 무엇이 아닌지를 보고 판단합니다.
- 문서 PR 에도 검증 길이 있습니다. llm-d 는 문서만 바뀌어도 사이트를 빌드해 미리보기를 주고, 가이드 검사와 dry-run 을 돌립니다. 작은 PR 일수록 이런 검사가 다 초록이면 리뷰어가 볼 것은 diff 몇 줄뿐입니다.
티티 한마디. 친구가 이름을 바꿨는데 주소록에는 옛 이름이 남아 있었어요. 불러도 대답이 없으니 다들 「연락이 안 되네」 하고 말았죠. 직접 불러 보고(0줄!), 새 이름을 확인하고(75!), 주소록 세 군데를 고쳐 적었더니 두 시간 만에 「좋아요」 도장이 찍혔어요. 이름이 비슷한 다른 친구한테 잘못 거는 일만은 조심하기로 했어요.
링크
모든 자료는 2026-10-17 에 열람했습니다.
- PR: llm-d/llm-d#2835 (병합 커밋
2b0b8de7) - llm-d 소스(바탕 커밋):
docs/architecture/autoscaling/wva.md,inference-gateway-dashboard.json,guides/turn-priority-fairness/README.md,CONTRIBUTING.md - 오토스케일러 수집기:
queueing_model.go(v0.9.0) - vLLM 지표 폐기 규칙:
docs/usage/metrics.md(v0.31.0), 카운터를 고른 이유:docs/design/metrics.md(v0.31.0) - vLLM 지표 정의:
vllm/v1/metrics/loggers.py(v0.31.0), 옛 V0 게이지vllm/engine/metrics.py(v0.9.0) - 같은 모양의 PR(진행 중): vllm-project/production-stack#1147