TT Lab
블로그

한국어 English 日本語 中文

시작하기
블로그

블로그

같은 요청을 Dynamo 로 보내면, 라운드로빈과 KV 인지 라우팅 실측

상태: 초안 (2026-11-14), 실측. 이 글의 숫자는 2026-11-13 에 필자가 직접 잰 값입니다. 환경과 요청은 1편과 같습니다. 쿠버네티스 v1.34, GPU 서버 세 대(24GB급 GPU 한 장, 8GB급 노트북 GPU 두 장), 노드 사이 1GbE, Dynamo v1.6.2 의 vllm-runtime:1.6.2 이미지(vLLM 0.31.0), 모델 Qwen3-0.6B 입니다. 라우터 인자는 전부 기본값입니다. 작성 규칙: 실측 데이터가 기본이고, 못 잰 것은 「미실측」, 확인하지 못한 것은 「미확인」으로 표시합니다.

라운드로빈과 KV 인지 라우팅

목차

1. 이 편에서 답할 질문

1편의 결론은 이랬습니다. Service 뒤에 vLLM 을 여러 대 두면 접두 캐시의 적중률은 「워커 한 대가 담는 접두 수 ÷ 접두 종류 수」로 정해지고, 워커를 늘려도 오르지 않습니다. 이 편은 같은 요청을 Dynamo 로 보내서 세 가지를 확인합니다.

  1. Dynamo 를 거치기만 하면 달라지는 것이 있는가(라운드로빈).
  2. KV 인지 라우팅을 켜면 적중률과 첫 토큰 시간이 얼마나 달라지는가.
  3. 문서가 조심하라고 적은 두 가지, 곧 해시 씨앗과 KV 이벤트를 빼면 어떻게 되는가.

2. 매니페스트에서 바뀌는 것

기준선은 Deployment 와 Service 였습니다. Dynamo 에서는 그 둘이 DynamoGraphDeployment(DGD) 하나로 바뀝니다. 오퍼레이터가 이것을 읽고 파드와 Service 를 만듭니다. 엔진 인자, 이미지, 모델, 노드 배치는 그대로 두고 다음 넷만 바꿨습니다.

바뀌는 것 기준선 Dynamo
리소스 Deployment + Service DGD 하나(구성 요소: 프런트엔드 1, 워커 여럿)
워커의 실행 명령 python3 -m vllm.entrypoints.openai.api_server python3 -m dynamo.vllm
OpenAI API 를 여는 곳 워커마다 8000 프런트엔드만 8000, 워커는 HTTP 를 열지 않음
라우팅 Service 가 연결 단위로 무작위 프런트엔드의 DYN_ROUTER_MODE

KV 인지 라우팅에 필요한 설정은 둘입니다.

# 프런트엔드
env:
  - {name: DYN_ROUTER_MODE, value: kv}

# 워커 인자
- --kv-events-config
- '{"publisher":"zmq","topic":"kv-events","endpoint":"tcp://*:20080","enable_kv_cache_events":true}'

워커는 KV 블록이 생기고 지워질 때마다 이 주소로 이벤트를 내보내고, 프런트엔드 안의 라우터가 그것을 받아 「어느 워커가 어떤 블록을 갖고 있는가」의 지도를 만듭니다. 요청이 오면 라우터는 요청의 앞부분과 가장 많이 겹치는 워커를 고르되 워커의 부하도 함께 따집니다.

옮기면서 확인한 사실을 적어 둡니다.

3. 변형 다섯 개

이름 구성 보려는 것
기준선 Service 뒤 vLLM(1편) 견줄 값
라운드로빈 DGD, DYN_ROUTER_MODE=round-robin Dynamo 를 거치는 것만의 효과
KV 라우팅 DGD, DYN_ROUTER_MODE=kv, KV 이벤트, PYTHONHASHSEED=0 본 기능
씨앗 없음 KV 라우팅에서 PYTHONHASHSEED 만 뺌 해시 씨앗이 정말 필요한가
근사 모드 DYN_ROUTER_USE_KV_EVENTS=false, 워커의 이벤트도 끔 이벤트 없이 추측만으로 얼마나 되는가

요청은 1편과 같습니다. 공유 접두 약 2,000토큰에 요청마다 다른 꼬리 약 300토큰을 붙였고, 워커 한 대의 KV 용량을 1GiB(요청 약 3.95개 분량)로 묶었습니다. 접두 종류는 2·7·12·24, 동시 요청은 4·8·16, 점마다 3회를 돌려 중앙값을 썼습니다. 씨앗이 같으므로 모든 변형이 똑같은 요청을 똑같은 순서로 받았습니다. 다섯 변형의 모든 점에서 오류는 0건이었습니다.

라운드로빈 변형의 한 점(접두 2종·동시 4)은 첫 반복을 뺐습니다. 직전에 같은 씨앗으로 시험 요청을 보낸 탓에 접두가 이미 캐시에 있었기 때문입니다. 그 점은 남은 2회의 중앙값입니다.

4. 결과: 라운드로빈은 기준선과 같고, KV 라우팅은 다르다

같은 요청, 세 가지 길 워커 6대 · 동시 8 · 3회 중앙값 · 요청 단위 적중 비율 0 25% 50% 75% 100% 2 7 12 24 서로 다른 접두의 수 KV 인지 라우팅 Service(동그라미), 라운드로빈(네모)
그림: 세 가지 길의 요청 단위 적중 비율

요청 가운데 캐시에 맞은 비율입니다(워커 6대, 동시 8).

접두 종류 Service 뒤 vLLM 라운드로빈 KV 라우팅
2 95.0% 95.0% 97.5%
7 55.5% 53.5% 83.0%
12 32.1% 29.2% 67.9%
24 17.5% 17.5% 43.3%

입력 토큰 가운데 캐시에서 온 비율로 보아도 같습니다. 이 요청에서는 2,371토큰 가운데 2,032토큰이 접두이므로 0.857 이 낼 수 있는 가장 큰 값입니다.

접두 종류 동시 Service 뒤 vLLM 라운드로빈 KV 라우팅
2 4 0.814 0.814 0.857
7 4 0.431 0.385 0.788
12 4 0.241 0.262 0.664
24 4 0.135 0.126 0.429
2 16 0.814 0.814 0.835
7 16 0.425 0.442 0.779
12 16 0.268 0.237 0.695
24 16 0.141 0.148 0.431

라운드로빈은 기준선과 구별되지 않습니다. Dynamo 의 프런트엔드를 앞에 두는 것만으로는 캐시가 살아나지 않습니다. 요청을 워커에 고르게 돌리는 것과 무작위로 뿌리는 것은 접두 캐시의 눈으로 보면 같은 일입니다.

KV 라우팅은 접두가 한 대의 용량을 넘는 구간에서 적중을 두 배에서 세 배로 올렸습니다. 접두 2종에서는 차이가 작습니다. 1편에서 적은 대로, 접두가 한 대에 다 들어가면 라우팅으로 얻을 것이 거의 없습니다.

라우터가 실제로 요청을 모았는지는 「접두 하나가 몇 대의 워커로 갔는가」로 확인했습니다. 요청의 nvext.extra_fields 에 worker_id 를 넣으면 응답에 처리한 워커의 식별자가 실려 옵니다. 그것으로 셌습니다.

접두 종류 라운드로빈 KV 라우팅
2 6.00대 1.00대
7 6.00대 2.86대
12 6.00대 4.00대
24 5.92대 5.17대

(워커 6대, 동시 4, 3회 중앙값.) 라운드로빈은 모든 접두를 모든 워커에 보냈습니다. KV 라우팅은 접두 2종일 때 접두마다 한 대에만 보냈고, 접두가 늘수록 퍼졌습니다.

5. 첫 토큰 시간과 처리량

첫 토큰까지의 시간, 꼬리(p99) 워커 6대 · 동시 16 · 3회 중앙값 0 0.4초 0.8초 1.2초 1.6초 2 7 12 24 서로 다른 접두의 수 Service 뒤 vLLM Dynamo 라운드로빈 Dynamo KV 인지 라우팅
그림: 첫 토큰까지의 시간 p99

첫 토큰까지의 시간(TTFT)입니다. 칸마다 p50 / p99 입니다(워커 6대).

접두 종류 동시 Service 뒤 vLLM 라운드로빈 KV 라우팅
2 4 37 / 122ms 41 / 125ms 34 / 73ms
7 4 63 / 184ms 89 / 142ms 40 / 129ms
12 4 94 / 193ms 106 / 140ms 43 / 138ms
24 4 101 / 254ms 113 / 143ms 64 / 149ms
2 16 64 / 325ms 74 / 332ms 67 / 206ms
7 16 142 / 1,353ms 111 / 576ms 72 / 240ms
12 16 193 / 1,441ms 190 / 646ms 77 / 193ms
24 16 205 / 1,508ms 199 / 774ms 109 / 242ms

읽을 것이 셋 있습니다.

처리량(초당 요청, 워커 6대·동시 16)도 따라 올랐습니다.

접두 종류 Service 뒤 vLLM 라운드로빈 KV 라우팅
2 18.9 19.1 21.1
7 14.1 16.0 20.1
12 13.9 14.7 19.2
24 13.3 14.3 17.6

GPU 는 그대로인데 접두 24종에서 32% 를 더 처리했습니다. 접두를 다시 계산하는 데 쓰던 시간이 줄어든 만큼입니다.

6. 워커 3대에서도 같은가

GPU 한 장에 워커 하나씩 둔 배치입니다(동시 8).

접두 종류 캐시 토큰 비율: 기준선 / 라운드로빈 / KV TTFT p99: 기준선 / 라운드로빈 / KV 초당 요청: 기준선 / 라운드로빈 / KV
2 0.840 / 0.840 / 0.848 165 / 171 / 83ms 17.0 / 17.3 / 20.6
7 0.487 / 0.475 / 0.690 853 / 413 / 145ms 12.4 / 13.6 / 18.5
12 0.283 / 0.291 / 0.474 1,125 / 679 / 152ms 11.2 / 12.5 / 17.2
24 0.143 / 0.141 / 0.252 1,216 / 830 / 202ms 10.7 / 11.8 / 16.6

방향은 같습니다. 접두 24종에서 처리량이 55% 늘었습니다. 다만 워커가 셋뿐이라 담을 수 있는 접두의 총량이 절반이고, 그만큼 적중률도 6대 배치보다 낮습니다.

부하가 용량을 넘는 점도 하나 있었습니다. 워커 3대·동시 16·접두 24종에서 KV 라우팅의 TTFT p50 은 279ms, p99 는 962ms 였습니다. 기준선(563ms, 3,060ms)보다는 낫지만 다른 점들처럼 0.2초 안으로 들어오지는 않았습니다. 라우팅은 낭비를 줄일 뿐이고 모자란 계산 자원을 만들어 주지는 않습니다.

7. 상한에는 얼마나 다가갔는가

1편에서 계산한 이론상 상한은 「워커 수 × 한 대가 담는 접두 수 ÷ 접두 종류 수」였습니다. 접두를 워커에 겹치지 않게 나눠 담는다고 가정한 값입니다.

배치 접두 종류 상한 실제 요청 단위 적중(동시 4 / 8 / 16)
워커 6대 7 100% 93 / 83 / 91%
워커 6대 12 100% 80 / 68 / 82%
워커 6대 24 99% 52 / 43 / 52%
워커 3대 7 100% 77 / 82 / 90%
워커 3대 12 99% 53 / 58 / 64%
워커 3대 24 49% 29 / 30 / 28%

기본값의 KV 라우팅은 캐시가 빠듯한 구간에서 상한의 절반에서 3분의 2 사이를 냈습니다. 무작위 분산보다는 두세 배 낫지만, 용량을 남김없이 쓰는 배치에는 미치지 못합니다.

까닭은 4절의 표에 보입니다. 접두 24종에서 접두 하나가 평균 5대의 워커로 갔습니다. 라우터는 겹침만 보지 않고 워커의 부하도 함께 보기 때문에, 겹치는 워커가 바쁘면 다른 워커로 보냅니다. 그 워커는 접두를 새로 계산해 담고, 그러느라 다른 접두를 밀어냅니다. 캐시가 빠듯할수록 이 밀어내기가 연쇄로 이어집니다.

Dynamo 문서에는 겹침과 부하의 비중을 바꾸는 라우터 인자가 있습니다. 이 글은 기본값으로만 쟀고, 그 인자를 바꿔 상한에 더 다가갈 수 있는지는 미실측입니다.

8. 해시 씨앗과 근사 모드

문서와 예제는 워커에 PYTHONHASHSEED=0 을 주라고 적습니다. vLLM 의 블록 해시가 파이썬의 해시를 거치므로 씨앗이 프로세스마다 다르면 같은 접두가 워커마다 다른 해시가 된다는 이유입니다. 씨앗을 빼고 재 봤습니다(워커 6대, 동시 8, 캐시 토큰 비율).

접두 종류 라운드로빈 KV 라우팅 씨앗 없음 근사 모드
2 0.814 0.835 0.848 0.848
7 0.439 0.702 0.729 0.638
12 0.247 0.573 0.547 0.480
24 0.149 0.361 0.343 0.245

씨앗을 빼도 결과는 같았습니다. 네 점의 차이는 0.03 안이고 방향도 엇갈립니다. 반복 사이의 흔들림과 구별되지 않는 크기입니다. 적어도 이 판과 이 구성에서는 씨앗이 없다고 라우팅이 깨지지 않았습니다. 까닭은 미확인입니다. 런타임이 씨앗을 스스로 정하는지, 라우터가 워커의 해시에 기대지 않는 길이 있는지를 코드에서 확인하지 못했습니다. 문서가 요구하는 설정이고 넣는 비용이 없으므로, 결과가 같았다는 이유로 빼라고 권하지는 않습니다.

근사 모드는 중간입니다. 이 모드에서 워커는 이벤트를 보내지 않고, 라우터는 자기가 보낸 요청의 기록으로 「그 워커에 아직 이 접두가 있을 것」이라고 추측합니다. 접두 7종에서는 KV 이벤트를 쓸 때와 큰 차이가 없었지만(0.638 대 0.702), 24종에서는 0.245 로 라운드로빈(0.149)과의 차이가 절반으로 줄었습니다. 캐시가 빠듯해 블록이 자주 밀려나면 라우터의 추측이 실제와 어긋나기 때문일 것입니다. 이벤트 포트를 열기 어려운 환경에서 쓸 수 있는 차선이라는 정도로 읽으면 됩니다.

9. 정리

이 측정의 한계는 1편과 같습니다. 접두를 고르게 뽑았고, 요청 길이가 모두 같으며, 모델이 작습니다. 큰 모델에서는 빗나간 요청 하나의 계산이 훨씬 길어서 같은 적중률 차이가 더 큰 시간 차이로 나타날 것이지만, 그것은 이 글이 잰 값이 아닙니다. 프런트엔드를 여러 대 두었을 때 라우터들이 같은 지도를 보는지도 미실측입니다.

참고

로그인하면 좋아요를 누를 수 있습니다

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다