프리픽스 비중이 큰 워크로드를 위한 SGLang과 RadixAttention(SGLang and RadixAttention for Prefix-Heavy Workloads)

SGLang은 KV 캐시(KV cache)를 래딕스 트리(radix tree)에 저장되는 1급(first-class) 재사용 자원으로 다룹니다. vLLM이 요청을 선착순(First-Come, First-Served; FCFS)으로 스케줄링하는 반면, SGLang의 캐시 인지 스케줄러(cache-aware scheduler)는 더 긴 공유 프리픽스(prefix)를 가진 요청을 우선합니다. 사실상 깊이 우선 래딕스 순회(depth-first radix traversal)를 수행해 자주 쓰이는 가지(hot branch)가 HBM(High Bandwidth Memory)에 계속 남도록 만드는 방식입니다. Llama 3.1 8B와 ShareGPT 형태의 1K 프롬프트(prompt)에서 SGLang은 약 16,200 tok/s를 기록하고, vLLM은 약 12,500 tok/s를 기록합니다. 약 29%의 우위입니다. 프리픽스 비중이 큰 RAG 워크로드에서는 이점이 6.4배까지 도달합니다. 음성 클로닝(voice cloning) 형태의 워크로드에서는 캐시 적중률(cache hit rate)이 86%를 넘었습니다. 2026년 기준으로 xAI, LinkedIn, Cursor, Oracle, GCP, Azure, AWS 전반에서 400,000개 이상의 GPU에 배포되어 있습니다. 함정은 프리픽스 순서(prefix ordering)가 일관되지 않으면 6.4배라는 숫자가 사라진다는 점이며, 결국 순서는 엔지니어가 직접 당길 수 있는 지렛대(lever)입니다.

유형: Learn 언어: Python(표준 라이브러리, 학습용 래딕스 트리 캐시 + 캐시 인지 스케줄러) 선수 지식: Phase 17 · 04(vLLM Serving Internals), Phase 14(Agentic RAG) 예상 시간: 약 75분

학습 목표

  • RadixAttention을 도식화할 수 있습니다. 프리픽스가 래딕스 트리에 어떻게 저장되는지, 같은 가지(branch)에 뿌리를 둔 시퀀스(sequence)들이 KV 블록(KV block)을 어떻게 공유하는지 설명합니다.
  • 캐시 인지 스케줄링(cache-aware scheduling)이 무엇인지 설명하고, 프리픽스 비중이 큰 트래픽에서 선착순(FCFS)이 왜 잘못된 선택인지 말할 수 있습니다.
  • 프리픽스 캐시 적중률(prefix-cache hit rate)과 프롬프트 길이 분포가 주어졌을 때 기대 가속(speedup)을 계산할 수 있습니다.
  • 6.4배라는 숫자를 현실로 만들거나 잃어버리게 만드는 프롬프트 순서(prompt ordering) 규율을 말할 수 있습니다.

문제

고전적인 서빙(serving)은 각 요청의 프롬프트를 들여다볼 수 없는 덩어리로 취급합니다. 5,000개의 RAG 요청이 모두 같은 2,000 토큰(token)짜리 시스템 프롬프트(system prompt)와 같은 검색 서두(retrieval preamble)로 시작하더라도, vLLM은 그 2,000 토큰 프리픽스를 5,000번 프리필(prefill)합니다. GPU는 같은 일을 계속 반복하는 셈입니다.

관찰은 단순합니다. 에이전트(agent) 워크로드와 RAG 워크로드의 프롬프트는 거의 항상 긴 프리픽스를 공유합니다. 시스템 프롬프트, 도구 스키마(tool schema), 퓨샷 예시(few-shot example), 검색 헤더(retrieval header), 대화 이력(conversation history)이 요청 사이에서 반복됩니다. 그 프리픽스의 KV 캐시를 한 번 저장하고 재사용할 수 있다면 다시 프리필할 필요가 없습니다.

RadixAttention은 정확히 이 일을 합니다. 토큰을 래딕스 트리에 색인(index)합니다. 각 노드(node)는 루트(root)에서 자신까지 오는 토큰 시퀀스의 KV 블록을 소유합니다. 새 요청은 트리를 따라 걷습니다. 토큰이 일치하는 노드는 해당 노드의 KV 블록을 재사용합니다. 프리필 비용은 전체 프롬프트가 아니라 "새로운" 접미부(suffix)에 비례하게 됩니다.

남는 도전은 스케줄링입니다. 두 요청이 2,000 토큰짜리 프리픽스를 공유하고 세 번째 요청은 같은 프리픽스 중 200 토큰만 공유한다면, 긴 프리픽스가 HBM에 남아 있도록 두 개의 긴 공유 요청을 함께 처리하고 싶을 것입니다. FCFS는 정반대로 동작합니다. 먼저 도착한 요청을 처리하기 때문에, 다음 긴 프리픽스 요청이 도착하기 전에 자주 쓰이던 가지를 축출(evict)해 버릴 수 있습니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.프리픽스 캐싱(prefix caching)이 활성화된 상태에서 라운드 로빈(round-robin) 부하 분산이 LLM 추론 성능을 저해하는 이유는 무엇인가요?

2.RadixAttention이 공유 KV 캐시 프리픽스를 저장하고 조회하는 데 사용하는 자료 구조는 무엇인가요?

0/2 답변 완료

개념

KV 색인으로서의 래딕스 트리

래딕스 트리(radix tree, 압축 트라이(compact trie))는 토큰 시퀀스를 저장합니다. 각 노드는 토큰 범위와 그 범위에 대해 계산된 KV 블록을 소유합니다. 자식(child)은 시퀀스를 하나 이상의 토큰만큼 확장합니다.

root
 |- "You are a helpful assistant..."  (2,000 tokens, 124 KV blocks)
      |- "Context: <doc A>..."        (500 tokens, 31 blocks)
           |- "Question: Alice..."    (80 tokens, 5 blocks)
           |- "Question: Bob..."      (95 tokens, 6 blocks)
      |- "Context: <doc B>..."        (520 tokens, 33 blocks)

새 요청이 시스템 프롬프트 + "Context: " + "Question: Carol" 형태로 들어옵니다. 스케줄러는 트리를 걷습니다. 시스템 프리픽스가 일치해 124 블록을 재사용하고, doc-A 가지가 일치해 31 블록을 재사용한 뒤, "Question: Carol"에 대해서만 새 블록 4개를 할당합니다. 프리필 비용은 새 토큰 4 블록뿐입니다. 트리가 없다면 160 블록이 필요합니다. 프리필에서 약 40배 절약입니다.

캐시 인지 스케줄링

래딕스 트리 기반 재사용도 캐시가 계속 휘둘리면(churn) 의미가 없습니다. 핵심 정책은 두 가지입니다.

  1. 깊이 우선 디스패치(Depth-first dispatch). 대기열(queue)에서 다음 요청을 고를 때 현재 실행 중인 집합(running set)과 같은 가지에 뿌리를 둔 요청을 선호합니다. 이렇게 하면 자주 쓰이는 가지가 고정(pinned) 상태로 유지됩니다.
  2. 블록 수준이 아니라 가지 수준의 LRU(branch-level LRU, not block-level). 개별 블록이 아니라 가지 전체를, 가장 짧게 쓰인 잎(leaf)부터 축출합니다. 그래야 캐시의 모양이 래딕스 트리의 모양과 맞습니다.

FCFS는 두 정책을 모두 위반합니다. 2,000 토큰을 공유하는 요청이 50 토큰만 공유하는 요청 뒤에 앉아 있고, 결과적으로 50 토큰짜리 요청을 받아들이느라 2,000 토큰짜리 가지가 축출될 수 있습니다.

외워야 할 벤치마크 숫자

  • Llama 3.1 8B, H100, ShareGPT 1K 프롬프트: SGLang 약 16,200 tok/s 대 vLLM 약 12,500 tok/s. 약 29% 우위.
  • 프리픽스 비중이 큰 RAG(같은 시스템 + 같은 문서, 다른 질문): SGLang에서 최대 6.4배.
  • 음성 클로닝 워크로드: 86.4% 프리픽스 캐시 적중률.
  • SGLang 고객의 운영(production) 환경 적중률: 프롬프트 규율에 따라 50-99%.
  • 2026년 기준 400,000개 이상의 GPU에 배포됨.

순서가 만드는 함정(ordering gotcha)

6.4배라는 숫자는 일관된 프롬프트 템플릿(prompt template) 순서에 의존합니다. 어떤 요청은 [system, tools, context, history, question] 순서로 프롬프트를 만들고, 다른 요청은 [system, context, tools, history, question] 순서로 만든다면 트리는 공유 프리픽스를 찾지 못합니다. 사람 눈에는 공유 프리픽스처럼 보이지만 래딕스 트리에게는 서로 다른 시퀀스 두 개입니다.

엔지니어가 당길 수 있는 지렛대는 이렇게 표현할 수 있습니다. 프롬프트 템플릿이 곧 캐시 키(cache key)입니다. 순서를 고정하세요. 바뀌지 않는 것(시스템 프롬프트, 도구, 스키마)을 가장 먼저 둡니다. 검색 컨텍스트(retrieval context)를 그다음에 둡니다. 사용자 질문(user question)은 가장 마지막에 둡니다. 동적(dynamic) 콘텐츠를 프리픽스 안에 끼워 넣지 마세요.

연구의 실제 사례에서는 동적 콘텐츠를 캐시 가능한(cacheable) 프리픽스 밖으로 옮기는 한 번의 변경만으로 어떤 배포의 캐시 적중률이 7%에서 74%로 올라갔습니다.

RadixAttention이 이기는 곳과 지는 곳

이기는 곳:

  • RAG: 같은 검색 서두, 다른 질문.
  • 에이전트: 같은 도구 스키마, 다른 쿼리(query).
  • 긴 시스템 프롬프트를 가진 챗(chat).
  • 반복되는 서두가 있는 음성/비전(voice / vision) 워크로드.

지는 곳, 즉 vLLM 수준 처리량으로 돌아가는 곳:

  • 고유한 프롬프트를 가진 단발성 생성(single-shot generation). 예: 코드 자동완성, 시스템 프롬프트 없는 자유 형식(open-ended) 챗.
  • 모든 요청이 프리픽스 안에 고유한 콘텐츠를 끼워 넣는 동적 프롬프트.

왜 이것은 커널 문제가 아니라 스케줄러 문제인가

KV 재사용을 커널(kernel) 트릭으로 구현할 수도 있습니다. SGLang의 통찰은 재사용이 스케줄러가 자주 쓰이는 가지를 상주(resident) 상태로 유지할 때만 비용을 회수한다는 점입니다. 단순히 "있으면 재사용"하는 정책은 혼합 부하(mixed load)에서 캐시를 계속 휘두르게 만듭니다. 래딕스 트리 색인 기반 스케줄러가 바로 그 커널 트릭을 운영 환경에서 29%의 우위로 바꿔 주는 장치입니다.

vLLM과의 상호작용

두 시스템은 엄격한 경쟁자가 아닙니다. 2026년에 vLLM도 프리픽스 캐싱(--enable-prefix-caching)과 캐시 인지 라우터(Rust로 작성된 vLLM Router)를 추가했습니다. 격차는 줄었지만 완전히 사라지지는 않았습니다. SGLang은 전체 스택(stack)이 래딕스 우선(radix-first)으로 설계된 반면, vLLM은 그 기능을 나중에 접목(graft)한 쪽입니다. 프리픽스 재사용이 지배하는 워크로드에서는 SGLang이 여전히 기본값입니다. 강한 프리픽스 패턴이 없는 범용 서빙에서는 vLLM이 같거나 더 낫습니다.

사용해보기

code/main.py는 학습용 래딕스 트리 KV 캐시와 두 가지 스케줄러 정책, 즉 FCFS와 캐시 인지 스케줄러를 구현합니다. 같은 워크로드를 두 방식으로 실행하고 프리픽스 캐시 적중률과 처리량 차이(throughput delta)를 보고합니다. 그런 다음 "뒤섞인 순서(scrambled ordering)" 워크로드를 실행해 6.4배라는 이점이 어떻게 무너지는지 보여줍니다.

산출물 만들기

이 강의는 outputs/skill-radix-scheduler-advisor.md를 만듭니다. 워크로드 설명, 즉 프롬프트 템플릿의 형태, 검색 패턴, 동시 테넌트(tenant) 수를 입력하면 프롬프트 순서 처방과 SGLang 도입 여부(go/no-go)를 생성합니다.

연습문제

  1. 쉬움: code/main.py를 실행합니다. 같은 워크로드에서 FCFS와 캐시 인지 스케줄러를 비교합니다. 두 결과의 차이는 프리필 절감, 디코드(decode) 절감, 대기열 지연(queue delay) 중 어디에서 옵니까?
  2. 중간: 프롬프트가 [system, tools, context]를 무작위로 뒤섞도록(permute) 워크로드를 수정합니다. 다시 실행하면 적중률은 어떻게 변합니까? 왜 그렇습니까?
  3. 중간: Llama 3.1 8B에서 2,000 토큰짜리 시스템 프롬프트를 하나의 래딕스 가지로 상주 상태로 유지할 때의 HBM 비용을 계산합니다. 프리픽스 재사용이 없는 16-시퀀스 배치(batch)와 비교합니다.
  4. 어려움: SGLang RadixAttention 논문을 읽습니다. 프리픽스 비중이 큰 부하에서 트리 형태(tree-shaped)의 LRU 축출이 블록 형태(block-shaped) LRU보다 나은 이유를 세 문장으로 설명합니다.
  5. 어려움: 어떤 고객이 캐시 적중률이 8%밖에 안 된다고 보고합니다. 가능성이 높은 원인 세 가지와 각각에 대해 실행할 진단(diagnostic)을 말합니다.

핵심 용어

용어흔한 설명실제 의미
RadixAttention"SGLang의 그것"공유 프리픽스가 KV 블록을 재사용하도록 KV 캐시를 래딕스 트리로 색인하는 방식
래딕스 트리(Radix tree)"압축 트라이(compact trie)"각 노드가 토큰 범위와 해당 KV 블록을 소유하는 트리
캐시 인지 스케줄러(Cache-aware scheduler)"자주 쓰이는 가지를 먼저(hot-branch-first)"상주 가지를 공유하는 요청을 선호하는 스케줄러
프리픽스 캐시 적중률(Prefix-cache hit rate)"프롬프트 중 공짜로 처리된 비율"재사용된 KV 블록에서 처리된 프롬프트 토큰의 비율
FCFS"선착순(first-come first-served)"프리픽스 지역성(locality)을 깨는 기본 스케줄링
가지 수준 LRU(Branch-level LRU)"잎부터 축출(evict the leaf)"래딕스 모양에 맞춘 축출 정책
프롬프트 템플릿 순서(Prompt template ordering)"캐시 키(cache key)"프롬프트 구성요소의 순서가 트리가 공유할 수 있는 범위를 결정함
시스템 프롬프트 고정(System prompt pinning)"상주 프리픽스(resident prefix)"축출 흔들림(eviction thrash)을 피하기 위해 변하지 않는 시스템 부분을 계속 상주 상태로 유지하는 방식

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

radix-scheduler-advisor

Advise on SGLang adoption and prompt-ordering discipline for prefix-heavy workloads that want RadixAttention's cache reuse.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.배포 환경의 프리픽스 캐시 적중률이 74%에서 7%로 떨어졌습니다. 가장 가능성 높은 원인은 무엇인가요?

2.SGLang의 캐시 인지 스케줄러가 FCFS보다 깊이 우선 디스패치(depth-first dispatch)를 선호하는 이유는 무엇인가요?

3.RadixAttention이 vLLM 대비 큰 속도 향상을 제공하지 못하는 시나리오는 무엇인가요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다