LLM WikiAccess-protected knowledge portal
← 스터디 홈
173편 · 약 16분

연속 배치(Continuous Batching): 현대 LLM 서빙에서 GPU 처리량을 최대화하는 반복 수준 스케줄링

현대 LLM 서빙 시스템(vLLM, SGLang, TRT-LLM)이 높은 처리량을 내는 핵심 기법이 연속 배치(Continuous Batching)다. 이 챕터에서는 왜 이 기법이 필요한지, 어떻게 동작하는지, 그리고 그 위에 쌓인 최적화들과 어떻게 연결되는지를 설명한다.

정적 배치의 한계

초기 LLM 서빙은 정적 배치(Static Batching)를 사용했다. N개 요청을 하나의 배치로 묶어 동시에 처리하는 방식이다. 문제는 각 요청의 생성 길이가 다르다는 점이다.

10개 요청을 배치로 처리한다고 하자. 9개가 50토큰에서 끝나고 1개가 500토큰을 생성한다면, 9개가 끝난 후에도 GPU는 1개의 요청을 위해 계속 돌아가야 한다. 이 시간 동안 나머지 9개 슬롯은 비어 있는데도 새 요청을 받지 못한다. 짧은 요청이 많을수록 GPU 낭비가 커진다.

ORCA: 반복 수준 스케줄링

2022년 OSDI에 발표된 ORCA 논문(Yu et al.)이 이 문제를 정확히 진단하고 해결책을 제시했다.

핵심 아이디어는 배치 경계를 "요청이 끝날 때"가 아니라 "토큰 생성 반복(iteration)마다" 다시 그리는 것이다. 매 디코딩 단계 직후에 완료된 요청을 제거하고, 대기 중인 새 요청을 즉시 추가한다.

이를 연속 배치(Continuous Batching) 또는 반복 수준 스케줄링(Iteration-Level Scheduling)이라 부른다.

정적 배치 (Static Batching) 배치 크기 = 3, 생성 길이 불균등 0 T A (짧음) 낭비 (대기) B (중간) 낭비 C (긺, 전체 배치 기다림) → 배치 완료 후에야 다음 배치 D E 연속 배치 (Continuous Batching) 요청이 끝날 때마다 즉시 새 요청 추가 0 A D F B E G C A 완료→D 추가 B 완료→E 추가
정적 배치 vs 연속 배치 타임라인

작동 원리

반복 수준 스케줄링의 단계

각 디코딩 단계(forward pass 1회)마다 다음 순서로 진행한다.

  1. 현재 배치에서 EOS 토큰을 생성한 시퀀스를 제거한다
  2. 대기 큐에서 새 시퀀스를 배치에 추가한다 (KV 캐시 메모리 허용 범위 내)
  3. 프리필(prefill)이 필요한 새 시퀀스는 이번 단계에 먼저 처리한다
  4. 배치 전체에 대해 forward pass를 실행한다
  5. 각 시퀀스에서 다음 토큰을 샘플링한다

배치 크기는 정적이지 않다. GPU 메모리가 허용하는 한 계속 새 요청이 들어온다. GPU는 항상 최대한 바쁜 상태를 유지한다.

ORCA 논문은 정적 배치 대비 최대 36.9배 처리량 향상을 보고했다.

KV 캐시와의 결합

연속 배치는 KV 캐시 관리와 밀접하게 연결된다. 각 시퀀스는 처리된 토큰만큼 KV 캐시 슬롯을 점유한다. 시퀀스가 끝나면 슬롯이 해제되고, 새 시퀀스가 그 슬롯을 쓸 수 있다.

초기 구현은 KV 캐시를 연속 메모리 블록으로 할당했다. 문제는 사전에 생성 길이를 알 수 없어 최악의 경우를 예약하거나, 부족하면 재할당해야 했다는 점이다.

vLLM이 PagedAttention으로 이 문제를 해결했다. 실제 메모리를 고정 크기 블록(페이지)으로 나눠 OS 가상 메모리 방식으로 관리한다. 생성 길이를 몰라도 블록을 동적으로 추가할 수 있다.

구현 생태계

vLLM

연속 배치를 PagedAttention과 결합해 대중화한 프레임워크다. LLM Scheduler가 반복마다 running, swapped, waiting 큐를 관리한다. Model Runner V2(챕터 2)에서 스케줄러와 실행 경로가 재설계됐다. v0.27(챕터 133)에서 Rust gRPC 제어면으로 전환해 스케줄 결정과 실행을 분리했다.

SGLang

RadixAttention(챕터 4)으로 KV 캐시를 트리 구조로 공유한다. 연속 배치와 결합해 공통 프리픽스가 있는 요청들이 KV 캐시를 재사용한다.

TensorRT-LLM

NVIDIA의 구현은 InFlight Batching이라는 이름을 쓴다. TRT-LLM 1.3(챕터 39)에서 PyTorch 백엔드로 전환하면서 배치 관리 경로가 변경됐다.

Hugging Face TGI (Text Generation Inference)

초기에 vLLM과 독립적으로 연속 배치를 구현했다. 이후 많은 커널과 최적화를 공유한다.

프리필-디코드 혼합 배치의 문제

연속 배치의 초기 구현에서 프리필(첫 번째 forward pass, 전체 프롬프트 처리)과 디코드(이후 토큰 생성)가 같은 배치에 섞인다. 이 혼합이 문제를 일으킨다.

  • 프리필: compute-bound 작업 (프롬프트 토큰 전체를 병렬 처리)
  • 디코드: memory-bound 작업 (토큰 하나씩 순차 생성)

두 작업이 섞이면 디코드 중인 시퀀스의 TBT(Time Between Tokens)가 프리필 지연만큼 증가한다. 다른 요청의 프리필이 내 디코딩 단계를 지연시킨다.

이 문제를 해결하는 방법이 두 가지다:

Chunked Prefill: 프리필을 작은 청크로 나눠 디코드와 교대로 처리한다. TTFT와 TBT를 동시에 줄인다. Sarathi-Serve(챕터 123)가 이 방식을 제안했고, 현재 vLLM에 기본 탑재됐다.

PD 분리(Prefill-Decode Disaggregation): 프리필 전용 노드와 디코드 전용 노드를 물리적으로 분리한다. 프리필 GPU와 디코드 GPU의 리소스 요구사항이 달라 각각을 독립 최적화할 수 있다. 챕터 169에서 자세히 다뤘다.

처리량·지연시간 트레이드오프

연속 배치는 처리량(throughput) 관점에서 거의 모든 시나리오에서 정적 배치를 압도한다. 그러나 개별 요청의 지연시간은 배치가 클수록 늘어날 수 있다.

  • TTFT(Time To First Token): 내 프리필 전에 다른 요청들의 디코드 단계가 있으면 TTFT가 늘어난다
  • TBT(Time Between Tokens): 배치 크기에 비례해 늘어난다 (배치가 크면 각 forward pass가 느려짐)

이것이 SLO 기반 스케줄링이 중요한 이유다. 처리량만 최대화하면 지연시간 SLO를 위반한다. SLAI(챕터 135), AdaServe(챕터 87), SMetric(챕터 82) 등이 이 균형을 다루는 연구다.

연속 배치 위에 쌓인 최적화들

연속 배치는 현재 LLM 서빙의 기본 전제로 자리잡았고, 그 위에 여러 최적화가 쌓였다.

최적화 기법해결하는 문제관련 챕터
Chunked Prefill프리필이 디코드 TBT를 높임123
PD 분리프리필·디코드 리소스 요구사항 불일치169
투기적 디코딩단일 forward pass 속도 한계22, 87, 103
프리픽스 캐싱반복 프리필 낭비171
SLO-aware 스케줄링처리량 vs 지연시간 균형135
이종 GPU 라우팅다른 GPU 스펙 혼재86

운영 기준: 연속 배치 서버 튜닝

핵심 파라미터 (vLLM 기준)

--max-num-seqs (기본값: 256): 동시에 처리할 최대 시퀀스 수. 메모리가 충분해도 이 값이 너무 크면 TBT SLO를 초과할 수 있다.

--gpu-memory-utilization (기본값: 0.9): KV 캐시용 GPU 메모리 비율. 너무 높이면 OOM, 너무 낮추면 처리량 저하.

--max-num-batched-tokens: 한 forward pass에 처리할 최대 토큰 수. 배치 내 총 토큰 수를 제한해 지연시간 예측 가능성을 높인다.

--enable-chunked-prefill: Chunked Prefill 활성화. 혼합 배치에서 TBT 안정성이 중요할 때 권장한다.

GPU 이용률 진단

연속 배치가 올바르게 동작하면 nvidia-smi에서 GPU 이용률이 85~95% 범위를 유지한다. 지속적으로 70% 이하면 배치에 요청이 충분히 채워지지 않거나, 메모리 제한으로 배치가 작게 유지되고 있을 수 있다.

# GPU 이용률 실시간 모니터링
nvidia-smi dmon -s u -d 1

# vLLM 메트릭 (Prometheus 엔드포인트)
# vllm:num_requests_running  — 현재 실행 중인 시퀀스 수
# vllm:gpu_cache_usage_perc  — KV 캐시 점유율

검증 체크리스트

  • [ ] 연속 배치 활성화 여부 확인 (vLLM: 기본 활성화)
  • [ ] GPU 이용률 모니터링: 85% 이상 목표
  • [ ] TTFT, TBT p50·p99 모두 추적 (처리량만 보면 SLO 위반을 놓침)
  • [ ] 평균·피크 배치 크기 기록 (vllm:num_requests_running)
  • [ ] KV 캐시 점유율 90% 초과 시 max_num_seqs 조정 또는 gpu_memory_utilization 감소
  • [ ] 지연시간 SLO 요구사항이 엄격하면 Chunked Prefill 또는 PD 분리 검토

References

  • Yu et al., "ORCA: A Distributed Serving System for Transformer-Based Generative Models", OSDI 2022 — https://www.usenix.org/conference/osdi22/presentation/yu
  • Kwon et al., "Efficient Memory Management for Large Language Model Serving with PagedAttention", SOSP 2023 — https://dl.acm.org/doi/10.1145/3600006.3613165
  • Agrawal et al., "Sarathi-Serve: Taming Throughput-Latency Tradeoff in LLM Inference with Chunked Prefills", OSDI 2024 — https://www.usenix.org/conference/osdi24/presentation/agrawal
  • Anyscale, "How continuous batching enables 23x throughput in LLM inference while reducing p50 latency" — https://www.anyscale.com/blog/continuous-batching-llm-inference
  • vLLM Documentation: Scheduler — https://docs.vllm.ai/en/latest/serving/distributed_serving.html