LMCache KV 오프로딩을 활용한 vLLM 프로덕션 스택(vLLM Production Stack with LMCache KV Offloading)
vLLM의 프로덕션 스택(production-stack)은 라우터(router), 엔진(engine), 관측성(observability)을 한데 엮은 표준 쿠버네티스(Kubernetes) 배포 참조 구현입니다. LMCache는 KV 오프로딩(KV offloading) 계층으로, GPU 메모리(GPU memory) 밖으로 KV 캐시(KV cache)를 꺼내 여러 질의(query)와 엔진(engine)에 걸쳐 재사용하게 해줍니다(먼저 CPU DRAM, 그다음 디스크/Ceph 단계). 2026년 1월에 도입된 vLLM 0.11.0 KV Offloading Connector는 커넥터 API(Connector API; v0.9.0+)를 통해 이 경로를 비동기적이고 플러그형(asynchronous and pluggable)으로 만듭니다. 오프로딩 지연(offload latency)은 사용자에게 직접 노출되지 않습니다. LMCache는 공유 프리픽스(shared prefix)가 없어도 가치가 있는데, GPU가 KV 슬롯(KV slot)을 모두 소진했을 때 선점된 요청(preempted request)을 프리필(prefill)부터 다시 계산하지 않고 CPU에서 복원(restore)할 수 있기 때문입니다. 4대의 a3-highgpu-4g에 분산 배치한 16개 H100(80GB HBM)으로 공개된 벤치마크(published benchmark)에서는 KV 캐시가 HBM 용량을 초과할 때 네이티브 CPU 오프로드(native CPU offload)와 LMCache가 모두 처리량(throughput)을 크게 끌어올렸습니다. 반대로 KV 점유량(footprint)이 낮을 때는 모든 구성(config)이 베이스라인(baseline)에 작은 오버헤드(overhead)만 더한 수준에 머물렀습니다.
유형: Learn
언어: Python (표준 라이브러리, 간단한 KV 스필 시뮬레이터(toy KV-spill simulator))
선수 지식: Phase 17 · 04 (vLLM Serving Internals), Phase 17 · 06 (SGLang/RadixAttention)
예상 시간: 약 60분
학습 목표
- vLLM 프로덕션 스택(production-stack)의 계층 구조 — 라우터(router), 엔진(engine), KV 오프로드(KV offload), 관측성(observability) — 를 도식으로 설명할 수 있다.
- 커넥터 API(Connector API; v0.9.0+)와 0.11.0의 비동기 경로(asynchronous path)가 오프로딩 지연(offload latency)을 어떻게 가리는지 설명할 수 있다.
- LMCache의 CPU-DRAM 캐시가 도움이 되는 구간(KV가 HBM을 초과하는 경우)과 오히려 오버헤드만 더하는 구간(KV가 HBM에 충분히 들어가는 경우)을 정량적으로 구분할 수 있다.
- 배포 제약(deployment constraint)이 주어졌을 때 네이티브 vLLM CPU 오프로드와 LMCache 커넥터(connector) 중 어느 쪽을 골라야 하는지 판단할 수 있다.
문제
운영 중인 vLLM 서빙(serving)에서 동시성(concurrency)이 올라갈 때마다 GPU의 HBM 사용률이 100%에 도달하고 선점(preemption) 이벤트가 발생합니다. 요청은 축출(evict)되고 다시 대기열에 들어가며(requeue), 똑같은 2K 토큰(token) 프롬프트(prompt)를 1분 안에 네 번이나 다시 프리필(prefill)하게 됩니다. GPU 연산은 중복된 프리필에 낭비되고, 실효 처리량(goodput)은 원시 처리량(raw throughput)보다 훨씬 낮은 수준에 머뭅니다.
GPU를 추가하면 비용이 선형으로 늘어납니다. HBM을 더 붙이는 것은 물리적으로 불가능합니다. 그러나 CPU DRAM은 상대적으로 저렴합니다. 한 소켓(socket)에 512GB 이상을 갖출 수 있고, 지연 시간(latency)은 HBM보다 몇 자릿수(order of magnitude) 더 느리지만 "잠시 따뜻하게 유지해야 하는(temporarily warm)" KV 캐시를 두기에는 충분합니다.
LMCache는 KV 캐시를 CPU DRAM으로 빼내어 선점된 요청이 빠르게 복원되도록 돕고, 여러 엔진에 걸쳐 반복되는 프리픽스(prefix)를 공유함으로써 각 엔진이 같은 프리픽스를 반복해서 프리필하지 않게 만듭니다.
개념
vLLM 프로덕션 스택(vLLM production-stack)
github.com/vllm-project/production-stack은 표준 쿠버네티스 배포 참조 구현입니다.
- 라우터(Router) — 캐시 인식(cache-aware) 라우터입니다(Phase 17 · 11). KV 이벤트(KV event)를 소비합니다.
- 엔진(Engines) — vLLM 워커(worker)입니다. GPU 한 장당 하나, 또는 TP/PP(텐서 병렬/파이프라인 병렬) 그룹마다 하나를 둡니다.
- KV 캐시 오프로드(KV cache offload) — LMCache 배포 또는 네이티브 커넥터(native connector)를 사용합니다.
- 관측성(Observability) — Prometheus 스크레이프, Grafana 대시보드, OTel(OpenTelemetry) 트레이스로 구성됩니다.
- 컨트롤 플레인(Control plane) — 서비스 디스커버리(service discovery), 설정, 롤링 업데이트(rolling update)를 담당합니다.
전체는 Helm 차트(chart) + 오퍼레이터(operator) 형태로 함께 배포됩니다.
KV 오프로딩 커넥터 API(KV Offloading Connector API; v0.9.0+)
vLLM 0.9.0은 플러그형 KV 캐시 백엔드(pluggable KV cache backend)를 위해 커넥터 API(Connector API)를 도입했습니다. 엔진은 블록(block)을 커넥터로 오프로드하고, 커넥터는 그 블록을 RAM, 디스크, 객체 저장소(object storage), LMCache 등 원하는 백엔드에 저장합니다. 이후 어떤 요청이 그 블록을 필요로 하면 커넥터가 다시 불러옵니다(load).
vLLM 0.11.0(2026년 1월)은 비동기 오프로드 경로(asynchronous offload path)를 추가했습니다. 일반적인 상황에서는 백그라운드(background)에서 오프로드가 진행되어 엔진이 그로 인해 차단(block)되지 않도록 한 것입니다. 다만 종단 간 지연(end-to-end latency)과 처리량은 여전히 워크로드 형태(workload shape), KV 캐시 적중률(KV cache hit rate), 시스템 부하(system pressure)에 따라 달라집니다. vLLM 공식 노트(note)도 커스텀 커널 오프로드(custom-kernel offload)가 낮은 적중률에서는 처리량을 떨어뜨릴 수 있으며, 비동기 스케줄링(async scheduling)이 추론적 디코딩(speculative decoding)과 알려진 상호작용 이슈(interaction issue)를 가진다고 명시합니다.
네이티브 CPU 오프로드와 LMCache 비교(Native CPU offload vs LMCache)
네이티브 vLLM CPU 오프로드(Native vLLM CPU offload): 엔진 로컬(engine-local) 방식입니다. KV 블록을 호스트 RAM(host RAM)에 저장합니다. 구현이 단순하고 네트워크 홉(network hop)이 없습니다. 다만 엔진 경계를 넘어 공유되지는 않습니다.
LMCache 커넥터(LMCache connector): 클러스터 단위(cluster-scale) 방식입니다. 블록을 공유 LMCache 서버(CPU DRAM + Ceph/S3 계층)에 저장합니다. 모든 엔진이 같은 블록에 접근할 수 있으며, 16개 H100 환경의 벤치마크가 공개되어 있습니다.
단일 엔진의 HBM 압박(HBM pressure)이 문제라면 네이티브를 선택합니다. 여러 엔진이 프리픽스를 공유한다면 LMCache가 정답입니다. 예를 들어 공통 시스템 프롬프트(system prompt)를 쓰는 검색 증강 생성(Retrieval-Augmented Generation; RAG)이나, 공유 템플릿(shared template)을 쓰는 멀티테넌트(multi-tenant) 워크로드가 여기에 해당합니다.
벤치마크 거동(Benchmark behavior)
4대의 a3-highgpu-4g에 걸친 16개 H100(80GB HBM) 테스트는 다음과 같은 거동을 보입니다.
- 낮은 KV 점유량(짧은 프롬프트, 낮은 동시성): 모든 구성이 베이스라인과 비슷한 수준이며, LMCache는 약 3~5%의 오버헤드를 더합니다.
- 중간 점유량: 엔진 간 프리픽스 재사용(prefix reuse) 효과가 살아나면서 LMCache가 도움을 주기 시작합니다.
- KV가 HBM을 초과: 네이티브 CPU 오프로드와 LMCache 모두 처리량을 크게 끌어올리며, LMCache는 엔진 간 공유(cross-engine sharing) 덕분에 이득이 더 큽니다.
LMCache가 결정적으로 유리한 경우(When LMCache is decisive)
- 테넌트(tenant) 간에 시스템 프롬프트가 공유되는 멀티테넌트 서빙.
- 질의(query) 전반에서 문서 청크(document chunk)가 반복되는 RAG.
- 같은 베이스 모델 위에 올린 미세 조정(fine-tuned) 변형 모델, 특히 LoRA. 베이스 모델의 KV 재사용이 중복 작업을 줄입니다.
- 선점이 잦은(preemption-heavy) 워크로드. 다시 프리필하는 것보다 CPU에서 복원하는 편이 더 저렴합니다.
켜지 말아야 할 경우(When NOT to enable)
- HBM 압박이 작을 때 — 이득 없이 오버헤드만 부담합니다.
- 짧은 컨텍스트(<1K 토큰) — 전송 시간이 다시 프리필하는 시간보다 더 깁니다.
- 단일 테넌트·단일 프롬프트 워크로드 — 잡아낼 재사용이 없습니다.
분산 서빙(disaggregated serving)과의 통합
Phase 17 · 17의 분산 서빙(disaggregated serving)과 LMCache를 결합하면 효과가 누적됩니다. 프리필 풀(prefill pool)에서 디코드 풀(decode pool)로 옮겨진 KV가 곧장 쓰이지 않으면 LMCache에 안착(land)하고, 이후 들어오는 질의는 LMCache에서 KV를 끌어옵니다. Phase 17 · 11의 캐시 인식 라우터(cache-aware router)는 엔진의 로컬 캐시(local cache)나 LMCache 공유 캐시 중 일치(match)하는 쪽으로 요청을 라우팅(route)할 수 있습니다.
기억해야 할 숫자(Numbers you should remember)
- vLLM 0.9.0: 커넥터 API가 처음 출시되었습니다.
- vLLM 0.11.0(2026년 1월): 비동기 오프로드 경로가 추가되었으며, 종단 간 지연에 미치는 영향은 워크로드, KV 적중률, 시스템 부하에 따라 달라집니다. 절대적인 보장이 아닙니다.
- 16개 H100 벤치마크: KV 점유량이 HBM을 초과할 때 LMCache가 도움이 됩니다.
- HBM 압박이 작을 때: 이득 없이 3~5%의 오버헤드가 발생합니다.
사용해보기
code/main.py는 LMCache를 켠 경우와 끈 경우의 선점이 잦은(preemption-heavy) 워크로드를 시뮬레이션합니다. 피한 재프리필(avoided re-prefill) 횟수, 처리량 향상(throughput gain), 손익분기(break-even)에 도달하는 HBM 사용률(HBM utilization)을 함께 보고합니다.
산출물 만들기
이 lesson은 outputs/skill-vllm-stack-decider.md를 만듭니다. 워크로드 형태(workload shape)와 vLLM 배포 정보가 주어졌을 때 네이티브, LMCache, 둘 다 사용하지 않는 선택지 중 하나를 결정해 주는 스킬(skill)입니다.
연습문제
- 쉬움:
code/main.py를 실행해 봅니다. 어느 HBM 사용률(HBM utilization)부터 LMCache가 본전을 뽑기 시작합니까?
- 중간: 한 테넌트가 6K 토큰짜리 시스템 프롬프트를 시간당 200건의 질의에 공유합니다. 테넌트당 LMCache로 절약되는 비용을 추정해 봅니다.
- 중간: LMCache 서버는 단일 장애점(single point of failure)이 될 수 있습니다. 고가용성(High Availability; HA) 전략을 설계해 봅니다(복제본(replica) 운영, 네이티브로의 폴백(fallback to native) 등).
- 어려움: LMCache가 회전 디스크(spinning disk) 위의 Ceph에 저장한다고 가정합니다. 70B FP8 모델에서 4K 토큰 KV(500MB)를 다시 읽는 시간은 다시 프리필하는 시간과 비교했을 때 어떻습니까?
- 어려움: vLLM 0.11.0의 비동기 경로가 정말 "공짜(free)"인지 따져 봅니다. 오버헤드는 어디에 숨어 있습니까?
핵심 용어
| 용어 | 흔한 설명 | 실제 의미 |
|---|
| 프로덕션 스택(Production-stack) | "참조 배포" | vLLM의 쿠버네티스 Helm 차트 + 오퍼레이터 |
| 커넥터 API(Connector API) | "KV 백엔드 인터페이스" | vLLM 0.9.0+의 플러그형 KV 저장소 인터페이스 |
| 네이티브 CPU 오프로드(Native CPU offload) | "엔진 로컬 스필" | 같은 엔진의 호스트 RAM에 KV를 저장하는 방식 |
| LMCache | "클러스터 KV 캐시" | CPU DRAM + 디스크 위에 동작하는 엔진 간 공유 KV 캐시 서버 |
| 0.11.0 async | "논블로킹 오프로드(non-blocking offload)" | 엔진 실행 스트림 뒤로 숨겨진 오프로드 |
| 선점(Preemption) | "공간을 만들기 위한 축출" | HBM이 가득 찼을 때 KV 캐시를 밀어내는 셔플 |
| 프리픽스 재사용(Prefix reuse) | "같은 시스템 프롬프트" | 여러 질의가 앞부분을 공유해 캐시 적중이 나는 상황 |
| Ceph 계층(Ceph tier) | "디스크 계층" | 캐시 계층 구조에서 DRAM 아래에 놓이는 영속 저장소 |
더 읽을거리