본문 바로가기

10. prefix caching

핵심 질문
  • 요청들이 앞부분을 공유할 때, 무엇을 재사용할 수 있는가 — 정확히 어디까지인가?
  • prefix 재사용은 어떤 안전 가정을 은근히 깔고 있는가?

목표
  • exact prefix hit가 재사용하는 것이 "어떤 prefill까지인가"를 정확히 짚는다.
  • 테넌트(tenant) 격리를 가정하지 않는 관점을 세운다.

여정에서의 위치

09장에서 KV가 블록 단위로 관리되면 여러 요청이 같은 물리 블록을 공유할 수 있다고 했습니다. prefix caching은 그 가능성을 실현합니다: 여러 요청의 프롬프트 앞부분(prefix)이 동일하면, 그 부분의 KV를 다시 계산하지 않고 재사용합니다.

일상 비유: 여러 손님이 같은 애피타이저로 시작한다면, 그 애피타이저는 한 번만 만들어 나눠 낼 수 있습니다. 단, 메인 요리부터 갈리는 순간 각자 따로 만들어야 합니다.

flowchart LR
    R1[요청1: 시스템프롬프트 + 질문A]:::req
    R2[요청2: 시스템프롬프트 + 질문B]:::req
    SP[공유 prefix<br/>시스템프롬프트 KV]:::mem
    R1 -->|앞부분 동일| SP
    R2 -->|앞부분 동일| SP
    SP --> P1[질문A만 새로 prefill]:::comp
    SP --> P2[질문B만 새로 prefill]:::comp

    classDef req fill:#fff3bf,stroke:#f59f00,color:#000;
    classDef mem fill:#e5dbff,stroke:#7048e8,color:#000;
    classDef comp fill:#d0ebff,stroke:#1971c2,color:#000;

RAG나 공통 시스템 프롬프트처럼 앞부분이 반복되는 워크로드에서 prefill 비용을 크게 아낄 수 있어, TTFT(14장)를 낮출 수 있습니다.

정확히 무엇을 재사용하나: "어떤 prefill까지"

여기가 이 장에서 가장 중요한 정밀함입니다. exact prefix hit(정확 접두 일치)가 재사용하는 것은 처음부터 "완전히 동일한 토큰 열"이 이어지는 지점까지의 prefill 결과(KV)입니다.

  • 재사용 범위는 첫 번째로 토큰이 달라지는 자리에서 끝납니다. 그 이후는 새로 prefill해야 합니다.
  • "비슷한" 프롬프트가 아니라 토큰 단위로 정확히 같은 접두여야 합니다. 한 토큰만 달라도 그 지점부터 hit가 끊깁니다.
  • 대개 블록 단위로 매칭되므로(09장), 재사용은 블록 경계까지 정렬되는 방식으로 이뤄집니다.
⚠️ 흔한 실수
흔한 오해 1: "내용이 비슷하면 재사용된다"
아닙니다. 의미가 비슷해도 토큰 열이 다르면 exact prefix hit는 일어나지 않습니다. prefix caching은 의미 캐시가 아니라 접두 토큰 일치 캐시입니다.
⚠️ 흔한 실수
흔한 오해 2: "prefill 전체가 공짜가 된다"
아닙니다. 공유되는 것은 동일 접두 부분의 prefill뿐입니다. 요청 고유 부분(질문·문서)은 여전히 새로 계산합니다.

🔒 테넌트 격리를 가정하지 마라

prefix caching은 "서로 다른 요청이 KV를 공유한다"는 성질을 갖습니다. 이 성질은 편리하지만, 누구의 요청끼리 공유되는가를 반드시 물어야 합니다.

  • 캐시가 여러 사용자·테넌트에 걸쳐 공유되면, 한 사용자의 프롬프트 앞부분이 다른 사용자의 요청 처리에 영향을 줄 수 있는 경로가 생깁니다. 예컨대 캐시 히트 여부가 응답 시간(타이밍)에 드러나 어떤 프롬프트가 앞서 존재했는지 추론하는 부채널(side-channel) 가능성이 논의됩니다.
  • 따라서 "prefix caching = 항상 안전한 최적화"라고 가정하지 않습니다. 격리 경계(사용자별·테넌트별 캐시 분리 여부)는 설계 선택이며, 자료가 그것을 명시하지 않으면 unknown으로 두어야 합니다.
🔬 증거 읽기 (주장 유형·조건)
  • "prefix caching이 RAG에서 TTFT를 크게 낮춘다"는 inferred/measured로, 앞부분이 실제로 반복되는 워크로드라는 조건에서만 참입니다. 접두가 매번 다른 워크로드에선 이득이 거의 없습니다.
  • "prefix caching은 안전하다"는 주장은 테넌트 격리 가정을 은근히 깔고 있습니다. 그 가정이 명시·검증됐는지 확인하기 전에는 받아들이지 마세요. 이는 owner의 기능 설명(vendor-reported)이 보안 보증과 다른 대표적 사례입니다.
⚖️ 절충
prefix caching은 반복 접두 워크로드에서 prefill↓·TTFT↓를 얻지만, 캐시 관리 복잡도·메모리 점유·(교차 테넌트 시) 격리 리스크를 더합니다. 이득의 크기는 전적으로 워크로드의 접두 반복률에 달려 있습니다.

여정에 다시 위치시키기

지금까지 3부(07~10장)는 "여정의 스케줄링·메모리 구간"에서 병목을 하나씩 다뤘습니다.

  • 07 배칭: 가중치 로드 비용을 나눠 쓰되, static의 낭비.
  • 08 continuous batching: 매 반복 재구성으로 낭비↓, 단 선점 비용.
  • 09 PagedAttention: KV 단편화↓, 단 블록 관리 비용.
  • 10 prefix caching: 접두 prefill 재사용, 단 워크로드 의존·격리 가정.

공통 교훈: 각 최적화는 특정 조건에서 특정 병목을 옮길 뿐, 무료도 무조건도 아니다. 이 태도가 4부(양자화·speculative)와 5부(지표·벤치마크 비판)로 이어집니다.

📌 핵심

  • prefix caching은 정확히 동일한 접두 토큰 열의 prefill 결과(KV)를 재사용한다 — 첫 불일치 지점에서 끝난다.
  • "비슷함"이 아니라 토큰 단위 정확 일치이며, 요청 고유 부분은 여전히 새로 계산.
  • 이득은 접두 반복 워크로드(RAG·공통 시스템 프롬프트)에서만 크다.
  • 테넌트 격리를 가정하지 말 것 — 교차 사용자 공유 시 부채널 등 리스크가 있고, 격리는 명시돼야 할 설계 선택.

🔎 이 장의 '지지하지 않는 결론'

  • "prefix caching은 항상 이득"이라고 말할 수 없습니다 — 접두가 반복되지 않으면 이득이 없습니다.
  • "prefix caching은 안전하다"를 단정할 수 없습니다 — 테넌트 격리 여부가 확인돼야 합니다.

✍️ 확인 문제

  1. exact prefix hit가 재사용하는 범위가 "첫 불일치 지점까지"인 이유를, autoregressive KV의 성질로 설명하세요.
  2. 의미가 비슷한 두 프롬프트가 prefix hit를 못 내는 이유는?
  3. (조건 유형) "prefix caching은 빠르고 안전하다"는 문장에서, '빠르다'와 '안전하다' 각각이 성립하려면 어떤 조건이 필요합니까?
다음 묶음(4부): 11 · 양자화의 절충 → 12 · speculative decoding과 MTP. 정밀도와 속도의 거래로.