본문 바로가기

09. PagedAttention

핵심 질문
  • KV 캐시를 "블록"으로 나눠 관리하면 어떤 낭비가 사라지는가?
  • 논리 블록과 물리 블록을 나눈다는 것은 무슨 뜻인가?

목표
  • PagedAttention의 원 설계(논리/물리 KV 블록)를 운영체제 가상 메모리에 빗대 이해한다.
  • 원 논문의 설계특정 vLLM 버전의 현재 명칭의 경계를 보존한다.

여정에서의 위치

08장에서 KV allocation(블록을 어떻게 줄까)이 남은 문제로 넘어왔습니다. 04장에서는 allocator 여유·단편화가 VRAM을 갉아먹는다고 했고, 05장에서는 KV가 토큰과 함께 자란다고 했습니다. PagedAttention은 이 셋의 교차점 — KV 캐시의 단편화 — 를 겨냥한 설계입니다.

문제: 연속 할당의 단편화

KV를 요청마다 하나의 연속된 큰 덩어리로 잡으면 두 낭비가 생깁니다.

  • 내부 단편화: 생성이 어디까지 갈지 몰라 최대 길이만큼 미리 잡으면, 실제로 짧게 끝난 요청은 잡아둔 공간 대부분을 낭비합니다.
  • 외부 단편화: 요청들이 들고 나면서 빈 공간이 조각나, 총량은 남는데 연속으로는 큰 요청을 못 넣는 상황.

일상 비유: 극장에서 일행마다 딱 붙은 좌석 블록을 통째로 예약하게 하면, 자리가 군데군데 남아도 큰 일행을 못 받습니다.

해법: 페이지처럼 나눠 담기

PagedAttention은 운영체제의 가상 메모리(virtual memory)·페이징(paging)에서 아이디어를 빌립니다. KV 캐시를 고정 크기 블록(block)으로 잘라, 요청의 토큰들을 이 블록들에 나눠 담습니다. 핵심은 두 층위를 분리한 것입니다.

  • 논리 블록(logical block): 요청 입장에서 본 "내 토큰들의 순서상 위치". 연속적으로 보입니다.
  • 물리 블록(physical block): VRAM 안 실제 저장 위치. 연속일 필요가 없습니다.
  • 블록 테이블(block table): 논리 블록 → 물리 블록의 매핑표. 요청은 논리적으로 연속이라 여기지만, 실제로는 흩어진 물리 블록에 저장됩니다.
flowchart LR
    subgraph 요청관점 [논리 블록: 연속으로 보임]
        L0[논리0]:::comp --> L1[논리1]:::comp --> L2[논리2]:::comp
    end
    BT[블록 테이블<br/>논리→물리 매핑]:::ctrl
    subgraph VRAM [물리 블록: 흩어져 있음]
        P7[물리7]:::mem
        P2[물리2]:::mem
        P9[물리9]:::mem
    end
    L0 --> BT --> P7
    L1 --> BT --> P2
    L2 --> BT --> P9

    classDef comp fill:#d0ebff,stroke:#1971c2,color:#000;
    classDef mem fill:#e5dbff,stroke:#7048e8,color:#000;
    classDef ctrl fill:#c3fae8,stroke:#0ca678,color:#000;

이렇게 하면 외부 단편화가 사라지고(빈 물리 블록 아무 데나 쓰면 됨), 내부 단편화는 마지막 블록 하나로 제한됩니다(미리 최대치를 잡지 않고, 필요할 때 블록 단위로 늘림). 그 결과 같은 VRAM으로 더 많은 동시 요청을 담을 수 있게 됩니다.

📌 핵심
이것이 05장에서 "하한 ≠ 실제 할당"이라 한 이유의 절반입니다. 실제 할당은 블록 단위로 이뤄지므로, 마지막 블록의 미사용분만큼 하한보다 큽니다.

⚠️ 원 설계 vs 특정 버전 명칭 — 경계를 지켜라

여기서 이 안내서의 핵심 규율을 적용합니다.

  • 원 논문의 설계 개념(논리/물리 KV 블록, 블록 테이블, 페이징식 관리)은 안정적입니다. 위 설명은 그 설계에 대한 것입니다.
  • 특정 프레임워크의 현재 구현·명칭(vLLM의 KV Cache Manager, 블록 크기 기본값, V1에서의 세부 동작 등)은 버전마다 바뀝니다. vLLM 문서는 PagedAttention을 "KV 캐시를 비연속 블록에 저장하는 기법"으로, KV Cache Manager를 그 할당 주체로 설명합니다(vLLM V1, 확인일 2026-07-20).
🔬 증거 읽기
"PagedAttention이 KV 단편화를 없앤다"는 설계 수준 주장은 원 논문(PRIMARY)에 근거합니다. 하지만 "그래서 처리량이 몇 배"라는 수치는 논문의 특정 실험 조건(measured)이며, 다른 모델·워크로드·하드웨어·버전에 그대로 옮길 수 없습니다. owner 저장소에 코드가 있다는 사실은 구현의 존재를 보증할 뿐, 당신의 환경에서의 성능을 보증하지 않습니다(REPRODUCTION과 구분).
⚖️ 절충
블록 페이징은 단편화를 줄이는 대신 블록 테이블 관리·간접 참조(indirection)라는 부가 비용을 더합니다. 대개 이득이 크지만 "공짜"는 아니며, 블록 크기 선택(작으면 단편화↓·테이블 오버헤드↑, 크면 반대)이라는 조절점이 있습니다.

이 설계가 다음 장을 가능하게 한다

블록 단위로 KV를 관리하면, 여러 요청이 같은 물리 블록을 공유하는 것도 가능해집니다. 프롬프트 앞부분이 같은 요청들이 그 부분의 KV 블록을 나눠 쓸 수 있다면, 중복 prefill을 피할 수 있습니다 — 이것이 다음 장 prefix caching입니다.

📌 핵심

  • PagedAttention은 KV를 고정 크기 블록으로 나눠, 논리 블록(연속처럼 보임)물리 블록(흩어짐)을 블록 테이블로 매핑.
  • OS 가상 메모리·페이징의 아이디어를 KV 캐시에 적용 → 외부 단편화 제거, 내부 단편화는 마지막 블록으로 제한.
  • 원 논문 설계(안정)와 특정 vLLM 버전 명칭·기본값(가변)을 구분해 읽어야 한다.
  • 블록 공유 가능성이 다음 장(prefix caching)을 연다.

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

  • "PagedAttention을 쓰면 처리량이 몇 배 는다"를 조건 없이 말할 수 없습니다 — 논문의 특정 실험 조건입니다.
  • vLLM의 현재 블록 크기·컴포넌트 명칭을 이 안내서만으로 단정할 수 없습니다 — 버전 의존이라 unknown은 문서·버전 확인이 필요합니다.

✍️ 확인 문제

  1. 내부 단편화와 외부 단편화를 정의하고, PagedAttention이 각각을 어떻게 다루는지 설명하세요.
  2. 논리 블록과 물리 블록을 나누는 이유를, 블록 테이블의 역할과 함께 설명하세요.
  3. (조건 유형) "PagedAttention 덕분에 우리 서버가 X배 빨라졌다"는 주장을 읽을 때, 원 논문 근거와 실제 성능 주장을 어떻게 분리해 평가하시겠습니까?
다음 장: 10 · prefix caching — 같은 앞부분을 재사용하기(그리고 테넌트 격리를 가정하지 않기).