본문으로 건너뛰기
5분 AI.
GITHUB TRENDING PYTHON WEEKLY #9 딥다이브 · 2026-10-23 분석

sglang 딥다이브
— 같은 계산은 아끼고, GPU는 쉬지 않게

추론·서빙 프레임워크

빠른 판단

무엇
KV 캐시 재사용·요청 배치·GPU 메모리 스케줄링으로 LLM·멀티모달 모델을 API로 제공하는 프레임워크
이럴 때
오픈 모델의 긴 문맥·동시 요청을 처리하는 자체 추론 서비스를 구축하고 캐시·배치 정책을 조정할 때
입력
모델 가중치·서빙 설정과 생성 요청
결과
배치·캐시를 적용한 모델 응답·스트림
대형 언어 모델에 질문 하나를 보내는 코드는 짧습니다. 수백 명의 질문을 동시에 받아 빠르게 답하는 서버는 훨씬 복잡합니다. SGLang은 그 사이를 채우는 추론 서빙 프레임워크입니다. HTTP 요청이 토큰으로 바뀌고, 배치에 합류하고, GPU 메모리를 빌렸다가 돌려주는 과정을 소스 수준에서 따라갑니다. Python 비동기 처리부터 자료구조·메모리 관리·Rust 연동까지, 이미 배운 기초가 실제 시스템에서 만나는 지점을 공부합니다. (sgl-project/sglang · ⭐37,655 · 포크 9,819 · Python · Apache-2.0 · 2026-10-23 GitHub 기준)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

모델의 답을 여러 사용자에게 효율적으로 전달하는 실행 시스템

SGLang은 LLM·멀티모달 모델의 추론을 API 서비스로 제공하는 프레임워크입니다. 모델 가중치를 읽고, 입력을 숫자 토큰으로 바꾸고, 여러 요청을 묶어 실행한 뒤, 생성한 토큰을 다시 문장으로 돌려줍니다. 이름의 출발점은 구조화된 생성 언어이지만, 현재 저장소에는 서빙 런타임과 확산 모델 실행 엔진도 들어 있습니다.

이 저장소의 핵심은 모델을 더 똑똑하게 학습시키는 것이 아니라, 이미 있는 모델을 더 효율적으로 실행하는 방법입니다. 강화학습 시스템과 연결할 때도 주로 답변 후보를 생성하는 역할을 맡습니다. 학습용 최적화기와 역전파 전체를 이 서버가 대신한다는 뜻은 아닙니다.

용어 풀이
추론과 서빙
추론은 학습된 모델에 입력을 넣어 결과를 계산하는 일입니다. 서빙은 그 계산을 여러 사용자가 요청할 수 있도록 API·대기열·오류 처리·관측 기능까지 갖춰 운영하는 일입니다. 맛있는 요리를 만드는 능력과, 주문이 몰리는 식당을 운영하는 능력의 차이를 떠올리면 됩니다.
한 문장 비유

모델이 요리사라면, SGLang은 주문표·조리대·재료 창고를 함께 관리하는 주방입니다

질문마다 요리사를 새로 부르면 준비 시간이 길어집니다. 여러 주문의 공통 준비 작업을 재사용하고, 한 주문이 끝난 자리에 다음 주문을 넣으면 같은 장비로 더 많은 손님을 받을 수 있습니다.

KV 캐시는 미리 손질해 둔 재료, 스케줄러는 다음 조리 순서를 정하는 담당자, 배치는 함께 조리할 주문 묶음입니다. 재료를 무한정 보관할 수 없어서 버릴 시점도 정해야 합니다.

사용자에게 보이는 입구는 단순하다

기본 HTTP 서버는 /generate와 OpenAI 호환 /v1/chat/completions 등을 제공합니다. 전자는 SGLang의 요청 형식을 직접 사용하고, 후자는 익숙한 채팅 클라이언트를 연결하기 좋습니다. API 형식이 호환된다고 모든 공급자의 부가 기능까지 동일한 것은 아닙니다.

# 요청 형식 예시: POST /generate 의 JSON 본문
{
  "text": "배치 처리를 초보자에게 설명해 줘.",
  "sampling_params": {
    "temperature": 0,
    "max_new_tokens": 64
  },
  "stream": false
}

이 필드는 python/sglang/srt/managers/io_struct.py의 GenerateReqInput에서 확인할 수 있습니다. sampling_params는 생성 길이와 무작위성 같은 조건이고, stream은 결과를 한 번에 받을지 생성 중간에도 받을지를 정합니다.

학습할 때는 세 층을 나눠 보세요. 입구는 요청 검증과 응답, 조율은 배치와 캐시, 실행은 모델과 GPU 커널입니다. 처음부터 모든 모델의 수학을 이해하지 않아도 입구에서 실행까지 연결되는 흐름은 추적할 수 있습니다.

2왜 주목받는가

반복되는 긴 문맥과 동시 요청이 추론 시스템의 중요한 문제가 되었다

2-1. 같은 지시문을 계속 읽는 낭비를 줄인다

상담 챗봇은 매 요청에 같은 시스템 지시문을 붙이고, 문서 질의 서비스는 같은 문서를 여러 번 읽습니다. 앞부분이 동일한 토큰열이라면 이전 계산의 일부를 재사용할 여지가 있습니다. SGLang의 대표 아이디어인 RadixAttention은 이런 접두어 공유를 KV 캐시 관리와 연결합니다. 원래의 설계 배경은 SGLang 논문에서 확인할 수 있습니다.

여기서 재사용하는 것은 완성된 답변 문자열이 아닙니다. 입력 접두어를 처리하며 만든 모델 내부 상태입니다. 따라서 뒷부분의 질문이 달라도 앞부분이 정확히 같으면 도움이 될 수 있습니다. 의미가 비슷한 문장을 벡터 검색으로 찾아 답을 재활용하는 기능과는 원리가 다릅니다.

2-2. 요청을 받은 순서와 GPU 실행 묶음을 분리한다

사용자마다 입력 길이와 출력 길이가 다릅니다. 가장 긴 응답이 끝날 때까지 처음의 묶음을 고정하면 빈자리가 생깁니다. Scheduler.get_next_batch_to_run()은 실행 중인 요청을 관리하면서 새 요청이 합류할 배치를 결정합니다. LLM 서버의 처리량은 모델 계산 속도뿐 아니라, 다음 계산을 얼마나 빈틈없이 준비하느냐에도 달려 있습니다.

용어 풀이
연속 배칭 (continuous batching)
요청 묶음을 끝까지 고정하지 않고 생성 단계가 진행되는 동안 완료된 요청을 빼고 새 요청을 받아들이는 방식입니다. 버스 한 대가 모든 승객의 목적지에 도착해야 다음 승객을 태우는 대신, 정류장마다 승하차시키는 모습과 비슷합니다.

2-3. 경쟁 도구와 비교하면 무엇이 보이는가

도구특징과 학습 초점SGLang을 살펴볼 이유
SGLang접두어 캐시·배치 스케줄링·모델 실행·분산 서빙을 연결 알고리즘이 API 서버의 상태 관리와 만나는 경로를 한 저장소에서 추적
vLLMPagedAttention과 블록 단위 KV 메모리 관리, 접두어 캐싱 같은 문제를 트리·캐시 선택 계층과 어떻게 결합하는지 비교 학습
llama.cppC/C++ 중심 추론, 양자화와 여러 로컬 실행 환경 로컬 실행 중심 관점에서 다중 요청 서버의 프로세스·배치 설계로 시야 확장

vLLM도 접두어 캐싱을 지원합니다. “SGLang에만 캐시가 있다”는 비교는 틀립니다. 비교 근거는 vLLM의 접두어 캐시 설계 문서와 llama.cpp 공식 저장소입니다. 이 표는 구조와 공부 방향을 비교하며, 동일 조건의 속도 순위를 뜻하지 않습니다.

2-4. 2026년의 관심과 연결되는 지점

2026-10-23 GitHub Trending Python Weekly 9위, 스타 37,655개는 관심의 크기를 보여 줍니다. 다만 그 주 순위가 오른 단일 원인을 이 숫자만으로 증명할 수는 없습니다. 위 항목은 현재 코드가 다루는 문제를 바탕으로 해석한 관심 요인입니다. 2024년 논문의 성능 수치도 2026년의 모든 모델·GPU에 그대로 적용할 수 없습니다.

3기술 스택 전체 지도

의존성 선언과 실제 구현을 함께 읽어야 보이는 다중 언어 시스템

주 언어는 Python이지만 Python만으로 완결된 서버는 아닙니다. 요청 조율은 Python, 장치 계산은 PyTorch와 전용 커널, 일부 서버·라우팅·확장 모듈은 Rust가 맡습니다. 아래 버전은 커밋 611a703의 선언값입니다. 설치 환경에서 실제로 선택된 모든 패키지의 버전 목록과는 구분해야 합니다.

3-1. 백엔드: 요청 계층과 모델 실행 계층

층기술·선언 버전어디서 확인하고 무엇을 배우나
Python 기반Python >=3.11, torch==2.14.1, transformers==5.19.0 python/pyproject.toml — 모델 설정·가중치·텐서 연산의 경계
HTTP·검증fastapi, pydantic, msgspec, uvicorn>=0.51 동일 의존성 파일 — FastAPI·Pydantic·msgspec은 버전 고정 없음. 요청 구조와 서버 실행을 분리
프로세스 통신pyzmq>=25.1.2, uvloop, orjson python/sglang/srt/entrypoints/engine.py — IPC·비동기 대기·직렬화
계산 가속flashinfer_python[cu13]==0.7.2, sglang-kernel==0.4.10, tilelang==0.1.12 python/pyproject.toml — 모델 코드와 장치별 연산 구현의 분리
구조화 생성xgrammar==0.2.7, outlines==0.1.11, llguidance>=1.7.6,<2.0.0 python/sglang/srt/constrained/ — 출력 문법에 맞는 다음 토큰 후보 제한
클라이언트·계측openai==2.8.0, prometheus-client>=0.20.0 클라이언트 호환성과 서버 관측은 GPU 연산과 별도의 책임

확산 모델용 선택 의존성 diffusion에는 diffusers==0.37.0, cache-dit==1.5.1, imageio==2.36.0 등이 선언되어 있습니다. 선택 의존성을 나누면 언어 모델 서버와 영상 생성 서버에 필요한 패키지 범위를 구분할 수 있습니다.

3-2. 프론트엔드: 두 가지 뜻을 구별하자

논문의 “프론트엔드 언어”는 브라우저 화면을 뜻하지 않습니다. python/sglang/lang/api.py의 function()·gen()은 생성 프로그램을 표현하는 Python API입니다. python/sglang/lang/ir.py는 그 표현을 담고, python/sglang/lang/interpreter.py는 실행을 담당합니다.

실제 브라우저 UI도 있습니다. python/sglang/multimodal_gen/apps/realtime_webui/의 index.html·styles.css·app.js는 확산 모델의 실시간 영상 데모입니다. 별도 package.json이나 npm 빌드가 없는 정적 구성이고, new WebSocket(...)·Canvas·디코더 작업자를 사용합니다. React나 Vue 기반의 공통 관리 화면으로 설명하면 부정확합니다.

웹 UI README는 원시 RGB 프레임 렌더링을 설명하지만, app.js의 DEFAULT_PREVIEW_OUTPUT_FORMAT은 "webp"이며 HTML에도 WebP·JPEG·원시 RGB 선택지가 있습니다. 설명의 기본 사례와 현재 기본 설정이 다를 수 있음을 보여 주는 작은 예입니다.

3-3. Rust·Go: 서버와 SDK의 별도 경계

부품선언값역할
rust/edition 2024, pyo3 0.29.0, tonic 0.14Python 확장·API 타입·gRPC·대체 서버. 해당 Cargo workspace에서 버전을 공유
sgl-router/edition 2021, axum 0.8, tokio 1.42, tonic 0.14.6SGLang 워커 앞의 라우팅과 KV 상태 활용. 의존성은 Cargo 버전 요구식
sgl-model-gateway/버전 0.3.2, axum 0.8.6, tokio 1.42.0별도 Rust workspace인 게이트웨이. 단일 엔진 내부의 배치 스케줄러와 구분
Go 바인딩go 1.24.0, toolchain go1.24.10, gRPC v1.77.0sgl-model-gateway/bindings/golang/go.mod — 서버 본체 언어가 아니라 SDK 영역

Python의 ==와 Cargo의 version = "0.8.6"는 같은 의미가 아닙니다. 후자는 보통 호환 가능한 버전 범위를 허용합니다. 버전 문자열을 읽을 때는 숫자뿐 아니라 고정·하한·호환 범위를 나타내는 연산자까지 함께 봐야 합니다.

3-4. 인프라·빌드: 플랫폼별 재현성을 다룬다

선언값을 읽을 때 주의
Dockerfile의 커널 기본값과 Python 의존성이 다르다

docker/Dockerfile은 SGL_KERNEL_VERSION=0.4.9를 기본 빌드 인자로 두고, 설치 단계에서 그 값을 사용합니다. 반면 python/pyproject.toml과 AOT 패키지 선언은 0.4.10입니다. 빌드 인자 재정의나 후속 설치에 따라 결과가 달라질 수 있으므로, 최종 이미지가 반드시 어느 버전이라고 이 두 줄만으로 단정해서는 안 됩니다.

4아키텍처 심화 분석

요청 하나를 추적하며 배우는 네 가지 설계 패턴

4-1. 전체 구조: 기본 Python HTTP 경로

sglang serve의 LLM 경로는 python/sglang/cli/serve.py의 _run_llm()에서 python/sglang/launch_server.py의 run_server()로 이어집니다. 기본 HTTP 실행은 python/sglang/srt/entrypoints/http_server.py의 launch_server()가 담당합니다. 아래는 단일 엔진의 기본 Python 경로를 단순화한 구조입니다.

클라이언트 / OpenAI 호환 SDK | | HTTP 요청 / SSE 응답 v +-----------------------------------------------------+ | 주 프로세스 | | FastAPI: /generate, /v1/chat/completions | | | 요청 검증·형식 변환 | | v | | TokenizerManager: 문자열 --> 토큰 ID, 요청 상태 관리 | +------------+------------------------------^---------+ | ZMQ IPC | ZMQ IPC v | +------------------------------+ +------------------+ | Scheduler 프로세스 | | Detokenizer | | 대기열 --> 정책 --> 실행 배치 | | 프로세스 | | ^ | | | 토큰 ID --> 문자열| | | v | +--------^---------+ | 접두어 캐시 모델 워커 | | | KV 메모리 풀 | | 생성 토큰 | | v +------------+ | ModelRunner | | | | | 모델·가속 커널 | +-------------------+---------+ v GPU 선택 확장: 라우터 --> 여러 엔진 / TP·PP / prefill·decode 분리

기본 구성에서는 HTTP 서버와 TokenizerManager가 주 프로세스에 있고, 스케줄러와 디토크나이저가 별도 프로세스입니다. Engine._launch_subprocesses()가 이 구성을 준비합니다. 다중 토크나이저·분산 병렬·Rust 서버 옵션에서는 프로세스 구성이 달라지므로 이 그림을 모든 실행 모드에 그대로 적용하면 안 됩니다.

특히 python/sglang/srt/environ.py의 SGLANG_RUST_SERVER 기본값은 False입니다. 켜면 launch_server()가 Python HTTP 경로 대신 Rust의 API·토크나이저·디토크나이저 경로를 사용합니다. Rust 디렉토리가 있다는 사실과 기본 서버가 Rust라는 주장은 구별해야 합니다.

4-2. 패턴 ① 파이프라인과 책임 분리

python/sglang/srt/entrypoints/http_server.py의 generate_request()는 요청 계약을 검사한 뒤 serve_generate_request()로 넘깁니다. 스트리밍 요청에서는 TokenizerManager.generate_request()의 결과를 비동기 반복으로 받아 data: ...\n\n 형태의 SSE 조각으로 보냅니다. HTTP 함수가 GPU 연산을 직접 구현하지 않습니다.

# python/sglang/srt/entrypoints/http_server.py
# serve_generate_request()의 스트리밍 핵심 부분을 발췌
async for out in _global_state.tokenizer_manager.generate_request(
    obj, request
):
    yield b"data: " + dumps_json(out) + b"\n\n"

python/sglang/srt/managers/tokenizer_manager.py의 같은 이름 함수는 배치 인자를 정규화하고, 요청 ID별 상태를 만들고, _tokenize_one_request()·_send_one_request()·_wait_one_response()를 연결합니다. 처리 중 실패하면 _release_req_states_on_failure()로 아직 전달하지 않은 상태를 지우거나 전달된 요청의 중단을 요청합니다.

이 정리는 성능 최적화만큼 중요합니다. HTTP 연결이 끊겼는데 요청 상태나 GPU 메모리 참조가 계속 남으면 서버는 오래 버티지 못합니다. “정상 응답을 만드는 코드”와 “중간에 실패했을 때 자원을 돌려주는 코드”를 함께 읽는 습관을 배울 수 있습니다.

용어 풀이
비동기 대기와 프로세스 분리
await는 결과를 기다리는 동안 이벤트 루프가 다른 일을 처리할 기회를 줍니다. 별도 프로세스는 실행 공간 자체를 나눕니다. SGLang은 두 방법을 함께 사용합니다. async를 붙인다고 GPU 계산이 자동으로 빨라지거나 CPU 작업이 자동으로 병렬화되는 것은 아닙니다.

4-3. 패턴 ② 접두어 트리와 자원 수명 관리

먼저 원리를 읽기 좋은 python/sglang/srt/mem_cache/radix_cache.py를 봅시다. RadixKey는 토큰열과 추가 구분 정보를 담습니다. RadixCache.match_prefix()는 가장 길게 일치하는 접두어를 찾고, insert()는 토큰열에 대응하는 KV 슬롯 정보를 트리에 넣습니다.

입력 A: [11, 23, 35, 47] 입력 B: [11, 23, 35, 59] 입력 C: [11, 23, 80] 공통 구간을 압축한 트리 (개념 예시, page_size=1) root `-- [11, 23] --> 공통 KV 슬롯의 위치 |-- [35] | |-- [47] A의 뒷부분 | `-- [59] B의 뒷부분 `-- [80] C의 뒷부분 트리의 키: 토큰 ID 구간 트리의 값: KV 메모리 풀의 슬롯 인덱스 실제 K·V 텐서: 별도의 장치 메모리 풀

압축된 한 노드의 중간에서 일치가 끝나면 _match_prefix_helper()가 _split_node()로 경계를 만듭니다. 문자열 한 글자마다 노드를 만드는 단순 트라이보다 긴 토큰 구간을 한 노드로 묶을 수 있습니다. 실제 키는 페이지 크기에 맞춰 정렬되므로 재사용 길이가 입력 길이와 항상 같지는 않습니다.

사용 중인 KV를 지우면 다음 생성 계산이 잘못된 메모리를 읽습니다. 그래서 inc_lock_ref()·dec_lock_ref()는 경로의 참조 수를 갱신하고, evict()는 퇴거 가능한 잎에서 정책 우선순위에 따라 슬롯을 반환합니다. 여기의 lock_ref는 “누군가 쓰는 캐시를 보호하는 참조 수”이며 일반적인 스레드 뮤텍스와는 역할이 다릅니다.

현재 구현과 연결
기본 캐시는 UnifiedRadixCache다

python/sglang/srt/mem_cache/registry.py의 default_radix_cache_factory()는 일반 경로에서 create_unified_radix_cache()를 호출합니다. 순수 슬라이딩 윈도·외부 캐시 등에는 별도 분기가 있습니다. 따라서 위의 RadixCache만 읽고 현재 기본 엔진의 구현을 모두 설명했다고 보면 안 됩니다.

python/sglang/srt/mem_cache/unified_radix_cache.py의 UnifiedRadixCache는 전체 어텐션·슬라이딩 윈도·Mamba 상태 등의 컴포넌트와 트리 코어를 조합합니다. match_prefix()는 세션 경로 또는 트리 조회로, insert()는 트리 코어의 단계별 작업과 메모리 관련 작업으로 이어집니다. 작은 구현에서 원리를 이해한 뒤 이 조합 계층으로 올라가는 순서가 좋습니다.

접두어가 같아도 무조건 공유하지는 않습니다. RadixKey.extra_key와 GenerateReqInput.cache_salt 같은 구분 정보가 있습니다. LoRA나 캐시 네임스페이스가 다른 요청을 섞지 않기 위한 경계입니다. 공통 지시문을 앞에 둔다는 최적화도 토큰열과 이 구분 조건이 맞아야 효과가 납니다.

4-4. 패턴 ③ 정책과 구현을 교체하는 전략·팩터리

python/sglang/srt/managers/schedule_policy.py의 SchedulePolicy.calc_priority()는 대기열 정렬을 맡습니다. 도착 순서인 fcfs, 접두어 일치 길이를 활용하는 lpm, 대기 중 증가한 prefill 처리 토큰 수와 미계산 입력 토큰 수를 고려하는 hrrn, 미계산 prefill이 짧은 순서인 shortest-prefill-first 등으로 분기합니다.

기본 정책은 fcfs입니다. 근거는 python/sglang/srt/arg_groups/fields/schedule.py의 schedule_policy = "fcfs" 선언입니다. 캐시를 가진 서버라는 이유로 접두어가 긴 요청을 항상 먼저 실행한다고 설명해서는 안 됩니다. 우선순위 옵션이나 모델별 해석 과정도 실제 동작에 영향을 줍니다.

캐시 구현 선택에도 같은 발상이 있습니다. register_radix_cache_backend()는 이름과 생성 함수를 등록하고, create_tree_cache()는 선택한 이름에 맞는 팩터리를 부릅니다. 이름이 없으면 기본 선택 체인을 사용하며, 잘못된 이름은 오류로 처리합니다.

# registry.py의 구조를 학습용으로 축약한 의사코드
if backend_name:
    factory = get_radix_cache_factory(backend_name)
    if factory is None:
        raise ValueError("등록되지 않은 캐시 구현")
    cache = factory(context)
else:
    cache = default_radix_cache_factory(context)

스케줄러가 원하는 일과 캐시가 그 일을 수행하는 방법을 분리하면, 호출부 전체를 바꾸지 않고 구현을 확장할 수 있습니다. 다만 같은 인터페이스라도 지원 기능이 다를 수 있어 create_tree_cache()에는 세션 캐시나 호스트 버퍼 모드의 호환성 검사도 들어 있습니다.

4-5. 패턴 ④ CPU 준비와 GPU 계산을 겹치는 실행 파이프라인

Scheduler.event_loop_normal()은 요청 수신, 다음 배치 선택, 실행, 결과 처리 순서로 읽으면 됩니다. event_loop_overlap()은 결과 대기열을 두고 현재 배치를 실행하면서 이전 배치 결과를 처리하는 구조입니다. CPU의 준비 시간과 GPU의 계산 시간이 직렬로 모두 더해지는 구간을 줄이려는 설계입니다.

순차 실행 루프의 개념 CPU: [배치 A 준비] [A 결과 처리][배치 B 준비] GPU: [A 계산] [B 계산] 겹침 루프의 개념 CPU: [배치 A 준비][배치 B 준비][A 결과 처리][다음 준비] GPU: [A 계산] [B 계산] ... 공유 버퍼와 이전 토큰 결과의 의존성 때문에 동기화는 여전히 필요

겹친다고 동기화를 없애지는 않습니다. _apply_war_barrier()는 다음 스케줄링의 공유 버퍼 쓰기가 이전 GPU 읽기를 앞지르지 않도록 이벤트 또는 스트림 대기를 적용합니다. 문법 제약 등으로 직전 결과가 필요하면 is_disable_overlap_for_batch()가 배치별 예외를 판단합니다.

모델 실행은 python/sglang/srt/model_executor/model_runner.py의 ModelRunner.forward()로 이어집니다. 여기에는 실행 경로, 프로파일링, 분산 모델 관련 처리가 모입니다. HTTP부터 모든 일을 한 함수에 넣지 않고 실행 계층으로 내려보내는 이유를 확인할 수 있습니다.

비유

프린터가 한 장을 인쇄하는 동안 컴퓨터가 다음 장을 준비하는 것과 비슷합니다. 하지만 첫 장의 결과를 읽어 다음 장의 내용을 정해야 한다면 기다려야 합니다. 겹침 실행의 어려움은 “동시에 한다”보다 어떤 데이터가 언제 준비되는지 지키는 것에 있습니다.

소스 추적을 마친 뒤 답해 볼 질문

  1. 요청이 대기 중인 상태와 GPU에서 실행 중인 상태는 어디서 구분되는가?
  2. 정렬 정책이 바뀌어도 같은 KV 메모리 풀을 사용할 수 있는 이유는 무엇인가?
  3. 클라이언트가 사라질 때 Python 상태와 KV 슬롯은 각각 누가 정리하는가?

5디렉토리 구조 해부

크기가 큰 저장소에서는 파일 수보다 책임의 경계를 먼저 찾는다
sglang/ |-- python/ | |-- pyproject.toml Python 패키지·의존성 | |-- setup.py Rust 확장 탐색·빌드 연결 | `-- sglang/ | |-- cli/ serve·generate 명령 분기 | |-- lang/ 생성 언어 API·중간 표현·해석기 | |-- srt/ 언어·시각 언어 모델 런타임 | | |-- entrypoints/ HTTP·엔진 진입점 | | |-- managers/ 요청·배치·토큰 변환 관리 | | |-- mem_cache/ KV 풀·접두어 캐시·전송 | | |-- model_executor/ 모델 실행·그래프 실행 계층 | | |-- models/ 모델 아키텍처 구현 | | |-- layers/ 어텐션·양자화·MoE 등의 층 | | `-- arg_groups/ 설정 필드·해석·검증 | |-- kernels/ 가속 연산과 AOT 커널 패키지 | `-- multimodal_gen/ 확산 모델 실행·파이프라인·데모 |-- rust/ API 타입·확장·서버 관련 crates |-- sgl-router/ 엔진 선택·KV 상태 기반 라우팅 |-- sgl-model-gateway/ 별도 게이트웨이와 언어별 바인딩 |-- proto/ gRPC 메시지·서비스 정의 |-- test/ 단위·통합·모델·장치별 검증 |-- benchmark/ 커널·서빙·분산 성능 실험 |-- examples/ API·엔진·모니터링 사용 사례 |-- docker/ CUDA·ROCm·NPU 등 실행 이미지 |-- scripts/ CI·릴리스·운영 보조 도구 |-- docs/ 공식 문서 사이트와 가이드 `-- .github/workflows/ 변경 범위별 CI·배포 워크플로

위 구조도의 폴더를 읽을 때 주목할 경계

서로 헷갈리는 위치구별하는 질문
lang/ · srt/생성 프로그램을 표현하는 API인가, 실제 요청을 실행하는 런타임인가?
models/ · layers/모델 전체의 연결 구조인가, 여러 모델이 쓸 수 있는 연산 부품인가?
mem_cache/ · kernels/무엇을 보관하고 언제 돌려줄지 결정하는가, 실제 장치 연산을 수행하는가?
엔진 · 라우터한 엔진 안에서 요청을 묶는가, 여러 엔진 중 어디로 보낼지 고르는가?
test/ · benchmark/동작이 맞는지 검증하는가, 어떤 조건에서 얼마나 빠른지 측정하는가?

파일 네 개로 시작하는 읽기 순서

  1. python/sglang/srt/entrypoints/http_server.py에서 generate_request()를 찾습니다. 전체 서버 파일을 처음부터 읽을 필요는 없습니다.
  2. python/sglang/srt/managers/tokenizer_manager.py에서 요청이 토큰화되고 전송되는 지점을 찾습니다.
  3. python/sglang/srt/managers/scheduler.py에서 event_loop_normal()과 다음 배치 선택만 먼저 읽습니다.
  4. python/sglang/srt/mem_cache/registry.py에서 캐시 선택을 확인한 뒤 python/sglang/srt/mem_cache/radix_cache.py와 python/sglang/srt/mem_cache/unified_radix_cache.py를 비교합니다.

커밋 기준 python/sglang/srt/managers/scheduler.py는 6,291줄, python/sglang/srt/managers/tokenizer_manager.py는 4,122줄입니다. 파일이 길다는 사실은 읽기를 포기할 이유보다 한 요청의 호출 경로를 좁혀야 할 이유에 가깝습니다. 함수별로 입력·출력·바꾸는 상태를 세 칸으로 기록해 보세요.

6학습 포인트 (기술별)

배운 문법이 어떤 시스템 문제를 해결하는지 연결하기
Python · 비동기 처리

결과를 기다리는 동안 다른 요청을 받는 법

TokenizerManager.generate_request()는 비동기 생성기입니다. 한 번에 최종 문자열만 반환하는 함수와 달리 결과 조각을 여러 번 내보낼 수 있습니다. HTTP 계층은 이 흐름을 SSE로 감쌉니다.

읽을 것: python/sglang/srt/managers/tokenizer_manager.py의 rid_to_state, _wait_one_response(), 실패 시 정리 경로.

작은 실습: 별도 Python 파일에서 지연 시간을 두고 세 단어를 내보내는 비동기 생성기를 만들어 보세요. 소비를 중간에 멈췄을 때 finally가 자원을 정리하는지도 관찰합니다.

자료구조 · 메모리 관리

트리의 값에 무엇을 저장할지 결정하는 법

RadixCache의 값은 답변이 아니라 KV 슬롯 인덱스입니다. 검색용 자료구조와 실제 텐서 저장소를 분리하면, 트리 구조를 바꾸는 일과 GPU 버퍼를 다루는 일을 구분할 수 있습니다.

읽을 것: python/sglang/srt/mem_cache/radix_cache.py의 _split_node()·inc_lock_ref()·evict(), test/registered/unit/mem_cache/test_radix_cache_unit.py의 페이지 정렬·참조·퇴거 사례.

작은 실습: 리스트를 슬롯 풀로 보고 “빌린 번호 집합”과 “사용 가능한 번호 집합”을 관리해 보세요. 사용 중인 번호를 퇴거하려 하면 거부하도록 만듭니다.

스케줄링 · 공정성

짧은 일 우선과 오래 기다린 일 보호를 함께 생각하기

입력 1,000토큰 중 900토큰이 캐시에 있다면 새로 계산할 부분은 대략 100토큰입니다. 입력 길이만 보고 정렬하면 이 차이를 놓칩니다. 하지만 짧은 일만 먼저 처리하면 긴 일이 계속 밀릴 수 있습니다.

읽을 것: python/sglang/srt/managers/schedule_policy.py의 _sort_by_hrrn()·_sort_by_shortest_prefill(), test/registered/unit/managers/test_schedule_policy.py의 대기량 증가 사례.

작은 실습: 도착 시점·미계산 토큰 수가 다른 요청 다섯 개를 표로 만들고 FCFS·짧은 작업 우선·대기 보정 정책의 순서를 손으로 계산합니다.

테스트를 읽는 요령
경계 조건이 곧 설계의 설명서다
구현은 가능한 모든 경우를 처리하느라 복잡하지만, 테스트는 “이 입력이면 이 결과여야 한다”를 보여 줍니다. 접두어 0개·완전 일치·노드 중간 일치·사용 중인 캐시 퇴거 같은 작은 사례를 먼저 읽으면, 어떤 불변조건을 지키려는 코드인지 보입니다.
PyTorch · 가속 커널

높은 수준의 텐서 연산과 장치 실행을 분리하기

ModelRunner.forward()가 받는 것은 HTTP JSON이 아니라 실행에 필요한 배치 표현입니다. 이후 모델·어텐션 백엔드·커널로 내려갑니다. 텐서의 shape, dtype, device가 다음 연산이 요구하는 조건과 맞는지 확인해야 합니다.

읽을 것: python/sglang/srt/model_executor/forward_batch_info.py, python/sglang/srt/model_executor/model_runner.py, python/sglang/kernels/. 처음에는 CUDA 구현 전체보다 함수 입력 텐서의 모양부터 기록합니다.

작은 실습: 길이가 다른 세 입력을 고정 길이로 패딩할 때 낭비되는 토큰 수와, 실제 토큰만 모았을 때의 수를 계산해 보세요. 커널을 작성하기 전에도 배치 설계의 효과를 이해할 수 있습니다.

Rust · 빌드와 인터페이스

언어가 달라도 경계는 명시적으로 유지하기

rust/Cargo.toml의 workspace는 공통 의존성을 공유하고, python/setup.py는 확장 모듈 메타데이터를 탐색합니다. proto/와 API 타입 crate는 통신하는 양쪽이 메시지 구조를 공유하는 지점입니다.

작은 실습: Rust 문법을 모두 배우기 전에 Python 모듈 이름·Cargo 패키지 이름·공개 API 타입을 연결한 표를 만들어 보세요. 라우터의 비동기 작업과 GPU 커널 실행을 같은 종류의 병렬성으로 오해하지 않는 것이 첫 목표입니다.

이 저장소에서 배울 가장 실용적인 습관은, 함수가 무엇을 계산하는지와 함께 어떤 상태를 소유하고 언제 반환하는지를 묻는 것입니다. 이 질문은 추론 서버뿐 아니라 DB 연결 풀, 작업 대기열, 이미지 처리 서버에도 그대로 적용됩니다.

7하드웨어 / 시스템 요구사항

“실행 가능”을 가중치 적재·문맥 길이·동시성으로 나눠 계산한다

7-1. 읽기와 GPU 실험의 요구사항은 다르다

목표환경을 잡는 기준주의할 점
소스·기초 과제일반 PC, 텍스트 편집기, 작은 예제용 PythonGPU 없이 요청 흐름·접두어·스케줄링 원리 학습 가능
작은 LLM 서버Linux + 지원 GPU, 짧은 문맥·낮은 동시성부터 시작0.6B 모델의 BF16 가중치는 계산상 약 1.2GB지만 전체 사용량은 더 큼
7B~8B급 탐색24GiB급 GPU를 검토하더라도 가중치·KV·버퍼 합을 먼저 계산긴 문맥·동시 요청·추가 모델은 여유 메모리를 빠르게 소모
다중 GPU 실험동일 계열 GPU, 지원 통신 경로, 충분한 호스트 메모리TP·PP 크기와 장치 간 대역폭이 지연 시간에 영향
다중 노드·P/D고속 네트워크와 선택한 KV 전송 백엔드의 요구사항 확인GPU가 빨라도 KV 전송이나 통신에서 병목 가능

위 표는 모든 모델의 공식 최소 사양표가 아닙니다. 필요 용량은 모델 구조·정밀도·문맥·동시성·백엔드에 따라 달라집니다. CPU RAM과 디스크에도 모델 다운로드·로딩·캐시용 공간이 필요합니다. GPU 메모리에 딱 맞는 크기만 보고 호스트 자원을 결정하지 마세요.

7-2. 메모리 계산을 직접 해 보자

# 가중치의 단순 근사: 양자화 메타데이터·작업 버퍼는 제외
가중치 메모리 ≈ 파라미터 수 × 파라미터당 바이트
8B × BF16 2바이트 = 16,000,000,000바이트 ≈ 14.9GiB

# 일반적인 디코더 어텐션의 KV 캐시 근사
KV 바이트 ≈ 2 × 층 수 × KV 헤드 수 × 헤드 차원
             × 보관 토큰 수 × 원소당 바이트

# 층 32, KV 헤드 8, 헤드 차원 128, BF16 예시
2 × 32 × 8 × 128 × 8192 × 2 = 1GiB / 요청
같은 조건의 독립 요청 8개 ≈ 8GiB

총 GPU 사용량 ≈ 가중치 + KV 풀 + 활성값 + 그래프·작업 버퍼

이 KV 식은 모든 모델에 통하는 식이 아닙니다. GQA의 KV 헤드 수, 슬라이딩 윈도, MLA의 압축 상태, Mamba의 상태 구조가 다릅니다. 공유 접두어가 있으면 중복을 줄일 수 있지만, 최악의 예산은 공유되지 않는 입력도 고려해야 합니다.

모델 가중치가 GPU에 들어간다는 사실만으로, 원하는 문맥 길이와 동시 요청 수까지 감당할 수 있다는 결론은 나오지 않습니다. 캐시를 크게 잡으면 더 많은 토큰을 보관할 수 있지만, 실행 중 임시 텐서가 쓸 공간도 남겨야 합니다.

7-3. 설정의 기본값도 장치에 따라 해석된다

python/sglang/srt/arg_groups/fields/schedule.py에서 mem_fraction_static과 chunked_prefill_size는 둘 다 None으로 시작합니다. python/sglang/srt/arg_groups/memory_hook.py의 handle_gpu_memory_settings()가 장치 메모리와 다른 설정을 보고 값을 정합니다.

GPU 메모리 구간chunked prefill 크기
20GiB 미만사용자 지정이 없으면 2,048토큰
20~35GiB사용자 지정이 없으면 4,096토큰
60~90GiB사용자 지정이 없으면 8,192토큰

구간은 하한을 포함하고 상한은 포함하지 않으며, 해당 함수의 일부 분기를 GiB로 표현했습니다. 모델·플랫폼별 후속 조정과 명시적 옵션이 있으므로 전체 실행의 고정값으로 외우지 마세요. mem_fraction_static은 가중치와 KV 풀에 쓰는 정적 메모리의 비율이며, KV 캐시만의 비율이 아닙니다.

7-4. 플랫폼 지원은 동일한 설치법을 뜻하지 않는다

README는 NVIDIA·AMD·Intel GPU/CPU·Ascend·Apple Silicon 등을 설명합니다. 실제 저장소에도 docker/rocm.Dockerfile·docker/xpu.Dockerfile·docker/npu.Dockerfile·docker/xeon.Dockerfile과 장치별 백엔드가 있습니다. 그러나 모델·연산·옵션의 지원 범위까지 모두 같다고 볼 수는 없습니다.

TPU는 README에서 SGLang-TorchTPU와 SGL-JAX라는 별도 프로젝트 경로도 안내합니다. NVIDIA용 python/pyproject.toml의 CUDA 의존성을 모든 플랫폼에 그대로 적용하지 말고, 공식 플랫폼 가이드와 모델별 실행 예제를 함께 확인해야 합니다. 기본 Dockerfile의 CUDA 13.0.3도 모든 하드웨어의 공통 최소 버전은 아닙니다.

8직접 해볼 수 있는 실습 과제

GPU 없는 입문 과제에서 측정과 공정성 설계까지 다섯 단계
과제 1 · 입문 · GPU 불필요

요청 하나의 여행 지도를 완성하기 30~60분

목표: /generate의 JSON이 모델 실행까지 도달하는 경로를 이해합니다.

  1. GenerateReqInput에서 text·sampling_params·stream의 타입을 적습니다.
  2. generate_request() → 토큰화 → 스케줄러 → run_batch() → 디토크나이저를 화살표로 연결합니다.
  3. 화살표마다 전달 데이터가 문자열·토큰 ID·배치·텐서 중 무엇인지 표시합니다.
  4. 검증 실패, 대기 중 취소, 생성 중 취소가 일어났을 때 되돌려야 할 상태를 각각 적습니다.

완료 기준: HTTP 서버가 모델의 모든 토큰을 직접 계산하지 않는 이유와 요청 ID가 필요한 이유를 자신의 말로 설명할 수 있습니다.

과제 2 · 입문 · GPU 불필요

접두어 재사용의 이득을 숫자로 보기 1시간

목표: 토큰열의 공통 앞부분과 중간 부분의 일치가 다른 문제임을 이해합니다. 아래는 SGLang 구현을 대체하는 코드가 아니라 원리만 보여 주는 독립 예제입니다.

def prefix_length(a, b):
    n = 0
    while n < min(len(a), len(b)) and a[n] == b[n]:
        n += 1
    return n

previous = [10, 20, 30, 40]
request = [10, 20, 30, 99, 88]
matched = prefix_length(previous, request)
uncached = len(request) - matched

assert matched == 3
assert uncached == 2
assert prefix_length([1, 2], [0, 1, 2]) == 0

확장: 요청 다섯 개를 만들고, 앞서 계산한 모든 요청 중 최대 접두어 길이를 찾으세요. 단순 선형 탐색을 접두어 트리로 바꿀 때 필요한 노드 정보를 적습니다. 토큰을 문자열 글자 수로 바꿔 계산하면 어떤 오차가 생기는지도 생각해 봅니다.

완료 기준: 공통 접두어가 늘면 새 prefill 작업은 줄어들 수 있지만, 새 출력 토큰 계산까지 전부 사라지지는 않는다고 설명할 수 있습니다.

과제 3 · 중급 · 지원 GPU 필요

작은 모델에 일반 응답과 스트리밍 요청 보내기 1~2시간

전제: Linux·NVIDIA 환경에 호환되는 SGLang과 드라이버가 준비되어 있고, 작은 모델과 실행 버퍼를 담을 GPU 여유가 있어야 합니다. 모델은 Hugging Face에서 내려받으므로 네트워크와 디스크 공간도 필요합니다. 아래는 단일 GPU·TP 1·단일 노드 예제이며, 다른 플랫폼은 전용 가이드를 따릅니다.

# 전용 실습 환경의 첫 터미널
sglang serve \
  --model-path Qwen/Qwen3-0.6B \
  --host 127.0.0.1 --port 30000 \
  --context-length 4096 \
  --max-running-requests 1 \
  --enable-metrics
# 서버가 준비된 뒤 두 번째 터미널
curl -sS http://127.0.0.1:30000/generate \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "배치 처리를 한 문장으로 설명해 줘.",
    "sampling_params": {"temperature": 0, "max_new_tokens": 64},
    "stream": false
  }'

그다음 stream을 true로 바꾸고 curl -N으로 다시 요청합니다. 출력 조각이 응답 전체인지 차이만 담은 값인지도 관찰하세요. 네이티브 API의 스트림을 곧바로 OpenAI 응답 조각과 같은 모양이라고 가정하지 않습니다.

완료 기준: JSON 응답의 text와 meta_info를 구분하고, SSE가 여러 요청을 보내는 방식이 아니라 한 응답을 이어 받는 방식임을 설명할 수 있습니다.

과제 4 · 중급 · 지원 GPU 필요

접두어 캐시의 효과를 조건별로 비교하기 반나절

목표: “두 번째가 빨랐다”를 설명 가능한 실험으로 바꿉니다. 긴 공통 지시문 뒤에 짧은 질문을 붙이고, 총 입력이 서버의 문맥 한도 안에 들도록 합니다.

실험군바꾸는 조건관찰
A캐시가 비어 있는 상태의 첫 요청초기화·워밍업과 prefill을 구분
B같은 접두어, 다른 질문meta_info.cached_tokens와 첫 출력 지연
C접두어 앞에 매번 다른 날짜·ID 추가앞부분 변경이 일치 길이에 미치는 영향
D--disable-radix-cache를 준 별도 서버 실행캐시 비활성 조건에서 같은 부하 비교

모델·정밀도·입력과 출력 토큰 수·동시성·워밍업 횟수를 고정하고 여러 번 반복합니다. 첫 출력 지연을 재려면 스트리밍의 첫 실제 출력 조각을 기록하고, 전체 응답 시간과 구분하세요. 페이지 정렬과 마지막 토큰 처리 때문에 캐시 토큰 수가 공통 입력 길이와 정확히 같지 않을 수 있습니다.

완료 기준: 중앙값·느린 꼬리 지연·캐시 토큰 수를 함께 적고, 입력 재사용 효과와 출력 생성 속도 변화를 구분한 비교표를 만듭니다.

과제 5 · 고급 · 시뮬레이션부터 시작

처리량과 공정성이 충돌하는 대기열 만들기 1~2일

목표: 긴 요청 하나와 계속 도착하는 짧은 요청을 넣고 FCFS·짧은 작업 우선·대기 보정 정책을 비교합니다. 처음에는 GPU 없이 한 토큰을 한 작업 단위로 계산하는 시뮬레이터면 충분합니다.

  1. 요청마다 도착 시점·입력 토큰·캐시 일치 토큰·출력 토큰을 정의합니다.
  2. 시간이 지날 때 새 요청을 넣고, 선택한 정책으로 다음 작업을 정합니다.
  3. 완료한 요청 수뿐 아니라 가장 오래 기다린 요청의 대기 시간을 기록합니다.
  4. test/registered/unit/managers/test_schedule_policy.py의 오래 기다린 긴 요청이 앞서는 사례와 비교합니다.

완료 기준: 단순 모형의 가정과 실제 엔진의 차이까지 적습니다. GPU의 배치 효율·통신·메모리 제약이 빠진 모형으로 실제 처리량을 예측했다고 주장하지 않습니다.

성능 실습의 결과물은 가장 빠른 숫자 하나가 아니라, 어떤 조건을 바꾸었을 때 무엇이 달라졌는지 설명하는 기록입니다. GPU가 없다면 과제 1·2·5만으로도 파이프라인·접두어 자료구조·공정성이라는 핵심 주제를 공부할 수 있습니다.

9관련 기술 심화 학습 로드맵

6주 동안 Python 요청 처리에서 추론 시스템 설계로 이동하기

하루 45~60분 정도를 기준으로 한 읽기 중심 경로입니다. 모델 수학과 GPU 커널을 한 번에 끝내려 하지 말고, 각 주마다 설명 가능한 작은 산출물을 남깁니다. 이미 익숙한 주제는 건너뛰어도 되지만 마지막에는 요청 전체를 다시 연결해 보세요.

주차배울 내용과 소스손에 남길 결과물
1주차HTTP·JSON·타입·생성기. python/sglang/srt/managers/io_struct.py와 python/sglang/srt/entrypoints/http_server.py 일반 응답과 SSE의 차이, 요청 필드 설명표, 과제 1
2주차asyncio·프로세스·IPC. TokenizerManager와 Engine._launch_subprocesses() 프로세스별 책임도, 정상·취소·검증 실패 시퀀스 세 개
3주차토큰화·prefill·decode·KV. python/sglang/srt/mem_cache/radix_cache.py에서 시작해 캐시 팩터리로 이동 접두어 기초 구현, 참조 수와 퇴거의 불변조건 목록
4주차연속 배칭·정책·공정성. event_loop_normal()과 SchedulePolicy 과제 5의 대기열 비교표, 처리량과 지연 시간의 상충 설명
5주차PyTorch 텐서·dtype·메모리·CUDA Graph. ForwardBatch와 ModelRunner 작은 모델의 메모리 예산표. GPU가 있으면 과제 3·4의 관찰 기록
6주차Rust 경계·gRPC·다중 엔진·관측. rust/·sgl-router/·모니터링 예제 단일 엔진을 여러 대로 확장할 때 바뀌는 상태·통신·장애 경계 정리

학습의 종료 기준은 파일을 많이 읽는 것이 아니라, 요청 하나의 상태와 메모리가 어디로 이동하는지 설명할 수 있는 것입니다. 그 뒤에는 관심에 따라 캐시 알고리즘, 장치 커널, 분산 라우팅 중 한 갈래를 선택하면 됩니다.

다음 단계
작은 구현으로 돌아가 설명을 검증하자

전체 런타임이 너무 크다면 README가 소개하는 Mini-SGLang을 보조 교재로 삼을 수 있습니다. 작은 구현에서 배치·캐시의 뼈대를 익힌 뒤, 이 저장소에 추가된 취소·장치 차이·세션·전송·오류 처리가 각각 어떤 현실 문제를 다루는지 비교하세요.

10핵심 키워드 사전

소스에서 만나는 말을 일상적인 문장으로 번역하기
용어쉬운 설명
토큰 / 토큰 ID모델이 읽고 쓰는 조각과 그 번호입니다. 한 글자·한 단어와 항상 같지는 않습니다.
토크나이저문자열을 토큰 ID로 바꾸고 그 반대 변환도 제공하는 도구입니다. 채팅 템플릿도 실제 입력 토큰에 영향을 줍니다.
추론 서빙모델 계산을 여러 사용자가 요청할 수 있는 API 서비스로 운영하는 일입니다.
prefill입력 토큰들을 읽어 다음 생성에 쓸 상태를 준비하는 단계입니다. 긴 입력의 비용과 관련이 큽니다.
decode앞에서 만든 상태를 이용해 출력 토큰을 이어 생성하는 단계입니다. 기본적인 자기회귀 생성은 순서 의존성이 있습니다.
KV 캐시어텐션에서 이미 계산한 Key·Value를 보관하는 저장소입니다. 답변 문자열을 저장하는 응답 캐시와 다릅니다.
Radix tree공통 접두어를 공유하고 연속 구간을 압축해 저장하는 트리입니다. 여기서는 토큰열에 대응하는 캐시 위치를 찾습니다.
RadixAttention접두어 공유를 활용해 요청 사이의 KV 재사용을 관리하는 SGLang의 대표 설계입니다. 단순히 어텐션 수식 하나의 이름으로만 이해하면 부족합니다.
페이지·슬롯KV 메모리 풀을 나누어 관리하는 단위입니다. 논리적인 토큰 위치와 실제 저장 위치를 연결해야 합니다.
참조 수 / lock_ref캐시를 누가 사용 중인지 세는 값입니다. 사용 중인 데이터를 퇴거 대상에서 보호하는 데 쓰입니다.
퇴거 / LRU공간이 부족할 때 캐시를 내보내는 일과, 최근 사용에서 가장 멀어진 후보를 우선하는 정책입니다. 사용 중인 캐시는 별도로 보호합니다.
연속 배칭생성 과정에서 완료 요청을 빼고 새 요청을 받아 GPU 실행 묶음을 갱신하는 방식입니다.
chunked prefill긴 입력의 prefill을 여러 조각으로 나누는 방식입니다. 긴 작업과 다른 요청 사이의 시간 배분에 영향을 줍니다.
FCFS / LPM각각 도착 순서 우선과 긴 접두어 일치 활용 정책입니다. 기본 스케줄링 선언은 FCFS입니다.
HRRN기다린 양과 남은 작업량을 함께 고려하는 정책입니다. 이 구현에서는 누적 prefill 처리 토큰 수의 증가량과 미계산 입력 토큰 수를 활용합니다.
TTFT요청부터 첫 출력 토큰까지 걸리는 시간입니다. 대기열·prefill·통신의 영향을 함께 받을 수 있습니다.
ITL / 처리량각각 출력 토큰 사이 간격과 단위 시간에 처리한 양입니다. 첫 응답이 빠른 것과 전체 처리량이 큰 것은 다른 목표입니다.
SSE한 HTTP 응답을 열어 둔 채 서버가 이벤트 조각을 이어 보내는 방식입니다. 양방향 WebSocket과 구분합니다.
ZMQ IPC이 엔진의 프로세스들이 요청·결과 메시지를 주고받는 통로입니다. GPU 간 집단 통신과는 다른 층입니다.
TP / PP각각 모델 텐서 계산을 여러 장치로 나누는 병렬화와, 모델의 층 단계를 장치별로 나누는 병렬화입니다.
DP / EP각각 요청·데이터를 복제된 실행 자원에 나누는 방식과, MoE의 전문가들을 장치에 나누는 방식입니다. 모델에 따라 조합이 달라집니다.
P/D 분리입력을 읽는 prefill과 출력을 이어 쓰는 decode를 다른 실행 자원에 맡기는 구성입니다. 중간 KV 전송이 필요합니다.
양자화가중치·연산 등에 더 적은 비트를 쓰는 방식입니다. 메모리 절감과 정확도·커널 지원을 함께 검토해야 합니다.
CUDA Graph반복되는 GPU 실행 작업을 미리 기록해 재실행하는 기능입니다. 준비 비용과 추가 메모리, 지원 형태의 제약이 있습니다.
투기적 디코딩보조 방식이 미리 제안한 토큰을 주 모델이 검증하는 생성 가속 기법입니다. 수락률과 추가 자원에 따라 이득이 달라집니다.
구조화 출력JSON Schema·문법 등에 맞게 생성 후보를 제한하는 기능입니다. 형식이 맞는 것과 답의 사실성이 맞는 것은 별개입니다.
LoRA / MoE각각 작은 추가 파라미터로 모델을 조정하는 방법과, 여러 전문가 중 일부를 선택해 계산하는 모델 구조입니다.
PyO3 / gRPC각각 Rust와 Python을 연결하는 바인딩 도구와, 정해진 메시지 타입으로 원격 함수를 호출하는 통신 체계입니다.
관측 가능성로그·메트릭·트레이스로 대기·실행·실패 원인을 구별하는 능력입니다. 빠르다는 주장에 설명 가능한 근거를 붙입니다.

처음에는 모든 약어를 외울 필요가 없습니다. 입력 처리, 실행 순서, 저장 공간, 통신, 측정 중 어느 문제를 다루는 말인지 먼저 분류하면 소스를 읽을 때 길을 잃지 않습니다.

11참고 링크

현재 문서와 커밋에 고정된 소스를 구분해 이어 읽기

프로젝트 공식 자료

본문과 연결되는 소스 — 커밋 611a703 기준

관련 기술의 공식 자료

현재 상태 (2026-10-23 확인)

항목내용
저장소 · 선정sgl-project/sglang · GitHub Trending Python Weekly #9
스타 / 포크37,655 / 9,819 — 2026-10-23 GitHub 기준
주 언어 · 생성일Python · 2024-01-08
최신 릴리스v0.5.22 · 2026-10-19
최근 push2026-10-23
최근 커밋611a703 · 2026-10-23 · [Chore] api: add fields to generate request (#45164) — 생성 요청 필드 추가
라이선스Apache-2.0 — 모델 가중치와 외부 의존성의 조건은 각각 별도 확인
추적 파일11,225개 항목 — 커밋 기준 Git 추적 경로 수
Python8,018파일 · 2,622,416줄
Rust642파일 · 302,159줄
CUDA.cu + .cuh 318파일 · 126,933줄
C / C++.c·.cc·.cpp·.h·.hpp 150파일 · 52,415줄
그 외 코드Shell 13,547줄 · Go 7,598줄 · JavaScript 5,555줄 · CSS 1,905줄 · HTML 295줄

집계 기준: 커밋 611a703의 Git 추적 파일을 확장자별로 묶은 물리적 줄 수입니다. 빈 줄·주석·테스트·생성 코드·해당 확장자의 서드파티 코드를 포함하고, 심볼릭 링크는 제외했습니다. JavaScript는 .js·.mjs·.cjs, Shell은 .sh를 집계했습니다. 다운로드되는 모델 가중치나 외부 패키지의 소스는 포함하지 않습니다. 따라서 사람이 작성한 구현 코드만의 크기나 언어별 작업량 비율로 해석하면 안 됩니다.

읽기 범위를 잡는 참고로, python/sglang/srt/의 Python·Rust·C/C++·CUDA·Go·JavaScript 해당 확장자 합계는 약 92만 줄이고 test/는 약 72만 줄입니다. 전체 크기를 목표로 삼기보다 4절의 요청 경로와 작은 테스트부터 읽는 편이 현실적입니다.

사용 전에 알아둘 한계
버전·하드웨어·성능·운영 경계를 함께 확인하자

① 릴리스와 개발 HEAD는 다릅니다. 최신 릴리스 표기는 v0.5.22이고 소스 설명은 2026-10-23의 611a703 기준입니다. 설치한 릴리스에 모든 함수·기본값·의존성이 똑같이 있다고 가정하면 안 됩니다. 공식 문서의 최신 페이지도 이후에 바뀔 수 있습니다.

② 모든 장치·모델·옵션 조합이 같은 수준으로 지원되지는 않습니다. 플랫폼 목록은 모델별 검증표가 아닙니다. 기본 Dockerfile과 Python 의존성의 커널 버전 차이도 있으므로 실제 배포 구성의 버전을 확인해야 합니다.

③ 빠른 속도는 조건이 붙는 결과입니다. 접두어 반복률·배치 크기·정밀도·입출력 길이·장치·워밍업에 따라 결과가 달라집니다. 캐시는 주로 반복 입력 처리의 비용을 줄이며, 새 출력 전체를 미리 계산해 주지는 않습니다.

④ 엔진 설치가 운영 구성을 완성하지는 않습니다. 외부 공개 서비스에는 인증·접근 제어·동시성 제한·타임아웃·로그 관리가 필요합니다. 특히 trust_remote_code처럼 모델 저장소의 코드를 허용하는 선택은 실행할 코드를 검토한 뒤 적용해야 합니다. 실습의 루프백 주소를 그대로 유지한 채 요청 흐름부터 익히세요.