LLM WikiAccess-protected knowledge portal

WIKI

SGLang RadixAttention: KV 캐시를 트리로 공유하는 LLM 추론 아키텍처

같은 prompt를 매번 새로 계산하는 비용 RAG 파이프라인을 프로덕션에서 운영하면 금방 눈치채는 패턴이 있다. 수백만 개의 요청이 같은 시스템 프롬프트와 같은 문서 청크를 앞에 달고 들어온다. few shot 분류기는 매 요청마다 동일한 예제 10개를 prefill한다. 멀티턴 에이전트는 대화가 길어질수록 앞부분을 반복한다. GPU에서 prefill은 비싸다. transformer의 attention은 모든 token에 대

경로human/study/content/ai-frontier/04-sglang-radixattention-prefix-kv-cache.md
카테고리Study
태그#ai-review #cache #frontier #prefix #radixattention #sglang #study

같은 prompt를 매번 새로 계산하는 비용

RAG 파이프라인을 프로덕션에서 운영하면 금방 눈치채는 패턴이 있다. 수백만 개의 요청이 같은 시스템 프롬프트와 같은 문서 청크를 앞에 달고 들어온다. few-shot 분류기는 매 요청마다 동일한 예제 10개를 prefill한다. 멀티턴 에이전트는 대화가 길어질수록 앞부분을 반복한다.

GPU에서 prefill은 비싸다. transformer의 attention은 모든 token에 대해 key·value를 계산해 KV 캐시에 올려야 한다. 이 캐시가 요청 단위로 격리되면, 공통 prefix의 KV는 동일한 연산을 반복한다. 이론적으로는 낭비고, 프로덕션에서는 비용이다.

vLLM의 PagedAttention은 KV 캐시를 메모리 page 단위로 나눠 fragmentation을 줄였다. 하지만 기본적으로는 요청 단위 격리다. 공통 prefix의 공유는 separate feature로 구현되어 있고, 그 범위는 여전히 정적이다.

SGLang은 이 문제를 정면으로 겨냥한다. RadixAttention은 KV 캐시를 radix tree 구조로 유지하고, 들어오는 모든 요청에서 공통 prefix를 찾아 계산을 재사용한다. 이 장에서는 RadixAttention의 작동 원리, MLA 지원 아키텍처, 구조화된 출력(structured output) 최적화, 그리고 프로덕션 배포 시 고려사항을 살펴본다.

이 장은 SGLang 공식 문서, GitHub 리포지토리, 관련 기술 분석 자료를 기준으로 한다. vLLM과의 성능 비교 수치는 공개된 벤치마크를 인용하며, 워크로드와 하드웨어에 따라 다를 수 있다.


RadixAttention: KV 캐시를 트리로 보는 관점

PagedAttention의 page는 물리적 메모리 단편화를 해결한다. 하지만 서로 다른 요청이 같은 prefix를 가지고 있다는 의미적 사실을 활용하지 않는다.

RadixAttention의 핵심 아이디어는 단순하다. KV 캐시를 token sequence의 공통 prefix를 노드로 갖는 radix tree(압축 트라이)에 저장하고, 새 요청이 올 때 이 트리에서 longest prefix match를 찾아 기존 KV를 그대로 사용한다.

요청 A: [시스템 프롬프트 | 문서 1 | 질문 A]
요청 B: [시스템 프롬프트 | 문서 1 | 질문 B]
요청 C: [시스템 프롬프트 | 문서 2 | 질문 C]

트리 구조:
root
  └─ [시스템 프롬프트] ─ 공유 ─
        ├─ [문서 1] ─ 공유 ─
        │     ├─ [질문 A]  ← 요청 A 고유
        │     └─ [질문 B]  ← 요청 B 고유
        └─ [문서 2] ─ [질문 C]  ← 요청 C 고유

요청 B가 들어오면 [시스템 프롬프트 + 문서 1]에 해당하는 KV는 이미 트리에 있다. SGLang은 이 부분의 prefill을 건너뛰고 [질문 B]만 새로 계산한다.

트리 구조와 메모리 관리

RadixAttention은 GPU 메모리 위에서 동작하며, 트리 노드의 KV 데이터는 연속 메모리 블록을 사용한다. 각 노드는 token 범위, 해당 KV 포인터, 참조 카운트, 마지막 접근 시각을 관리한다.

메모리가 부족해지면 LRU(Least Recently Used) 정책으로 리프 노드부터 eviction한다. 참조 카운트가 0인(현재 활성 요청이 사용하지 않는) 노드만 제거 대상이 된다. 이 설계는 진행 중인 요청의 KV를 건드리지 않으면서 캐시 적중률을 유지한다.

RadixAttention: 공통 prefix KV 캐시를 트리로 공유한다 들어오는 요청 요청 A 시스템 프롬프트 문서 청크 1 질문 A 요청 B 시스템 프롬프트 문서 청크 1 질문 B 요청 C 시스템 프롬프트 문서 청크 2 질문 C GPU 메모리 — Radix Tree KV Cache root 빈 prefix 시스템 프롬프트 KV refcount=3 모든 요청이 공유 공유 KV 문서 1 KV refcount=2 A·B 공유 문서 2 KV refcount=1 C만 질문 A KV 신규 계산 질문 B KV 신규 계산 질문 C KV 신규 계산 계산 절감 효과 요청 B 시스템+문서1 skip prefill 비용 ↓↓ RAG 시나리오 60%+ prefix 공유 최대 6.4× 처리량 메모리 효율 refcount=0 노드만 LRU eviction DeepSeek V3 vLLM 대비 3.1× 추론 속도 공통 KV는 treed에서 직접 참조한다. 신규 계산은 요청 고유 suffix뿐이다.
SGLang RadixAttention 아키텍처와 KV 캐시 공유 원리

PagedAttention과 무엇이 다른가

vLLM의 PagedAttention은 KV 캐시를 고정 크기 page로 나눈다. 목적은 메모리 단편화 제거다. 서로 다른 요청의 page는 물리적으로 불연속 메모리에 흩어져 있어도 논리적으로 이어진다.

공통 prefix 공유를 위해 vLLM도 prefix caching 기능을 별도로 제공한다. 하지만 두 접근의 근본적 차이는 설계의 우선순위다.

관점PagedAttention (vLLM)RadixAttention (SGLang)
KV 캐시 구조고정 크기 page, 요청별 논리 주소radix tree, token sequence 기반
prefix 공유별도 캐싱 레이어로 구현트리 구조가 공유를 기본값으로 만든다
재사용 탐색정적 prefix 비교longest match를 트리에서 탐색
evictionpage 단위 LRUleaf 노드부터 refcount 기반 LRU
동적 공유제한적요청 도착 순서에 관계없이 공유

중요한 것은 어느 구현이 항상 낫다는 게 아니라, 워크로드가 prefix 공유를 얼마나 많이 가지느냐다. 고정 시스템 프롬프트 없는 단발성 요청이 대부분이라면 RadixAttention의 트리 탐색 overhead가 이득보다 클 수 있다. prefix 공유가 60% 이상인 워크로드에서야 RadixAttention의 가속이 드러난다.


MLA: DeepSeek V3에서 3.1× 빠른 이유

DeepSeek V3는 MLA(Multi-head Latent Attention)를 사용한다. 일반 MHA(Multi-head Attention)가 각 head마다 전체 KV를 저장하는 것과 달리, MLA는 low-rank 투영으로 KV를 압축한 잠재 벡터(latent vector)를 저장한다. KV 캐시 크기가 크게 줄고, 그만큼 더 긴 context를 같은 메모리로 처리할 수 있다.

그런데 이 구조는 기존 attention 커널이 그대로 최적화하기 어렵다. 잠재 벡터를 실제 K·V로 복원하는 단계가 추가되기 때문이다.

SGLang은 MLA를 위한 복수의 backend를 통합했다.

backend특징
FlashAttention3현재 기본값 MLA backend. H100 Hopper 아키텍처의 WGMMA·TMA 명령을 활용
FlashInfer페이지 단위 KV 처리에 최적화. 짧은 decode 단계에서 강점
FlashMLADeepSeek이 MLA를 위해 직접 공개한 커널. CudaCore GEMMs 대신 Tensor Core를 사용
CutlassMLANVIDIA CUTLASS 기반. 커스터마이징 가능성이 높음

같은 모델을 처리하는데 SGLang이 vLLM보다 DeepSeek V3에서 3.1× 빠른 이유는 RadixAttention의 prefix 공유와 MLA 최적화 커널의 조합이다. 단순한 추론 엔진 차이가 아니라 모델 아키텍처에 맞는 backend를 적극적으로 지원한 결과다.


Structured Output: 압축 FSM으로 JSON 디코딩을 3× 빠르게

LLM에서 구조화된 출력(JSON 스키마, 함수 호출)은 두 가지 방식으로 구현된다. 하나는 후처리 검증, 다른 하나는 디코딩 단계에서 유효하지 않은 토큰을 직접 차단하는 방식이다.

후자가 더 강력하지만 비용이 있다. 토큰마다 현재 FSM(Finite State Machine) 상태에서 허용되는 다음 토큰 집합을 계산해야 한다. vocabulary가 128,000개라면 매 step마다 128,000개 중 허용 여부를 판단해야 한다.

SGLang은 압축 FSM(Compressed Finite State Machine)을 사용한다. 핵심은 JSON 스키마에서 파생된 FSM을 사전에 분석하고, vocabulary를 토큰 단위가 아니라 FSM transition 단위로 미리 인덱싱하는 것이다. 런타임에는 현재 상태에서 유효한 토큰 집합을 미리 계산된 마스크에서 O(1)으로 읽어온다.

일반 FSM                압축 FSM
매 step: O(vocab_size)  매 step: O(1) 마스크 조회
예: 128k token 검사    예: 미리 인덱싱된 비트마스크

SGLang 기준 JSON 디코딩이 나이브 구현 대비 약 3× 빠르다. 복잡한 중첩 JSON 스키마일수록 이 차이가 커진다.

이 기능은 도구 호출(tool calling), 함수 시그니처 추출, 데이터 추출 파이프라인에서 특히 중요하다. structured output을 검증 단계에서 디코딩 단계로 끌어들이면 재생성 재시도 비용도 줄어든다.


배포 아키텍처와 스케일링

SGLang은 단일 서버 배포부터 분산 클러스터까지 지원한다.

핵심 구성 요소

Zero-overhead CPU 스케줄러: 모든 요청 배치 결정을 Python GIL 밖에서 C++로 처리한다. 스케줄러가 GPU와 asyncronous하게 돌기 때문에 배치 구성 지연이 추론 throughput에 영향을 덜 준다.

Prefill-Decode 분리(Disaggregation): prefill(prompt 처리)과 decode(토큰 생성)를 별도 worker로 분리한다. prefill은 compute-bound, decode는 memory-bandwidth-bound이므로 분리하면 각자 최적 하드웨어를 쓸 수 있다. 멀티턴 에이전트에서 긴 context prefill이 decode throughput을 막는 문제를 줄인다.

Cache-aware 로드밸런서: 새 요청을 라우팅할 때 어떤 worker의 RadixAttention 트리에 해당 prefix가 이미 있는지를 고려한다. 캐시 히트가 높은 worker로 보내 cross-worker KV 재계산을 줄인다.

병렬 전략

Tensor Parallel  → 한 모델을 여러 GPU에 나눠 실행 (큰 모델)
Pipeline Parallel → 레이어를 나눠 GPU 간 파이프라인 (긴 모델)
Expert Parallel  → MoE 모델의 expert를 분산 (DeepSeek 등)
Data Parallel    → 요청을 여러 인스턴스에 분산 (수평 확장)

SGLang은 이 네 가지를 조합해 설정할 수 있다. DeepSeek V3처럼 MoE + MLA를 결합한 모델에서는 Expert Parallel과 MLA 커널 최적화를 같이 쓰는 것이 일반적이다.


SGLang이 적합한 워크로드와 그렇지 않은 워크로드

RadixAttention의 이점은 prefix 공유 비율과 직결된다. 이 비율이 낮으면 트리 탐색과 관리 overhead가 순이익을 상쇄한다.

워크로드SGLang이 유리한 이유
RAG 파이프라인같은 문서 청크가 여러 쿼리에 반복됨. prefix 히트율 높음
few-shot 분류기고정 예제가 모든 요청에 붙음. 예제 부분 KV 완전 공유
멀티턴 에이전트대화 앞부분이 누적됨. 긴 context일수록 공유 비율 높아짐
code completion코드베이스 prefix가 반복됨. 파일 단위 공유 가능
structured output압축 FSM으로 JSON 디코딩 가속
DeepSeek MoE 모델MLA 특화 커널로 vLLM 대비 현저한 속도 차이
워크로드주의할 점
완전히 무작위 요청prefix 공유 없음. 트리 탐색만 overhead
단발성 긴 promptcache hit 없고 eviction만 발생
짧은 문서 요약 반복prefix가 없으면 vLLM과 차이 없음
안정성이 최우선SGLang은 vLLM보다 ecosystem이 작아 provider 지원이 제한적일 수 있음

프로덕션 도입 체크리스트

워크로드 적합성 평가
프로덕션 요청 샘플에서 공통 prefix 길이와 비율을 측정한다. 60% 미만이면 RadixAttention 이득이 제한적이다.
모델 아키텍처를 확인한다. MLA(DeepSeek), MoE, 긴 context가 결합된 경우 SGLang의 MLA backend가 효과적이다.
structured output 요구가 있으면 vLLM outlines 대신 SGLang 압축 FSM과 throughput을 직접 비교한다.
KV 캐시 설정
GPU 메모리의 RadixAttention 할당량(--mem-fraction-static)을 먼저 측정하고 설정한다.
prefill-decode disaggregation이 필요한지 판단한다. prefill이 decode를 지연시키면 분리를 검토한다.
cache-aware 로드밸런서를 활성화해 cross-worker KV 재계산을 줄인다. 클러스터 규모가 작으면 overhead가 클 수 있다.
성능 측정
TTFT(Time To First Token)와 TPOT(Time Per Output Token)을 별도로 측정한다. prefix hit는 TTFT를 줄이고 TPOT에 영향이 적다.
cache hit rate를 모니터링한다. 히트율이 낮으면 eviction 설정과 workload 패턴을 검토한다.
vLLM과 같은 hardware에서 같은 workload로 A/B 비교한다. benchmark 수치를 그대로 적용하지 않는다.
운영·롤백
SGLang과 vLLM은 OpenAI-compatible API를 공유하므로 라우터 레이어만 바꾸면 전환 가능하다. 롤백 경로를 미리 준비한다.
모델 파일과 구성 호환성을 사전 검증한다. Hugging Face 형식은 대부분 지원하나, 커스텀 architecture는 확인이 필요하다.
SGLang 프로덕션 배포 운영 gate

정리

SGLang의 RadixAttention은 "KV 캐시를 요청 단위로 격리한다"는 기본 가정을 바꾼다. radix tree로 공통 prefix를 공유하면 RAG, few-shot, 멀티턴 워크로드에서 prefill 비용이 실질적으로 줄어든다.

MLA 특화 backend(FlashAttention3, FlashMLA 등)는 DeepSeek 계열처럼 attention 아키텍처가 다른 모델에서 기존 엔진 대비 눈에 띄는 성능 차이를 만든다. 압축 FSM structured output은 도구 호출과 JSON 추출이 많은 에이전트 파이프라인에서 디코딩 단계 자체를 빠르게 한다.

운영자가 기억할 것은 세 가지다. 첫째, 이득의 크기는 prefix 공유 비율에 달려 있다. 측정 없이 도입하면 overhead만 추가된다. 둘째, DeepSeek처럼 MLA를 쓰는 모델이라면 backend 선택이 latency·throughput에 결정적이다. 셋째, OpenAI-compatible API를 공유하므로 vLLM과 전환 비용이 낮다. 워크로드를 측정한 뒤 둘을 비교하고 선택하면 된다.

References