TT Lab
요금제

한국어

시작하기
블로그

블로그

NVIDIA Dynamo: 프리필과 디코드를 나누고, KV 가 있는 곳으로 보내기

상태: 초안 (2026-10-13), 일부 실측. 논문·공식 문서·NVIDIA 블로그는 2026-10-13 에 직접 열어 확인했고, 문서는 Dynamo v1.5.1(2026-10-07) 기준입니다. NVIDIA 가 낸 성능 수치는 「업체 발표」로 표시했습니다. 실측은 같은 사이트의 「토스 ML/AI Infra 준비」 14편(8GB급 GPU, vLLM)과 24편(Dynamo 1.6.0 개발 빌드, 8GB급·24GB급 GPU, 0.6B 모델)에서 다시 인용했습니다. NVLink·RDMA 로 연결된 환경의 분리 서빙 이득은 미실측입니다. 작성 규칙: 실측 데이터가 기본이고, 못 잰 것은 「미실측」, 확인하지 못한 것은 「미확인」으로 표시합니다.

NVIDIA Dynamo: 프리필과 디코드를 나누기

목차

1. 프리필과 디코드는 같은 GPU 에서 서로를 방해한다

긴 프롬프트가 끼어들 때 디코드에 생기는 일 요청 A 가 15ms 마다 토큰을 내는 중, 긴 프롬프트 B 가 들어온다 (가) 한 GPU 에서 함께 GPU B 프리필 A 의 다음 토큰이 227ms 늦다(실측) (나) 프리필·디코드 분리 디코드 GPU B 의 토큰 → 프리필 GPU B 프리필 KV 전송 0ms 200ms 400ms 600ms · 분리하면 A 의 토큰 간격은 고르게 유지된다. · 대신 B 의 첫 토큰에 KV 를 옮기는 시간이 더해진다. 전송 시간 = 토큰당 KV × 입력 토큰 ÷ 링크 속도 227ms: 8GB급 GPU·vLLM 기본 청크 2,048 실측. 전송 길이는 설명용.
그림: 긴 프롬프트가 디코드에 끼어드는 모습과 분리했을 때

1편에서 프리필은 계산에, 디코드는 메모리 대역폭에 묶인다고 했습니다. 둘이 한 GPU 를 나눠 쓰면 문제가 생깁니다. 연속 배칭은 새 요청의 프리필을 디코드 걸음 사이에 넣는데, 프리필이 긴 걸음은 오래 걸리고 그동안 배치 안의 다른 요청은 다음 토큰을 받지 못합니다.

우리 실측. 8GB급 GPU 에서 vLLM 기본 설정(한 걸음 입력 상한 2,048토큰)으로 디코드 중인 요청 옆에 3,500토큰짜리 입력을 끼우자, 그 구간의 최대 토큰 간격이 227ms 였습니다(3회 227·226·226ms). 평소 간격은 약 15ms 입니다. 2편의 청크 프리필로 이 값을 69ms 까지 줄일 수 있었지만, 그 대가로 긴 입력의 첫 토큰이 조금 늦어졌습니다. 청크는 간섭을 나눠 낼 뿐 없애지 못합니다.

분리 서빙을 처음 체계적으로 다룬 두 논문은 이 문제를 이렇게 짚습니다.

2. 분리 서빙: 나누고, KV 를 옮긴다

방법은 단순합니다. 프리필 전용 GPU 와 디코드 전용 GPU 를 따로 둡니다. 프리필 GPU 가 프롬프트의 KV 를 만들면 그 KV 를 디코드 GPU 로 보내고, 디코드 GPU 는 받은 KV 에 이어 토큰을 만듭니다.

DistServe 의 결과. A100 80GB(노드 안 NVLink, 노드 사이 25Gbps), OPT-13B·66B·175B 에서 지연 목표를 90% 이상 지키는 최대 요청률(goodput)을 쟀습니다.

작업 모델 vLLM 대비 요청률 vLLM 대비 지연 목표
챗봇(ShareGPT) OPT-13B·66B·175B 2.0~4.6배 1.8~3.2배 엄격
코드 완성(HumanEval) OPT-66B 5.7배 1.4배 엄격
요약(LongBench) OPT-66B 4.3배 12.6배 엄격

다른 기준선(DeepSpeed-MII)과 비교하면 최대 7.4배였고, 초록의 「요청률 최대 7.4배 또는 지연 목표 12.6배 엄격」이 이 두 표를 합친 값입니다. 동기 예시도 직관적입니다. 13B 모델을 A100 한 장에 두면 약 1.6 요청/초였는데, 프리필만 하면 5.6, 디코드만 하면 10 요청/초를 냈고, 프리필 2장 + 디코드 1장으로 나누면 GPU 당 3.3 요청/초로 2.1배가 되었습니다.

KV 전송은 어땠을까요. 논문은 OPT-66B 의 512토큰 요청 하나가 KV 약 1.13GB 라서 초당 10요청이면 11.3GB/s 가 필요하다고 계산합니다. 그래서 프리필과 디코드를 같은 노드 안(NVLink) 에 배치하도록 설계했고, 그 결과 OPT-175B 에서 전송이 전체 지연의 0.1% 미만이었습니다.

Splitwise 의 결과. KV 를 층마다 비동기로 보내 다음 층 계산과 겹쳤습니다(InfiniBand). 겹치지 못한 전송은 A100 약 8ms, H100 약 5ms 로 프롬프트 계산 시간의 7% 미만이었고 전체 지연에 0.8% 를 더했습니다. 전력이 같은 조건에서 A100 으로만 나눈 구성이 기준(A100)보다 처리량 2.15배였습니다(본문 그림 18a). 초록의 대표 수치(「비용 20% 절감하며 1.4배」, 「같은 비용·전력에서 2.35배」)는 본문 실험과 같은 짝으로 찾지 못해 여기서는 본문 값만 적습니다.

3. NVIDIA Dynamo 의 구성

Dynamo: 분리 서빙과 KV 인지 라우팅 프런트엔드 OpenAI 호환 API · 토큰화 KV 인지 라우터 워커마다 비용 = 새로 계산할 프리필 블록 (이미 가진 블록은 뺌) + 디코드 부하 → 가장 싼 곳 블록 색인 워커 1: ■■■□ 워커 2: ■□□□ 프리필 워커 계산 위주 · 큰 텐서 병렬 등 워커 1 워커 2 디코드 워커 메모리 위주 · 큰 배치 워커 3 워커 4 NIXL 로 KV 전송 NVLink · RDMA(UCX) · TCP · 저장소(GDS 등) ↑ 워커가 블록 저장·삭제 이벤트를 라우터에 알림 플래너 대기열·KV 사용률·지연 목표를 보고 프리필·디코드 워커 수를 늘리고 줄인다 KV 오프로딩 GPU → CPU → 디스크 → 객체 KVBM(1.5 에서 폐지 예고) 또는 LMCache 등 엔진 연결
그림: Dynamo 의 구성: 프런트엔드, KV 인지 라우터, 프리필·디코드 워커, NIXL, 플래너

Dynamo 는 vLLM·SGLang·TensorRT-LLM 같은 엔진 위에서 여러 GPU·여러 노드를 묶는 서빙 프레임워크입니다. 엔진을 대신하지 않고, 엔진 여러 개를 어떻게 나누고 어디로 보낼지를 맡습니다. 문서(v1.5.1)에서 확인한 구성은 다음과 같습니다.

4. 왜 처리량이 오르나

원천 무엇이 바뀌나 근거
간섭 제거 디코드 GPU 에 긴 프리필이 끼지 않아, 토큰 간격 목표를 지키며 디코드 배치를 키운다 실측(간섭 227ms), DistServe·Splitwise
단계별 맞춤 프리필·디코드에 다른 병렬화·GPU 수·하드웨어를 준다. 플래너가 비율을 부하에 맞춘다 DistServe(2.1배 예시), Splitwise
캐시 적중 같은 앞부분을 가진 워커로 보내 프리필 자체를 건너뛴다 실측(5절), 업체 발표
작업 집합 나누기 앞부분이 워커별로 갈라져, 각 워커의 GPU 캐시에 자기 몫이 다 들어간다 실측(5절)

NVIDIA 의 발표 수치는 이렇습니다. 모두 업체 발표이고, 직접 재현하지 않았습니다.

5. 직접 재 본 Dynamo

다른 시리즈에서 Dynamo(1.6.0 개발 빌드, vLLM 0.30.0, NIXL 1.3.2)를 Qwen3-0.6B(토큰당 KV 114,688바이트)로 재 보았습니다.

KV 인지 라우팅. 워커 둘을 띄우고, 약 1,500단어짜리 앞부분 12종을 6번씩 섞어 보냈습니다(재요청 60번). 재요청이 같은 앞부분의 KV 를 가진 워커로 가면 첫 토큰이 약 15ms, 아니면 약 80ms 였습니다.

라우팅 60번 중 적중(3회) 첫 토큰 평균
라운드 로빈 35, 40, 43 34~42ms
무작위 44, 31, 45 32~46ms
KV 인지, 근사 모드 60, 53, 60 15~26ms
KV 인지, 이벤트 모드인데 이벤트 없음 39, 44, 41 32~38ms
KV 인지, 이벤트 모드 60, 60, 60 15ms

분리 서빙. 결과는 반대였습니다. 모두 단독 서빙보다 느렸습니다.

구성(동시 1) 1,500단어 3,000단어
8GB급 GPU 단독 78ms 172ms
같은 GPU 한 장을 프리필·디코드 프로세스로 나눔 406ms 812ms
서로 다른 서버 둘로 나눔(1GbE 급 링크) 1,721~1,752ms 3,407~3,533ms

이것은 「분리 서빙이 느리다」가 아니라 **「느린 링크로 나누면 느리다」**입니다. 논문들이 NVLink 나 InfiniBand 를 전제로 하는 까닭이 이 표에 있습니다.

6. Dynamo 와 LMCache 의 관계

둘은 경쟁 관계가 아니라 층이 다릅니다. LMCache 는 엔진 하나 옆에서 KV 를 저장·불러오는 캐시 계층이고, Dynamo 는 엔진 여러 개를 묶어 나누고 보내는 프레임워크입니다. 문서에서 확인한 통합 지점은 다음과 같습니다.

7. 언제 이득이 없나

분리 서빙의 손익은 3편과 같은 모양의 식으로 어림할 수 있습니다. 첫 토큰에 더해지는 시간 ≈ 토큰당 KV × 입력 토큰 ÷ 링크 처리량(층별 전송으로 일부는 계산과 겹쳐 숨길 수 있음). 입력 4,096토큰의 KV 를 옮기는 시간을 계산하면 다음과 같습니다(전송 시간만, 계산).

링크 속도는 1GbE 급이 우리 실측 실효 104MB/s, 100Gb/s 가 이론 12.5GB/s, NVLink 급이 DistServe 논문에 적힌 A100 사이 600GB/s 입니다.

모델 KV 크기 1GbE 급 100Gb/s NVLink 급
Qwen3-0.6B 470MB 4.5초 38ms 0.8ms
Llama 3.1 8B 537MB 5.2초 43ms 0.9ms
Llama 3.1 70B 1.34GB 12.9초 107ms 2.2ms

이 값이 아낄 수 있는 것(간섭으로 늦어지던 디코드, 과하게 잡던 GPU)보다 크면 손해입니다. 그래서 분리가 이득이 없거나 손해인 경우는 다음과 같습니다.

Dynamo 문서도 보편적인 문턱은 없다고 적습니다. 모델·GPU·입력 길이 분포에 따라 경계가 달라지므로, 초기 판(v0.1.0)은 「프리픽스 적중을 뺀 프리필 길이가 문턱을 넘고 원격 프리필 대기열이 짧을 때만」 원격 프리필을 썼고, v1.5.1 에서는 라우터 비용에 따라 조건부로 나누는 기능이 실험 단계로 들어가 있습니다. 분리할지는 내 링크로 KV 전송 처리량을 먼저 재고, 그 값으로 위 식을 계산한 뒤에 정하는 것이 안전합니다.

KV 인지 라우팅은 사정이 다릅니다. KV 를 옮기지 않고 요청을 KV 쪽으로 옮기므로 링크 비용이 없습니다. 같은 앞부분이 다시 오는 부하라면 비교적 손해 볼 일이 적습니다. 다만 한 워커에 몰리지 않게 부하 가중치를 맞추고, 이벤트가 실제로 들어오는지 확인해야 합니다.

8. 시리즈 정리

편 무엇을 아끼나 언제 효과가 크나 언제 없나
1. KV 캐시 지난 토큰의 K·V 재계산 항상(출력이 같음) — 대신 메모리를 먹는다
2. PagedAttention·연속 배칭·프리픽스 캐시 메모리 낭비, 빈 자리, 같은 앞부분 계산 동시 요청이 많을 때, 공통 프롬프트 작업 집합이 GPU 보다 클 때 캐시가 지워짐
3. LMCache GPU 밖에 둔 KV 로 프리필 대체 긴 문맥, 재사용 많음, 빠른 저장 경로 짧은 입력, 낮은 적중, 느린 링크, 작은 용량
4. Dynamo 간섭 제거, 단계별 맞춤, KV 쪽으로 라우팅 높은 부하, 긴 프롬프트, 빠른 GPU 사이 링크 느린 링크, 한 장, 낮은 부하, 작은 모델

네 편을 관통하는 질문은 하나였습니다. 「이 KV 를 다시 계산하는 것과 어딘가에서 가져오는 것 가운데 무엇이 싼가.」 답은 모델의 토큰당 KV 크기, GPU 의 계산 속도, KV 가 지나는 길의 속도, 그리고 같은 앞부분이 얼마나 자주 다시 오는지로 정해집니다. 넷 다 재 볼 수 있는 값입니다.

티티 한마디. 서브 연습하는 사람과 랠리 연습하는 사람을 한 테이블에 두면 서로 공을 기다리느라 둘 다 손해예요. 테이블을 나누면 좋아지죠. 그런데 공 바구니를 옆 건물에서 날라 와야 한다면? 그때는 그냥 같이 치는 게 나아요. 나누기 전에 바구니가 얼마나 빨리 오는지부터 재 보세요.

참고

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

댓글

아직 댓글이 없습니다.

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