round-robin이 KV 캐시를 낭비하는 방식
LLM 서빙 클러스터를 운영하면 처음에는 단순하게 보인다. vLLM 레플리카를 여러 개 띄우고, 앞에 로드밸런서를 두고, 요청을 고루 분산한다. Kubernetes의 Service 하나면 충분해 보인다.
문제는 KV 캐시에서 시작된다. RAG 파이프라인의 요청은 대부분 같은 시스템 프롬프트와 같은 문서 청크를 앞에 달고 들어온다. 멀티턴 에이전트의 대화는 세션이 길어질수록 앞부분이 반복된다. 동일한 모델을 여러 테넌트가 사용할 때도 공통 prefix가 많다.
round-robin은 이 사실을 모른다. 요청 A를 pod-1로 보내고, 요청 B를 pod-2로 보낸다. 두 요청이 같은 1만 token prefix를 갖더라도 각 pod에서 prefill을 다시 한다. GPU에서 prefill은 비싸다. 캐시 히트율이 0%에 수렴하면 KV 캐시는 사실상 무용지물이다.
llm-d는 이 문제를 Kubernetes 레이어에서 해결한다. 핵심 아이디어는 단순하다. "어떤 pod의 KV 캐시에 이 요청의 prefix가 이미 있는가"를 라우팅 결정의 기준으로 쓴다. 이 장에서는 llm-d의 아키텍처, KV 캐시 인식 라우팅이 동작하는 방식, prefill/decode 분리, 그리고 프로덕션 운영 체크리스트를 살펴본다.
이 장은 llm-d 공식 문서, GitHub 리포지토리, CNCF 블로그, IBM Research 발표 자료를 기준으로 한다. 성능 수치는 특정 워크로드와 하드웨어(H100)에서 측정된 결과이며, 환경에 따라 다를 수 있다.
llm-d가 탄생한 배경
llm-d는 2025년 5월 IBM, Red Hat, Google Cloud, CoreWeave, NVIDIA, Alibaba Cloud, DaoCloud의 협업으로 시작됐다. 2026년 3월 24일 CNCF Sandbox 프로젝트로 공식 채택됐다.
CNCF Sandbox 채택은 프로덕션 준비 완료를 의미하지 않는다. 커뮤니티 거버넌스와 방향성에 대한 신호다. 실제 도입은 워크로드 적합성과 성숙도를 직접 평가해야 한다.
프로젝트의 전제는 명확하다. LLM 추론 클러스터에서 가장 비싼 자원은 GPU 메모리와 compute다. 이 자원을 낭비 없이 쓰려면 어떤 요청을 어떤 pod로 보낼지 결정하는 로직이 단순 round-robin보다 훨씬 정교해야 한다.
아키텍처 개요
llm-d는 세 개의 핵심 컴포넌트로 구성된다.
- Gateway API Inference Extension (GAIE): Kubernetes SIG Network에서 관리하는 업스트림 프로젝트. Envoy의 외부 처리(ext_proc) 프로토콜을 통해 라우팅 결정권을 플러그인에 위임한다.
- Endpoint Picker Plugin (EPP): 실제 라우팅을 결정하는 컴포넌트. 들어오는 요청의 prompt prefix 해시를 계산하고, KV Cache Indexer의 점수를 참고해 최적 pod를 선택한다.
- KV Cache Indexer (
llm-d-kv-cache): vLLM pod에서 방출되는 KVEvent 스트림을 실시간으로 수신해 pod별 캐시 블록 현황을 관리한다.
KV Cache Indexer: 실시간 캐시 현황 추적
vLLM은 캐시 블록이 생성되거나 evict될 때마다 KVEvent를 방출한다. KV Cache Indexer는 이 이벤트 스트림을 소비해 두 가지 데이터 구조를 유지한다.
Write path (이벤트 수신):
vLLM pod → KVEvent(block_hash, pod_id, medium) → Indexer → KV-Block Index 갱신
Read path (점수 조회):
EPP → "이 prompt prefix의 캐시가 어느 pod에 있는가?" → Indexer → 점수 반환KV-Block Index: block_hash → (pod_id, 메모리 매체) 매핑. GPU/CPU/디스크 오프로드 상태를 포함한다.
kvcache.Index: 위 블록 인덱스 위의 논리적 인덱스. 토큰 시퀀스(prefix)를 블록 해시 시퀀스로 변환한 뒤, 가장 많은 블록이 캐시된 pod를 찾아준다.
두 가지 스코링 모드
| 모드 | 동작 방식 | 특징 |
|---|---|---|
| 근사(Approximate) | 트래픽 패턴에서 캐시 분포를 예측 | 낮은 overhead, 정확도 제한 |
| 정밀(Precise) | vLLM의 KVEvent로 실제 블록 상태를 읽음 | 높은 정확도, 이벤트 스트림 인프라 필요 |
측정 결과에서 정밀 스코링과 근사 스코링의 차이는 극적이다. 공통 prefix가 많은 워크로드에서 정밀 모드의 P90 TTFT는 0.542초인 반면, 근사 모드는 31초를 넘었다. 57배 차이다. 캐시 히트의 유무가 prefill 비용 전체를 결정하기 때문이다.
Prefill/Decode 분리
llm-d는 prefill과 decode를 별도 GPU 풀에서 처리하는 분리 아키텍처(Disaggregated Serving)를 지원한다.
| 단계 | 연산 특성 | 적합한 자원 |
|---|---|---|
| Prefill (prompt 처리) | compute-bound (행렬 곱셈 집약) | compute 고성능 GPU |
| Decode (토큰 생성) | memory-bandwidth-bound | 메모리 대역폭이 큰 GPU |
분리하지 않으면 긴 prompt의 prefill이 진행 중인 decode 배치를 지연시킨다. 멀티턴 에이전트처럼 context가 누적되는 워크로드에서 TTFT가 점점 나빠지는 원인이다.
분리 아키텍처에서는 prefill pod가 compute를 마친 뒤 KV 캐시 데이터를 고속 인터커넥트(NVLink, InfiniBand)나 NIXL(NVIDIA의 고성능 전송 라이브러리)을 통해 decode pod로 전달한다. decode pod는 KV를 받는 즉시 토큰 생성을 시작한다.
요청 → prefill-pod (prompt prefill 완료) → KV 블록 전송 → decode-pod (토큰 스트리밍)llm-d는 vLLM의 pluggable KV Connector API를 통해 이 분리를 구현한다. pd-profile-handler 플러그인이 어떤 요청을 어느 prefill pod로 보낼지 결정한다.
LeaderWorkerSet (LWS)와 멀티노드 지원
단일 모델이 여러 GPU 노드에 걸쳐 tensor parallel 또는 pipeline parallel로 실행될 때, Kubernetes의 기본 Deployment로는 이 그룹을 하나의 논리 단위로 다루기 어렵다.
LeaderWorkerSet(LWS)는 Kubernetes SIG Apps에서 관리하는 API로, leader pod와 worker pod 그룹을 하나의 복제 단위로 묶는다. llm-d는 LWS를 사용해 대형 모델의 멀티노드 레플리카를 Kubernetes에서 관리한다.
DeepSeek처럼 Expert Parallelism이 필요한 MoE 모델을 클러스터에서 운영할 때 LWS가 핵심적인 역할을 한다.
플러그인 생태계
v0.6.0(2026년 4월 3일)에서 llm-d inference-scheduler의 플러그인 생태계가 확장됐다.
| 플러그인 | 역할 |
|---|---|
no-hit-lru-scorer | 캐시 히트가 없는 pod를 최근 사용 기준으로 제외해 캐시 편향을 줄임 |
active-request-scorer | 현재 활성 요청 수가 적은 pod를 선호해 부하를 균형 있게 분산 |
speculative-indexing | 다음 요청에서 히트할 가능성이 높은 prefix를 미리 인덱싱 |
플러그인은 scorer와 filterer 인터페이스를 구현한다. 팀이 직접 scorer를 작성해 특정 워크로드에 맞게 최적화할 수 있다.
하드웨어 지원 확장
v0.6.0에서 NVIDIA H100 외에도 다음 하드웨어 지원이 추가됐다.
- AMD ROCm: AMD GPU에서 vLLM 기반 추론
- Intel Gaudi / HPU: Intel의 AI 가속기
- CPU on AMX: Intel AMX(Advanced Matrix Extensions) 명령을 사용하는 CPU 추론
클라우드 외에 엣지나 온프레미스 환경에서 다양한 하드웨어를 혼합해 사용하는 팀에게 의미 있는 변화다.
언제 llm-d가 필요한가
정리
llm-d의 핵심은 단순하다. "어떤 pod의 KV 캐시에 이 요청의 prefix가 있는가"를 라우팅 기준으로 쓴다. round-robin이 무작위로 분산해 캐시를 낭비하는 것과 달리, EPP는 KV Cache Indexer의 실시간 점수를 받아 캐시 히트율이 가장 높은 pod로 요청을 보낸다.
이 접근은 RAG, 멀티턴, 멀티테넌트처럼 prefix가 반복되는 워크로드에서 TTFT를 크게 줄인다. 정밀 스코링 모드에서는 근사 모드 대비 P90 TTFT가 57배 개선된 사례가 보고됐다.
Prefill/Decode 분리는 compute-bound prefill이 bandwidth-bound decode를 막는 구조적 문제를 해결한다. LWS는 이 복잡한 멀티노드 배포를 Kubernetes의 단일 관리 단위로 만든다.
llm-d는 여전히 CNCF Sandbox 단계다. prefix 공유 비율을 먼저 측정하고, 동일 워크로드에서 round-robin과 직접 비교한 뒤 도입을 결정하는 것이 안전하다.
References
- llm-d: Kubernetes-native distributed inferencing — Red Hat Developer
- Welcome llm-d to the CNCF: Evolving Kubernetes into SOTA AI infrastructure — CNCF Blog
- KV-Cache Wins You Can See: From Prefix Caching in vLLM to Distributed Scheduling with llm-d — llm-d Blog
- llm-d Inference Scheduler Architecture — llm-d Docs
- llm-d KV Cache Manager — llm-d Docs
- GitHub: llm-d/llm-d-kv-cache — Distributed KV cache scheduling & offloading libraries
- Master KV cache aware routing with llm-d — Red Hat Developer
- Complete Guide to llm-d CNCF Sandbox — DEV Community
- KV-Cache Wins You Can Feel: Building AI-Aware LLM Routing on Kubernetes — IBM Research KubeCon EU 2026
- llm-d on Kubernetes: Disaggregated LLM Inference Deployment Guide — Spheron Blog