같은 시스템 프롬프트를 매 요청마다 다시 계산하고 있다면 GPU는 하루 종일 같은 숙제를 반복하는 셈이다. 프리픽스 캐싱은 앞부분이 같은 요청의 KV를 재사용해 prefill을 건너뛴다. 2026년 현재 vLLM·SGLang·TensorRT-LLM·llama.cpp 네 엔진 모두 기본 활성이라, 질문은 "켜까"가 아니라 "왜 우리 히트율은 낮은가"다. 이 글은 엔진의 메커니즘, 히트율을 결정하는 프롬프트 배치, 그리고 레플리카가 둘 이상일 때 캐시를 깨는 로드밸런서 문제를 다룬다.
네 엔진의 메커니즘 — 히트의 단위가 다르다
- vLLM Automatic Prefix Caching — 16토큰 블록마다 (부모 블록 해시, 토큰 ID, LoRA ID·멀티모달 해시·
cache_salt)로 체인 해시를 만든다. 완전히 찬 블록만 캐시되므로 50토큰 프리픽스는 48토큰만 인정된다. LRU 축출, V1에서 기본 활성(--no-enable-prefix-caching으로 끔). 해시 알고리즘이 프로파일에 보이면--prefix-caching-hash-algo xxhash. - SGLang RadixAttention — 프롬프트와 생성 결과를 radix tree로 들고 페이지 크기 1토큰이라 짧은 프롬프트에서 손해가 없다. 대기열을 "가장 긴 매칭 프리픽스" 순으로 정렬하는 캐시 인지 스케줄링이 핵심이며, LMSYS 벤치에서 히트율 50~99%, 처리량 최대 5배. 축출 정책은
--radix-eviction-policy로 lru/lfu/priority 선택. - TensorRT-LLM KV cache reuse —
enable_block_reuse기본 활성, 부분 블록 재사용, 0~100 우선순위 LRU(시스템 프롬프트 고정 가능, 히트율 ~20% 상승),host_cache_size로 축출 전 CPU 오프로드. - llama.cpp — 슬롯 단위
cache_prompt. 슬롯보다 대화가 많으면 축출되고--slot-save-path로 디스크 저장. 단일 서버·엣지 계층용.
단일 인스턴스 이득은 크지만 prefill/TTFT에만 걸린다. llm-d의 측정에서 Qwen3-32B 10K 토큰 프롬프트 TTFT는 4.3초→0.6초, 디코드는 그대로다. 국내 SqueezeBits 비교(Llama-3.1-8B, 공유 프리픽스 25%, 출력 1K)에서 처리량은 TRT-LLM +34.7%, vLLM 0.6.3 +13.3%였고, 공유 프리픽스가 전혀 없을 때 당시 vLLM은 −36.7%였다(V1에서 개선). 캐시는 "거의 공짜"지만 워크로드가 맞아야 한다.
히트율은 엔진이 아니라 프롬프트 배치가 결정한다 — 0.3% → 87%
Qwen2.5-32B를 H100 4노드에서 서빙한 사례가 교과서적이다. 1,847토큰 고정 시스템 프롬프트를 쓴 에이전트는 히트율 94%, TTFT 480→110ms, prefill 연산 −38%. 그런데 한 테넌트가 프롬프트 앞 200토큰에 타임스탬프·세션 UUID·도구 출력 해시를 넣자 히트율 0.3%로 떨어졌다 — 47번째 토큰에서 갈라지니 그 뒤 블록 전부가 미스다. 가변 필드를 끝으로 옮기자 87%, TTFT 510→145ms. "Don't Break the Cache"(에이전트 세션 500+건)도 같은 규칙으로 비용 −41~80%를 얻었다. 캐시를 조용히 깨는 것들:
- 요청마다 바뀌는 헤더 — Claude Code가 llama.cpp에 붙인 귀속 헤더 하나가 매 턴 수만 토큰을 재처리시켰다.
- JSON 키 순서 비결정성, 사용자별 도구 목록, 앞부분 컨텍스트 재정렬(뒤 전부 무효).
- 토크나이저·챗 템플릿 버전 변경(캐시의 정체성은 토큰 ID), 마지막 부분 블록, LoRA 전환, 이미지 해시 없는 멀티모달.
- 멀티테넌트에서
cache_salt없이 공유하면 히트/미스 타이밍으로 다른 테넌트의 프리픽스를 추측하는 사이드채널(PrefixWall)이 생긴다. 공개 시스템 프롬프트만 공유하고 고객 데이터는 salt — 선택적 격리가 전면 격리보다 재사용을 70% 더 남긴다.
레플리카가 2대 이상이면 로드밸런서가 캐시를 깬다
- 1단계 세션 스티키: vLLM Router의 consistent hashing. 챗봇이면 이것으로 충분한 경우가 많다.
- 2단계 프리픽스 해시 라우팅: SGLang 라우터는 워커별 근사 radix tree로 매칭률 기준 라우팅. Llama-3.1-8B 8×A100에서 히트율 20%→75%, 처리량 82.7K→158.6K tok/s.
- 3단계 KV 이벤트 기반: llm-d의 정밀 스케줄링은 16×H100·150테넌트에서 P90 TTFT 0.54초 vs 랜덤 92.6초(170배), 처리량 2배. Baseten의 Dynamo KV 라우터는 50K 토큰 코딩 트래픽에서 히트율 89%, TTFT −50%, RPS +61%. GKE Inference Gateway는 평균 TTFT 2,625→188ms.
작은 클러스터의 현실적 기대치는 처리량이 아니라 꼬리 지연이다 — 4레플리카 멀티턴에서 히트율 62→90%, P95 TTFT 727→237ms, 처리량은 그대로였다. 프롬프트가 전부 고유하거나 200토큰 미만이면 라우팅 투자는 건너뛴다. 이번 주에 할 일: 프롬프트를 고정→few-shot→도구→사용자 데이터 순으로 정렬하고, vllm:prefix_cache_hits / vllm:prefix_cache_queries를 대시보드에 올리고, 세션 스티키부터 켠다. GPU 캐시 용량이 히트율을 막는 순간(HiCache 40→80%)의 이야기는 ⑦편에서.
— LLM 서빙 캐싱 시리즈 ③ / 다음 글: API 프롬프트 캐싱 — 가격표, TTL, 손익분기
댓글 없음:
댓글 쓰기
국정원의 댓글 공작을 지탄합니다.