LLM

vLLM vs SGLang — 프로덕션 LLM 서빙 프레임워크 어떻게 골라야 하나

cell-devlog 2026. 6. 15. 16:32
반응형

 


모델을 골랐으면 다음 결정이 서빙 엔진입니다. vLLM과 SGLang은 둘 다 OpenAI 호환 엔드포인트를 제공하고, 둘 다 PagedAttention 계열 메모리 관리를 씁니다. 그런데 특정 워크로드에서는 성능 차이가 6배까지 납니다. 어떤 걸 써야 하는지는 모델 크기가 아니라 워크로드 형태가 결정합니다.


핵심 차이 — PagedAttention vs RadixAttention

두 엔진의 근본적 차이는 KV 캐시를 어떻게 다루느냐입니다.

vLLM의 PagedAttention은 KV 캐시 메모리를 고정 크기 블록으로 관리하고 요청이 끝나면 해제합니다. SGLang의 RadixAttention은 KV 캐시를 LRU 래딕스 트리에 유지하고 새 요청이 이전 요청과 프리픽스를 공유하면 재사용합니다. PagedAttention이 더 단순하고, RadixAttention은 프리픽스 오버랩이 있을 때 더 빠릅니다.

실전에서 이게 의미하는 바를 구체적으로 보면 이렇습니다.

2,000 토큰짜리 툴 정의 시스템 프롬프트를 모든 요청에 넣는 코딩 에이전트를 예시로 들면, PagedAttention은 그 2,000 토큰을 매 요청마다 재연산합니다. RadixAttention은 처음 한 번만 연산하고 캐시합니다. RAG 파이프라인, 멀티턴 대화, 에이전트 워크플로우처럼 시스템 프롬프트나 컨텍스트가 반복되는 환경에서 차이가 극명합니다.


벤치마크 — 실제 수치

H100 기준, SGLang은 약 16,200 tok/s, vLLM은 약 12,500 tok/s로 SGLang이 29% 앞섭니다. 70B 이상 대형 모델에서는 차이가 3~5% 수준이지만, 8B 소형 모델에서는 격차가 더 벌어집니다. SGLang의 RadixAttention이 작은 모델에서 프리필이 전체 비용의 더 큰 부분을 차지할 때 효과가 크기 때문입니다.

테일 레이턴시(TTFT p95)도 SGLang이 모든 동시성 수준에서 5~8% 낮습니다.

프리픽스 헤비 워크로드에서는 격차가 극단적입니다. SGLang이 최대 6.4배 처리량 향상을 기록합니다. DeepSeek V3 기준으로는 SGLang이 vLLM 대비 3.1배 빠릅니다.


vLLM 빠른 시작

pip install vllm

# 기본 서빙
python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3.3-70B-Instruct \
  --tensor-parallel-size 4 \
  --max-model-len 32768 \
  --dtype bfloat16 \
  --port 8000

# FP8 양자화 + 프리픽스 캐싱 활성화 (H100/H200)
python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3.3-70B-Instruct \
  --tensor-parallel-size 4 \
  --quantization fp8 \
  --enable-prefix-caching \
  --max-model-len 65536 \
  --port 8000

OpenAI SDK로 호출:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="dummy"  # vLLM은 키 불필요
)

response = client.chat.completions.create(
    model="meta-llama/Llama-3.3-70B-Instruct",
    messages=[
        {"role": "system", "content": "당신은 시니어 소프트웨어 엔지니어입니다."},
        {"role": "user", "content": "Python asyncio 이벤트 루프를 설명해줘."}
    ],
    max_tokens=1024,
    stream=True
)

for chunk in response:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

SGLang 빠른 시작

pip install sglang[all]

# 기본 서빙
python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.3-70B-Instruct \
  --tp 4 \
  --dtype bfloat16 \
  --port 30000

# 에이전트 워크로드 최적화 설정
# (RadixAttention 기본 활성화, 프리픽스 캐싱 자동)
python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.3-70B-Instruct \
  --tp 4 \
  --dtype bfloat16 \
  --mem-fraction-static 0.85 \
  --max-prefill-tokens 16384 \
  --chunked-prefill-size 4096 \
  --port 30000

SGLang도 OpenAI 호환 엔드포인트를 제공합니다:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:30000/v1",
    api_key="dummy"
)

# 구조화된 출력 — SGLang의 강점
response = client.chat.completions.create(
    model="meta-llama/Llama-3.3-70B-Instruct",
    messages=[
        {"role": "user", "content": "다음 코드의 버그를 JSON으로 정리해줘: ..."}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "bug_report",
            "schema": {
                "type": "object",
                "properties": {
                    "bugs": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "line": {"type": "integer"},
                                "severity": {"type": "string", "enum": ["critical", "high", "medium", "low"]},
                                "description": {"type": "string"},
                                "fix": {"type": "string"}
                            }
                        }
                    },
                    "summary": {"type": "string"}
                }
            }
        }
    },
    max_tokens=2048
)

import json
result = json.loads(response.choices[0].message.content)
print(result)

구조화 출력에서 SGLang은 문법 마스크 생성을 GPU 인퍼런스와 오버랩해서 처리하기 때문에 guided decoding이 처리량에 거의 영향을 주지 않습니다. vLLM은 배치 크기 8 이상에서 guided decoding 활성화 시 눈에 띄는 성능 저하가 나타납니다.


프리필-디코드 분리(Disaggregated Prefill-Decode) — 고처리량 구성

대규모 트래픽에서 레이턴시와 처리량을 동시에 최적화하는 고급 패턴입니다.

프리필은 프롬프트를 처리하는 컴퓨트 바운드 단계이고, 디코드는 토큰을 생성하는 메모리 바운드 단계입니다. 이 둘을 분리하면 각각 독립적으로 스케일링할 수 있습니다.

vLLM 분리 서빙 설정:

# 프리필 노드
python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3.3-70B-Instruct \
  --tensor-parallel-size 4 \
  --port 8200 \
  --kv-transfer-config \
  '{"kv_connector":"PyNcclConnector","kv_role":"kv_producer","kv_rank":0,"kv_parallel_size":2}'

# 디코드 노드
python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3.3-70B-Instruct \
  --tensor-parallel-size 4 \
  --port 8201 \
  --kv-transfer-config \
  '{"kv_connector":"PyNcclConnector","kv_role":"kv_consumer","kv_rank":1,"kv_parallel_size":2}'

# 라우터 (프로덕션에서는 전용 로드밸런서 사용)
python vllm/tests/disagg_prefill/toy_proxy_server.py \
  --prefill http://PREFILL_IP:8200 \
  --decode http://DECODE_IP:8201 \
  --port 8000

SGLang 분리 서빙 설정:

# SGLang 분리 모드 (RadixAttention이 프리픽스 캐싱 자동 최적화)
python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.3-70B-Instruct \
  --tp 4 \
  --disaggregation-mode prefill \
  --port 30200

python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.3-70B-Instruct \
  --tp 4 \
  --disaggregation-mode decode \
  --port 30201

DeepSeek MoE 모델 서빙 — SGLang이 공식 권장

DeepSeek 모델은 SGLang이 공식 권장 프레임워크입니다. 멀티토큰 예측(디코드 1.8배 가속), 익스퍼트 병렬화 EPLB 로드 밸런싱, MoE 아키텍처에 최적화된 프리필-디코드 분리를 지원합니다. DeepSeek V3에서 vLLM 대비 3.1배 빠릅니다.

# DeepSeek V4 / MoE 모델 SGLang 서빙
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V4 \
  --tp 8 \
  --dp 2 \
  --enable-dp-attention \
  --moe-ep-size 4 \
  --dtype bfloat16 \
  --port 30000

Multi-LoRA 서빙 — 여러 어댑터를 하나의 서버로

# vLLM Multi-LoRA
from vllm import LLM, SamplingParams
from vllm.lora.request import LoRARequest

llm = LLM(
    model="meta-llama/Llama-3.3-8B-Instruct",
    enable_lora=True,
    max_lora_rank=64,
    max_loras=4  # 최대 동시 로드 LoRA 수
)

# 서로 다른 LoRA 어댑터로 동시 요청
sampling_params = SamplingParams(temperature=0.7, max_tokens=512)

prompts_and_loras = [
    ("코드 리뷰해줘: ...", LoRARequest("code-reviewer", 1, "/loras/code_reviewer")),
    ("번역해줘: ...", LoRARequest("translator", 2, "/loras/ko_translator")),
    ("요약해줘: ...", LoRARequest("summarizer", 3, "/loras/summarizer")),
]

outputs = llm.generate(
    [p for p, _ in prompts_and_loras],
    sampling_params,
    lora_request=[l for _, l in prompts_and_loras]
)

SGLang은 Multi-LoRA를 네이티브 기능으로 지원하며 서로 다른 어댑터 간 배칭을 처리합니다. vLLM도 지원하지만 SGLang의 구현이 더 성숙합니다.


하드웨어별 선택 가이드

vLLM은 NVIDIA GPU 외에 Google TPU(v4~v6e), AWS Trainium/Inferentia, Intel Gaudi, AMD GPU, Intel XPU, Arm CPU, PowerPC CPU를 지원합니다. SGLang은 주로 NVIDIA와 AMD GPU를 타깃으로 하며, TPU 지원은 실험적입니다.

def choose_serving_engine(
    hardware: str,           # "nvidia" | "amd" | "tpu" | "trainium" | "gaudi"
    workload: str,           # "chat" | "rag" | "agent" | "batch" | "structured"
    model_type: str,         # "dense" | "moe"
    prefix_reuse_rate: float # 0.0 ~ 1.0 (시스템 프롬프트 재사용 비율)
) -> dict:
    """
    워크로드 특성에 따른 서빙 엔진 선택 가이드
    """
    # 비NVIDIA 하드웨어 → vLLM
    if hardware in ["tpu", "trainium", "gaudi"]:
        return {
            "engine": "vLLM",
            "reason": f"{hardware}는 vLLM만 공식 지원"
        }

    # MoE 모델 → SGLang
    if model_type == "moe":
        return {
            "engine": "SGLang",
            "reason": "DeepSeek 공식 권장, 3.1배 성능 우위"
        }

    # 프리픽스 재사용 높음 → SGLang
    if prefix_reuse_rate > 0.3 or workload in ["rag", "agent", "chat"]:
        return {
            "engine": "SGLang",
            "reason": f"RadixAttention으로 최대 6.4배 처리량 향상"
        }

    # 구조화 출력 → SGLang
    if workload == "structured":
        return {
            "engine": "SGLang",
            "reason": "guided decoding 오버헤드 최소, 배치 크기 무관"
        }

    # 배치 처리, 다양한 모델 지원 필요 → vLLM
    if workload == "batch" or hardware != "nvidia":
        return {
            "engine": "vLLM",
            "reason": "가장 넓은 모델/하드웨어 지원, 커뮤니티 최대"
        }

    # 기본 → vLLM (더 넓은 생태계)
    return {
        "engine": "vLLM",
        "reason": "기본 선택지, 광범위한 서드파티 통합"
    }

# 테스트
print(choose_serving_engine("nvidia", "agent", "dense", 0.7))
# → SGLang (RadixAttention으로 최대 6.4배 처리량 향상)

print(choose_serving_engine("tpu", "batch", "dense", 0.1))
# → vLLM (TPU는 vLLM만 공식 지원)

print(choose_serving_engine("nvidia", "batch", "moe", 0.1))
# → SGLang (DeepSeek 공식 권장, 3.1배 성능 우위)

커뮤니티 & 생태계

vLLM은 GitHub 스타 75,000+로 SGLang 대비 3배 규모의 커뮤니티를 갖고 있습니다. xAI(Grok 3), Microsoft Azure, LinkedIn, Cursor, Oracle Cloud, AWS에서 사용 중이며 40만+ GPU에서 운영됩니다. Red Hat, IBM, Intel이 적극 기여합니다. SGLang은 가장 높은 프로필의 단일 배포에서 강세를 보입니다. Grok 3가 대표적 사례입니다.


실전 판단 기준 요약

상황 선택 이유

RAG / 에이전트 / 멀티턴 챗 SGLang RadixAttention 프리픽스 캐싱
DeepSeek / MoE 모델 SGLang 공식 권장, 3.1배 성능
구조화 출력(JSON 스키마) SGLang guided decoding 오버헤드 최소
TPU / Trainium / Gaudi vLLM 유일한 공식 지원
다양한 모델을 자주 교체 vLLM 가장 넓은 모델 지원
빠른 시작 / 첫 배포 vLLM 커뮤니티·문서·예제 최다
단일 고정 모델 최대 처리량 TensorRT-LLM 28분 컴파일 후 최고 성능

✅ 결론

  • 에이전트·RAG·멀티턴 챗이면 SGLang, 이유는 RadixAttention이 반복 프리픽스를 캐시해서 처리량이 최대 6.4배 오릅니다
  • DeepSeek 같은 MoE 모델을 쓰면 SGLang이 공식 권장이고 3배 이상 빠릅니다
  • TPU·Trainium·Gaudi처럼 비NVIDIA 하드웨어라면 vLLM이 유일한 선택지입니다
  • 처음 배포하거나 모델을 자주 바꾼다면 vLLM이 커뮤니티·문서·생태계가 압도적입니다
  • 워크로드 형태를 먼저 파악하고 엔진을 고르세요. 모델 크기보다 프리픽스 재사용 비율이 더 중요합니다

❌ 주의

  • 벤치마크 수치는 워크로드 형태에 따라 완전히 달라집니다. 직접 테스트가 필수입니다
  • SGLang은 NVIDIA·AMD GPU 중심 — 다른 하드웨어로 확장 계획이 있으면 vLLM을 선택하세요
  • TensorRT-LLM은 최고 처리량을 제공하지만 모델당 28분 컴파일이 필요해서 모델 다양성이 필요한 환경에는 부적합합니다
  • 두 프레임워크 모두 빠르게 업데이트됩니다. 이 비교는 2026년 6월 기준이며, 몇 달 뒤 격차가 달라질 수 있습니다

 

반응형