LLM이 토큰을 생성할 때마다 이전 토큰들의 중간 연산 결과를 저장해 두는 게 KV 캐시예요. 없으면 매 토큰마다 처음부터 다시 계산해야 해요.
근데 이 KV 캐시를 어떻게 관리하느냐에 따라 성능이 완전히 달라져요. vLLM과 SGLang은 서로 다른 방식으로 이 문제를 풀어요.
KV 캐시가 뭔가
트랜스포머의 어텐션 레이어는 매 스텝마다 이전 토큰들의 Key/Value 벡터를 참조해요.
1번째 토큰 생성: [토큰1] KV 계산
2번째 토큰 생성: [토큰1, 토큰2] — 토큰1 KV 재계산하면 낭비!
KV 캐시:
1번째 토큰 생성: [토큰1] KV 계산 → 저장
2번째 토큰 생성: 저장된 토큰1 KV 재사용 + 토큰2 KV만 계산
→ 계산량 대폭 감소
문제는 KV 캐시가 메모리를 많이 먹는다는 거예요.
Llama-3.1-8B 기준, 요청 1개 KV 캐시:
= 레이어 수 × 헤드 수 × 시퀀스 길이 × 헤드 차원 × 2(K+V) × 바이트
≈ 32 × 32 × 4096 × 128 × 2 × 2 = 약 2GB (FP16)
동시 요청 100개면 → 200GB 필요 → H100 3개 필요
이 메모리를 효율적으로 관리하는 게 핵심이에요.
PagedAttention — vLLM의 방식
문제: 기존 방식은 각 요청마다 최대 시퀀스 길이만큼 연속 메모리를 미리 할당해요. 실제론 그만큼 안 쓰는데 메모리가 낭비돼요 (메모리 단편화).
기존 방식:
요청 A: [████████████ ] 최대 4096 미리 할당, 실제 1000 토큰 사용
요청 B: [████ ] 최대 4096 미리 할당, 실제 200 토큰 사용
→ GPU 메모리 20~38%만 실제 사용
PagedAttention 은 OS의 가상 메모리 개념을 KV 캐시에 적용했어요.
PagedAttention:
KV 캐시를 고정 크기 페이지(블록)로 분할
요청마다 필요한 만큼만 페이지 할당
사용 안 하는 페이지는 다른 요청에 재사용
→ GPU 메모리 96%+ 활용
→ 동시 처리 요청 수 대폭 증가
vLLM, SGLang, TensorRT-LLM 모두 PagedAttention을 기반으로 써요. 이제는 표준이에요.
RadixAttention — SGLang의 혁신
PagedAttention은 메모리 단편화 문제를 풀었어요. 근데 또 다른 낭비가 있어요.
여러 요청이 같은 프롬프트 앞부분을 공유하는 경우, 매번 다시 계산해요.
챗봇 요청 1000개:
모두 동일한 시스템 프롬프트 (1000 토큰) + 각자 다른 질문
기존 방식: 1000개 요청 × 1000 토큰 = 100만 토큰 프리필 연산
RadixAttention: 시스템 프롬프트 1번만 계산 + 999번 재사용
→ 프리필 연산 99% 절감
RadixAttention 은 KV 캐시를 Radix 트리에 저장해요. 공유 접두사를 자동으로 찾아 재사용해요.
Radix 트리 구조:
[시스템 프롬프트 KV] ← 모든 요청이 공유
├── [사용자A 질문 KV]
│ └── [응답A KV]
├── [사용자B 질문 KV]
│ └── [응답B KV]
└── [사용자C 질문 KV]
└── [응답C KV]
새 요청이 오면 트리에서 가장 긴 공통 접두사를 찾아 재사용
LRU(가장 최근 사용 안 된 것 제거) 정책으로 메모리를 자동 관리해요.
어느 워크로드에서 얼마나 빠른가
RadixAttention 효과는 공유 접두사 비율에 비례해요.
공유 접두사 비율 | 캐시 히트율 | TTFT 개선
60%+ | 75~95% | 매우 큼
40~60% | 50~75% | 중간
20% 이하 | ~0% | 없음
효과 큰 워크로드:
✅ 챗봇 (동일 시스템 프롬프트)
✅ RAG (동일 문서 + 다른 질문)
✅ Few-shot 프롬프팅 (동일 예시)
✅ 에이전트 (동일 툴 정의 + 대화 히스토리)
✅ Tree-of-Thought (같은 문제, 다른 경로)
효과 없는 워크로드:
❌ 완전히 다른 프롬프트들
❌ 동적으로 매번 바뀌는 시스템 프롬프트
멀티턴 대화에서 SGLang이 vLLM 대비 약 10~20% 더 빠른 이유예요.
HiCache — 계층적 KV 캐시 (SGLang 최신 기능)
GPU 메모리만으로는 긴 컨텍스트나 많은 동시 대화를 감당하기 힘들어요. SGLang HiCache는 KV 캐시를 계층으로 관리해요.
GPU 메모리 (빠름, 비쌈, 적음)
↕ 자동 이동
CPU 메모리 (중간)
↕ 자동 이동
디스크/원격 스토리지 (느림, 싸고, 많음)
실제 효과:
- Qwen3-Coder-480B 코딩 에이전트 (25K+ 토큰): TTFT 56% 감소, 처리량 2배
- DeepSeek-R1 671B (PD 분리 환경): TTFT 84% 감소
# HiCache 활성화 (--enable-hicache)
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--enable-hicache \
--hicache-ratio 0.5 # CPU 메모리에 GPU의 50% 크기 캐시
FP8 KV 캐시 — 메모리 50% 추가 절감
KV 캐시를 FP16 대신 FP8로 저장하면 메모리를 절반으로 줄여요. 품질 손실은 미미해요.
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-70B-Instruct \
--kv-cache-dtype fp8_e4m3
같은 GPU에서 더 많은 동시 요청을 처리할 수 있어요.
KV 캐시 히트율 올리는 실전 팁
RadixAttention을 최대로 활용하려면 프롬프트를 잘 설계해야 해요.
1. 시스템 프롬프트를 고정해요
# 나쁜 예 — 매번 다른 프롬프트
system_prompt = f"현재 시각은 {datetime.now()}입니다. 당신은 어시스턴트입니다."
# → 매번 캐시 미스
# 좋은 예 — 고정 접두사
system_prompt = "당신은 도움이 되는 어시스턴트입니다."
# → 모든 요청이 캐시 히트
2. 동적 내용은 뒤에 배치해요
# 나쁜 예
prompt = f"사용자 ID: {user_id}\n{공통_시스템_프롬프트}\n{질문}"
# → user_id가 앞에 있어서 캐시 미스
# 좋은 예
prompt = f"{공통_시스템_프롬프트}\n사용자 ID: {user_id}\n{질문}"
# → 공통 부분이 앞에 있어서 캐시 히트
3. RAG 문서를 앞에 배치해요
# 같은 문서로 여러 질문할 때
prompt = f"{공통_문서}\n\n질문: {각자_다른_질문}"
# → 문서 KV 캐시 재사용, 질문만 새로 계산
캐시 히트율 모니터링
# Prometheus 메트릭으로 확인
curl http://localhost:30000/metrics | grep cache
# 주요 지표
sglang:cache_hit_rate # 캐시 히트율 (높을수록 좋음)
sglang:token_usage # 전체 토큰 메모리 사용률
# 서버 상태 API로도 확인 가능
import requests
stats = requests.get("http://localhost:30000/get_server_info").json()
print(f"캐시 히트율: {stats['cache_hit_rate']:.1%}")
PagedAttention vs RadixAttention 정리
PagedAttention RadixAttention
| 목적 | 메모리 단편화 해결 | 공유 접두사 재사용 |
| 효과 | 메모리 효율 4~5배 | TTFT 최대 95% 감소 |
| 적용 엔진 | vLLM, SGLang 모두 | SGLang 특화 |
| 워크로드 | 모든 워크로드 | 공유 프롬프트 워크로드 |
| 설정 | 기본 활성화 | 기본 활성화 |
둘은 경쟁 관계가 아니에요. SGLang은 PagedAttention + RadixAttention을 같이 써요.
마무리
KV 캐시 관리의 핵심을 정리하면 이래요.
PagedAttention — "메모리를 페이지로 쪼개서 낭비를 없앤다" RadixAttention — "같은 앞부분은 한 번만 계산한다"
SGLang이 챗봇, RAG, 에이전트 워크로드에서 vLLM보다 빠른 이유는 RadixAttention이에요. 공유 프롬프트가 많을수록 효과가 커요. 시스템 프롬프트를 고정하고 동적 내용을 뒤에 배치하는 것만으로도 캐시 히트율을 크게 올릴 수 있어요. 😄
'LLM' 카테고리의 다른 글
| Meta Muse Spark 발표 — Llama 이후 독자 모델 (0) | 2026.04.10 |
|---|---|
| Speculative Decoding 완전 정리 — 추론 속도 2~3배 올리는 법 (0) | 2026.04.09 |
| LLM 지식 증류(Knowledge Distillation) 완전 정리 — 큰 모델의 지식을 작은 모델에 이식하는 법 (0) | 2026.04.09 |
| LoRA / QLoRA 완전 가이드 — LLM 파인튜닝을 저렴하게 하는 법 (0) | 2026.04.09 |
| LLM 양자화 완전 정리 — FP8, AWQ, GPTQ, GGUF 차이와 선택법 (1) | 2026.04.09 |