본문 바로가기

07. batch 효율

핵심 질문
  • 여러 요청을 묶어(batch) 처리하면 왜 이득인가? 그 이득은 언제 새는가?
  • "배치를 키우면 처리량이 는다"는 어떤 조건에서 참인가?

목표
  • 배칭이 03장의 memory 병목을 어떻게 완화하는지 연결한다.
  • static batch의 padding·straggler 낭비를 정의하고, "배치 폭"과 "유효 work"를 구분한다.

여정에서의 위치

03장에서 decode가 memory 쪽으로 기우는 이유는 "한 토큰을 위해 방대한 가중치를 읽어오기 때문"이었습니다. 여기서 자연스러운 아이디어가 나옵니다: 가중치를 한 번 읽어올 때, 여러 요청의 토큰을 동시에 처리하면 그 읽기 비용을 나눠 쓸 수 있지 않을까? 이것이 배칭(batching)의 근본 동기입니다.

flowchart LR
    subgraph 배치없음
        R1[요청1: 가중치 로드→토큰1]:::comp
        R2[요청2: 가중치 로드→토큰1]:::comp
    end
    subgraph 배치
        B[가중치 1회 로드]:::result --> BR[요청1·2·3 토큰 동시 계산]:::result
    end

    classDef comp fill:#d0ebff,stroke:#1971c2,color:#000;
    classDef result fill:#d3f9d8,stroke:#2f9e44,color:#000;

즉 배칭은 03장 표에서 본 "decode의 배치 크기가 커지면 compute 쪽으로 이동"의 실현입니다. 같은 가중치 로드로 더 많은 유효 연산을 하게 만들어 가속기 활용률(utilization)을 높입니다.

static batch — 가장 단순한 배칭

static batch(정적 배치)는 요청들을 한 묶음으로 고정해 함께 시작하고, 그 묶음이 다 끝날 때까지 다음 묶음을 시작하지 않는 방식입니다. 구현이 단순하지만 두 가지 낭비가 생깁니다.

1. padding(패딩) 낭비

배치 안 요청들의 길이가 다르면, 짧은 요청을 긴 요청에 맞춰 빈 토큰(padding)으로 채워 모양을 맞춥니다. 이 padding 자리의 연산은 버려지는 work입니다.

2. straggler(낙오자) 낭비

한 배치는 가장 긴 요청이 끝날 때까지 붙잡혀 있습니다. 짧은 요청은 일찍 끝났는데도 자리를 뜨지 못하고, 그 슬롯은 새 요청을 받지 못한 채 놀게 됩니다. 이 "가장 느린 하나를 기다리는" 문제가 straggler입니다.

flowchart TB
    B[static batch 시작]:::ctrl --> S1[요청A: 10토큰 생성 후 종료]:::comp
    B --> S2[요청B: 200토큰 생성]:::comp
    S1 -.대기(놀고 있음).-> W[요청A 슬롯 낭비]:::danger
    S2 --> E[배치 전체 종료]:::result
    W --> E

    classDef ctrl fill:#c3fae8,stroke:#0ca678,color:#000;
    classDef comp fill:#d0ebff,stroke:#1971c2,color:#000;
    classDef danger fill:#ffc9c9,stroke:#e03131,color:#000;
    classDef result fill:#d3f9d8,stroke:#2f9e44,color:#000;

'배치 폭'과 '유효 work'는 다르다

여기서 중요한 구분: 배치 폭(batch width, 슬롯 수)이 크다고 해서 유효 work(실제로 쓸모 있는 연산)가 그만큼 많은 것은 아닙니다. padding과 straggler 때문에, 배치 폭 대비 유효 work의 비율(유효 활용률)이 낮아질 수 있습니다.

📌 핵심
"배치 크기 32"라는 말은 "동시에 유효한 계산 32개"가 아닙니다. 그중 얼마가 padding이고, 얼마가 이미 끝나 straggler를 기다리는 슬롯인지에 따라 실제 이득이 달라집니다.
⚖️ 절충(tradeoff)
  • 배치를 키우면: throughput(처리량)↑ 가능하지만, 개별 요청의 TTFT·지연이 늘 수 있음(14장에서 다시). 큰 배치는 prefill 대기·큐를 늘립니다.
  • 배치를 줄이면: 개별 지연↓ 가능하지만, 가속기 활용률↓로 throughput↓.
  • 그래서 "무조건 큰 배치"는 답이 아니고, 워크로드·SLO에 따라 달라집니다.
🔬 증거 읽기 (주장 유형)
"배치를 키우면 throughput이 는다"는 어떤 지점까지만 참입니다. 여러 자료가 동시성을 올리면 총 TPS가 오르다가 포화점(saturation) 이후엔 정체·하락한다고 설명합니다(확인일 2026-07-20). 조건(모델·하드웨어·워크로드) 없이 "배치↑=처리량↑"으로 단정하는 자료는 신뢰도를 낮춰 읽으세요. 이는 inferred 경향이지 무조건 참인 법칙이 아닙니다.

static batch의 한계가 다음 장을 부른다

straggler와 padding 낭비의 뿌리는 "배치를 통째로 시작하고 통째로 끝낸다"는 점입니다. 만약 배치를 통째가 아니라 매 반복(iteration)마다 재구성할 수 있다면 — 끝난 요청은 즉시 내보내고 빈자리에 새 요청을 넣는다면 — 이 낭비를 크게 줄일 수 있습니다. 그것이 다음 장의 continuous batching입니다.

📌 핵심

  • 배칭의 동기는 가중치 로드 비용을 여러 요청이 나눠 쓰기(03장 memory 병목 완화).
  • static batch는 묶음을 통째로 시작·종료 → padding(길이 맞춤 낭비)과 straggler(가장 긴 요청 대기) 낭비.
  • 배치 폭 ≠ 유효 work: 낭비를 빼야 실제 이득이 보인다.
  • 배치 확대는 throughput↑과 개별 지연↑의 절충이며, 포화점 이후엔 이득이 줄거나 사라진다.

🔎 이 장의 '지지하지 않는 결론'

  • "배치를 크게 하면 항상 빨라진다"고 말할 수 없습니다 — 포화점·개별 지연·낭비가 있습니다.
  • 특정 최적 배치 크기를 이 장 개념만으로 처방할 수 없습니다(범위 밖: 프로덕션 튜닝).

✍️ 확인 문제

  1. padding 낭비와 straggler 낭비를 각각 정의하고, 둘의 공통 뿌리(static batch의 어떤 성질)를 말하세요.
  2. "배치 폭 32"가 "유효 work 32"와 다를 수 있는 이유를 설명하세요.
  3. (조건 유형) "배치를 키우면 처리량이 는다"가 성립하는 조건과, 뒤집히는 조건을 각각 하나씩 드세요.
다음 장: 08 · continuous batching — 배치를 매 반복 재구성하기.