본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 4장: Continuous Batching과 동적 배칭
2026년 3월 22일·AI / ML·

4장: Continuous Batching과 동적 배칭

정적 배칭의 한계를 분석하고, Continuous Batching의 iteration-level 스케줄링 원리와 vLLM, TGI, TensorRT-LLM의 구현 차이를 비교합니다.

16분380자9개 섹션
llmaiperformancemlops
공유
llm-inference4 / 10
12345678910
이전3장: PagedAttention과 vLLM다음5장: Speculative Decoding — 추측 기반 가속

이 장에서 배우는 것

  • 정적 배칭(Static Batching)의 구조적 한계
  • Continuous Batching의 원리와 iteration-level 스케줄링
  • 요청별 독립 완료가 처리량에 미치는 영향
  • vLLM, TGI, TensorRT-LLM의 배칭 구현 비교
  • 배치 크기 튜닝 전략

왜 배칭이 중요한가

1장에서 Decode 단계가 메모리 바운드라고 설명했습니다. 토큰 하나를 생성하기 위해 모델 가중치 전체를 HBM에서 읽어와야 하는데, 실제 연산량은 매우 적습니다. 이것은 GPU의 연산 자원이 크게 낭비되고 있다는 뜻입니다.

**배칭(Batching)**은 여러 요청을 묶어 한 번에 처리함으로써 이 문제를 완화합니다. 모델 가중치를 HBM에서 한 번 읽어올 때, 여러 요청의 토큰을 동시에 연산하면 메모리 읽기 비용을 공유할 수 있습니다.

GPU 활용률∝배치 크기×토큰당 연산량메모리 대역폭\text{GPU 활용률} \propto \frac{\text{배치 크기} \times \text{토큰당 연산량}}{\text{메모리 대역폭}}GPU 활용률∝메모리 대역폭배치 크기×토큰당 연산량​

배치 크기가 커질수록 산술 강도(Arithmetic Intensity)가 높아져서, 메모리 바운드에서 컴퓨트 바운드로 전환됩니다. 이것이 배칭이 추론 최적화의 핵심인 이유입니다.

정적 배칭의 한계

가장 단순한 배칭 방식은 **정적 배칭(Static Batching)**입니다. 여러 요청을 모아 하나의 배치로 구성하고, 배치 내 모든 요청이 완료될 때까지 기다렸다가 다음 배치를 처리합니다.

정적 배칭의 문제
text
시간 →
요청 A: [████████████████████████████████]  (128토큰 생성)
요청 B: [████████________padding________]  (32토큰 생성, 96토큰 대기)
요청 C: [████████████____padding________]  (48토큰 생성, 80토큰 대기)
                    ↑                    ↑
                    B 완료               A 완료 → 전체 배치 완료

정적 배칭에는 세 가지 근본적인 문제가 있습니다.

1. 패딩 낭비

배치 내 요청들의 출력 길이가 다르면, 짧은 요청은 긴 요청이 끝날 때까지 빈 연산(패딩)으로 GPU 자원을 낭비합니다. 실제 워크로드에서 출력 길이의 분산은 매우 크기 때문에, 이 낭비는 상당합니다.

2. Head-of-Line Blocking

하나의 매우 긴 요청이 배치 전체를 지연시킵니다. 배치 내 3개 요청이 이미 완료되었더라도, 나머지 1개 요청이 끝나기 전에는 새로운 요청을 받을 수 없습니다.

3. 낮은 GPU 활용률

배치 간 전환 시점에 GPU가 유휴 상태가 되고, 패딩 연산도 실질적으로 유휴 상태와 다르지 않습니다.

Info

정적 배칭의 핵심 문제는 "배치"를 원자적(Atomic) 단위로 취급한다는 점입니다. 배치 전체가 시작되고, 배치 전체가 완료될 때까지 아무것도 변경할 수 없습니다.

Continuous Batching의 원리

Continuous Batching은 배치를 원자적 단위가 아닌, iteration(단일 Decode 스텝) 단위로 관리합니다. 매 iteration마다 스케줄러가 배치의 구성을 재평가하고, 완료된 요청을 빼고 새로운 요청을 넣을 수 있습니다.

Iteration-level 스케줄링

Continuous Batching 동작
text
Iteration 1: [A, B, C, D]  ← 4개 요청 처리
Iteration 2: [A, B, C, D]  ← B 완료 (EOS 토큰 생성)
Iteration 3: [A, E, C, D]  ← B 제거, 대기열의 E 투입
Iteration 4: [A, E, C, D]  ← D 완료
Iteration 5: [A, E, C, F]  ← D 제거, F 투입
...

매 iteration이 끝날 때마다 다음을 결정합니다.

  1. EOS 토큰을 생성했거나 최대 길이에 도달한 요청을 즉시 배치에서 제거
  2. 대기열에 있는 새 요청의 Prefill을 즉시 시작
  3. 메모리 상황에 따라 배치 크기를 동적으로 조절

정적 배칭과의 비교

처리량 극대화 메커니즘

Continuous Batching이 처리량을 극대화하는 핵심 메커니즘을 분석합니다.

GPU 유휴 시간 제거

정적 배칭에서는 배치 전환 시점과 패딩 구간에서 GPU가 유휴 상태가 됩니다. Continuous Batching은 항상 처리할 요청이 있는 한 GPU가 쉬지 않습니다.

동적 배치 크기

메모리가 허용하는 범위에서 배치 크기가 자동으로 조절됩니다. 짧은 요청이 많이 들어오면 배치가 커지고, 긴 컨텍스트 요청이 들어오면 배치가 작아집니다. KV 캐시 메모리가 부족해지면 새 요청의 투입을 지연시키는 배압(Backpressure) 메커니즘이 작동합니다.

Prefill과 Decode의 혼합

고급 스케줄러에서는 한 iteration 안에서 일부 요청은 Prefill, 일부는 Decode를 동시에 수행하는 **혼합 배칭(Mixed Batching)**을 지원합니다. 이를 통해 새 요청의 TTFT를 줄이면서도 기존 요청의 Decode를 계속 진행할 수 있습니다.

Warning

Prefill과 Decode의 혼합은 연산 특성이 매우 다르기 때문에 주의가 필요합니다. Prefill은 컴퓨트 바운드, Decode는 메모리 바운드이므로, 혼합 비율에 따라 전체 시스템의 성능 특성이 달라집니다. 일부 시스템은 Prefill과 Decode를 별도 GPU로 분리하는 disaggregated serving 접근법을 사용하기도 합니다.

요청별 독립 완료

Continuous Batching의 또 다른 핵심 이점은 요청별 독립 완료입니다. 각 요청은 자신의 생성이 끝나는 즉시 결과를 반환합니다.

continuous_batching_simulation.py
python
# Continuous Batching의 요청별 독립 완료 시뮬레이션
 
class ContinuousBatchScheduler:
    def __init__(self, max_batch_size: int, max_memory_blocks: int):
        self.max_batch = max_batch_size
        self.max_blocks = max_memory_blocks
        self.active: list[Request] = []
        self.waiting: list[Request] = []
        self.used_blocks = 0
 
    def step(self) -> list[Request]:
        """한 iteration 수행"""
        completed = []
        
        # 1. 완료된 요청 제거
        for req in self.active[:]:
            if req.is_finished():
                self.active.remove(req)
                self.used_blocks -= req.num_blocks
                completed.append(req)
        
        # 2. 새 요청 투입
        while (self.waiting 
               and len(self.active) < self.max_batch
               and self.used_blocks + self.waiting[0].initial_blocks 
                   <= self.max_blocks):
            new_req = self.waiting.pop(0)
            self.active.append(new_req)
            self.used_blocks += new_req.initial_blocks
        
        # 3. 활성 요청 Decode 수행
        for req in self.active:
            req.decode_one_token()
        
        return completed

이 방식은 사용자 경험에도 직접적인 영향을 미칩니다. 정적 배칭에서는 응답이 "뭉치(Burst)"로 돌아오지만, Continuous Batching에서는 각 요청의 응답이 준비되는 즉시 스트리밍됩니다.

추론 엔진별 구현 비교

vLLM

vLLM의 스케줄러는 PagedAttention과 긴밀하게 통합되어 있습니다. 블록 매니저가 보고하는 가용 블록 수를 기반으로 배치 크기를 동적으로 결정합니다.

  • 스케줄링 정책: FCFS(First-Come-First-Served) 기본, 우선순위 기반 옵션
  • Preemption: 메모리 부족 시 낮은 우선순위 요청을 일시 중단하고 KV 캐시를 CPU로 스왑
  • Chunked Prefill: 긴 입력의 Prefill을 여러 iteration에 나누어 Decode 지연을 방지

TGI (Text Generation Inference)

Hugging Face의 TGI는 Rust 기반의 고성능 서버로, Continuous Batching을 Token Streaming과 결합합니다.

  • Token Streaming: gRPC/SSE를 통한 실시간 토큰 스트리밍
  • Flash Decoding: Flash Attention 기반의 최적화된 Decode 커널
  • Watermark: AI 생성 텍스트 워터마킹 내장

TensorRT-LLM

NVIDIA의 TensorRT-LLM은 하드웨어 최적화에 중점을 둡니다.

  • Inflight Batching: NVIDIA의 Continuous Batching 구현체
  • FP8 Native: H100/H200의 FP8 텐서 코어를 직접 활용
  • Custom Kernels: NVIDIA GPU에 최적화된 커스텀 커널
특성vLLMTGITensorRT-LLM
언어Python + CUDARust + PythonC++ + CUDA
PagedAttention네이티브 지원지원자체 구현
모델 지원 폭매우 넓음넓음NVIDIA 최적화 모델
GPU 최적화 깊이중간중간매우 깊음
배포 편의성높음높음중간
커뮤니티매우 활발활발NVIDIA 주도

배치 크기 튜닝 전략

배치 크기는 지연시간과 처리량의 트레이드오프를 결정하는 핵심 파라미터입니다.

배치 크기와 성능의 관계

배치 크기별 성능 특성
text
배치 크기   | 지연시간(TPOT) | 처리량(TPS)  | GPU 활용률
1           | 최소           | 낮음         | 낮음 (메모리 바운드)
4           | 약간 증가      | 중간         | 중간
16          | 증가           | 높음         | 높음
64          | 크게 증가      | 매우 높음    | 매우 높음 (컴퓨트 바운드)
256+        | 매우 큼        | 포화         | 포화 (메모리 한계)

튜닝 가이드라인

  1. 지연시간 민감 서비스 (챗봇): 배치 크기를 작게 유지하되, 최소 4-8로 설정해 기본적인 효율을 확보합니다. TPOT SLO를 기준으로 상한을 설정합니다.

  2. 처리량 우선 서비스 (배치 처리): 메모리가 허용하는 최대 배치 크기를 사용합니다. KV 캐시 메모리가 병목이 되는 시점까지 배치를 키웁니다.

  3. 혼합 워크로드: Continuous Batching의 동적 조절에 의존하되, max_num_seqs와 max_num_batched_tokens 파라미터로 상한을 제어합니다.

Tip

vLLM에서 --max-num-seqs 파라미터는 동시에 처리할 수 있는 최대 요청 수를, --max-num-batched-tokens는 한 iteration에서 처리할 최대 토큰 수를 제한합니다. 프로덕션 환경에서는 이 두 값을 SLO와 GPU 메모리에 맞게 조절하는 것이 중요합니다.


정리

이 장에서는 Continuous Batching의 원리와 구현을 살펴보았습니다.

  • 정적 배칭은 패딩 낭비와 Head-of-Line Blocking으로 GPU 활용률이 낮습니다
  • Continuous Batching은 iteration-level 스케줄링으로 요청의 독립적 투입과 완료를 가능하게 합니다
  • 매 iteration마다 배치 구성을 재평가하여 GPU 유휴 시간을 최소화합니다
  • vLLM, TGI, TensorRT-LLM 모두 Continuous Batching을 핵심 기능으로 지원합니다

다음 장에서는 자기회귀 생성의 순차적 한계를 우회하는 영리한 접근법인 Speculative Decoding을 다룹니다. 작은 모델의 "추측"을 큰 모델이 검증하는 방식으로 어떻게 수학적으로 동일한 출력을 유지하면서 2-3배의 속도 향상을 달성하는지 알아보겠습니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#llm#ai#performance#mlops

관련 글

AI / ML

5장: Speculative Decoding — 추측 기반 가속

Draft-Verify 패러다임으로 자기회귀 디코딩을 가속하는 Speculative Decoding의 원리, 수학적 보장, 그리고 Medusa, Eagle 등 변형 기법을 분석합니다.

2026년 3월 24일·17분
AI / ML

3장: PagedAttention과 vLLM

OS 가상 메모리에서 영감받은 PagedAttention의 원리를 설명하고, vLLM의 아키텍처와 Automatic Prefix Caching, 계층적 KV 캐시를 분석합니다.

2026년 3월 20일·16분
AI / ML

6장: Prefix Caching과 프롬프트 최적화

시스템 프롬프트 캐싱, Prefix-aware 스케줄링, RadixAttention의 원리를 분석하고, 멀티턴 대화와 평가 워크플로우에서의 성능 개선을 다룹니다.

2026년 3월 26일·17분
이전 글3장: PagedAttention과 vLLM
다음 글5장: Speculative Decoding — 추측 기반 가속

댓글

목차

약 16분 남음
  • 이 장에서 배우는 것
  • 왜 배칭이 중요한가
  • 정적 배칭의 한계
    • 1. 패딩 낭비
    • 2. Head-of-Line Blocking
    • 3. 낮은 GPU 활용률
  • Continuous Batching의 원리
    • Iteration-level 스케줄링
    • 정적 배칭과의 비교
  • 처리량 극대화 메커니즘
    • GPU 유휴 시간 제거
    • 동적 배치 크기
    • Prefill과 Decode의 혼합
  • 요청별 독립 완료
  • 추론 엔진별 구현 비교
    • vLLM
    • TGI (Text Generation Inference)
    • TensorRT-LLM
  • 배치 크기 튜닝 전략
    • 배치 크기와 성능의 관계
    • 튜닝 가이드라인
  • 정리