AEGLOSLAB 엔비디아 기술 스택

제5부 추론 최적화와 서빙

5.1 추론 최적화 개관

5.1.1 이 장에서 배우는 것 / 선수 지식

제5부의 시작. 제0~4부에서 우리는 모델을 빠르게 실행하는 하드웨어와 커널(GPU·CUDA·라이브러리)과 여러 GPU로 키우는 법(데이터센터·스케일)을 익혔다. 그 무게중심은 대체로 학습이었다. 이제 무게를 추론(inference) 으로 옮긴다 — 학습이 끝난 모델을 24/7로 서비스하며, 사용자 요청에 지연(latency) 안에 답하고, 처리량(throughput) 을 극대화하고, 정밀도(accuracy) 를 지키며, 메모리·비용을 통제하는 일이다.

이 장은 제5부 전체의 지도다. 개별 도구(TensorRT·TensorRT-LLM·Triton)를 파기 전에, 추론 최적화가 무엇을 사이에서 저울질하는 게임인지를 먼저 세운다. 핵심 틀은 네 꼭짓점의 사면체 트레이드오프 — 지연·처리량·정밀도·메모리(비용) 다. 어느 하나를 당기면 다른 셋 중 하나 이상이 따라 움직인다. 이 틀을 손에 쥐면 이후 장들(5.2~5.15)의 모든 기법이 "사면체의 어느 축을 어떤 대가로 미는가"로 정리된다.

배우는 것:

  • 추론이 학습과 무엇이·왜 다른가 — 작업의 형태(forward-only·반복·가변 부하)와 목표(SLA·비용)의 차이.
  • 추론 성능의 언어 — TTFT·TPOT·p99 같은 지연 지표, tokens/s·QPS 같은 처리량 지표, goodput, $/토큰.
  • 사면체 트레이드오프(지연·처리량·정밀도·메모리)와, 그 중심에 있는 배치 크기라는 마스터 노브.
  • LLM 추론의 두 국면 — prefill(컴퓨트 바운드)과 decode(메모리 바운드)가 왜 다른 최적화를 요구하나(루프라인, 1.10).
  • 실행할 수 있는 최적화 레버의 목록과, 각각이 이후 어느 장에서 깊어지는가(제5부 로드맵).
  • 엔비디아 추론 스택의 지형 — 컴파일·최적화(TensorRT/TRT-LLM) → 서빙(Triton) → 마이크로서비스(NIM)의 계층.

선수 지식: 1.1(처리량 vs 지연 — 추론 SLA는 둘의 균형), 1.10(루프라인·메모리바운드 — decode가 왜 느린지의 핵심), 1.13~1.14(정밀도·양자화 — 정밀도 축), 1.9(HBM 대역폭 — decode의 병목), 3.6~3.7(어텐션·KV 캐시 — LLM 추론 메모리), 2.10~2.11(스트림·CUDA Graphs — 런치 오버헤드), 4.13~4.14(NCCL·병렬화 — 다GPU 추론). 이 장은 개관이라 코드보다 수치 계산·의사결정 워크스루 중심이다. 구체 도구 실습은 5.2부터.

정직: 이 장의 어떤 처리량·지연 수치도 특정 제품의 공식 벤치마크가 아니라 "구조를 보여주는 개략 계산" 이다. 실제 값은 모델·시퀀스 길이·배치·GPU 세대·소프트웨어 버전에 따라 크게 달라진다 — 반드시 그 시점·그 환경에서 실측한다. 제품·SDK 명칭과 기능 범위는 리브랜딩·버전 변화가 잦아 "시점 의존, 확인 필요".

5.1.2 추론은 학습과 무엇이 다른가 (왜)

같은 모델, 같은 GPU라도 학습과 추론은 다른 기계처럼 다뤄야 한다. 최적화의 목표 함수가 다르기 때문이다.

축학습(training)추론(inference)
연산forward + backward + optimizerforward만
실행 횟수데이터셋을 여러 epoch, 한 번의 잡모델 수명 내내 무한 반복(요청마다)
배치크게(처리량 극대), 내가 정함사용자 부하가 정함(가변·예측 불가)
목표정해진 시간/비용에 수렴SLA(p99 지연) 안에서 비용/처리량 최적
부하 패턴안정적·예측 가능버스트·주야 변동, 큐잉
상태옵티마이저·그래디언트(거대)모델 가중치 + (LLM이면) KV 캐시
정밀도 여유수렴 유지가 관건출력 품질 유지(양자화 더 공격적 가능)
비용의 의미일회성 CapEx/클라우드 버스트지속 OpEx — 추론비가 모델 TCO를 지배

세 가지 함의가 따라온다.

① 추론비가 누적된다. 학습은 한 번 끝내면 되지만, 추론은 모델이 살아 있는 한 매 요청마다 GPU를 쓴다. 인기 있는 모델은 학습보다 추론에 훨씬 많은 총연산을 쓴다. 그래서 추론에서의 1.5× 효율 개선은 곧 운영비 33% 절감이다 — 최적화의 경제적 동기가 학습보다 직접적이다.

② 부하를 내가 통제하지 못한다. 학습 배치는 내가 64·256으로 정하지만, 추론은 사용자가 언제 몇 개를 보낼지 모른다. 그래서 추론 시스템의 절반은 모델이 아니라 요청을 모으고·줄 세우고·배치로 묶는 스케줄러다(동적 배칭, 5.13). 같은 GPU·같은 모델이라도 배칭 전략이 처리량을 몇 배 가른다.

③ 지연에 꼬리(tail)가 있다. 평균이 빨라도 p99(상위 1% 느린 요청) 가 SLA를 깨면 서비스 실패다. 배치를 키우면 평균 처리량은 좋아지지만 큐에서 기다리는 요청의 꼬리 지연이 늘 수 있다. 추론 최적화는 평균이 아니라 분포를 다룬다.

학습 (내가 통제·한 번· 처리량 게임) 추론 (사용자가 통제·무한 반복· 지연/처리량/비용 동시 게임) forward+backward 큰 배치 손실 ↓ 요청 큐·배처 (여기가 추론 시스템의 핵심) 요청 요청 forward 응답

5.1.3 추론 성능의 언어 — 지표 정의

최적화하려면 먼저 무엇을 재는지 정의해야 한다. 추론 지표는 지연과 처리량 두 축, 그리고 그 둘을 묶는 goodput·비용이다.

지연(latency) — 한 요청이 얼마나 빨리 끝나나.

  • TTFT(Time To First Token): 요청 도착 → 첫 토큰 생성까지. LLM에서 체감 반응성. prefill 비용이 지배(5.1.6).
  • TPOT(Time Per Output Token) / ITL(Inter-Token Latency): 토큰 사이 간격. 생성 "흐름"의 속도. decode 비용이 지배.
  • End-to-end latency: TTFT + (출력 토큰 수 − 1) × TPOT + 큐 대기. 사용자가 실제 느끼는 총시간.
  • 분위수: p50(중앙값)·p99(꼬리). SLA는 거의 항상 분위수로 쓴다("p99 TTFT < 500ms").

처리량(throughput) — 단위 시간에 얼마나 많이.

  • tokens/s: LLM의 1차 지표(전체 시스템이 초당 생성하는 토큰). 입력·출력 토큰을 구분해 보고하기도.
  • requests/s(QPS): 요청 단위 처리량. 비-LLM(분류·검출)·짧은 요청에서 자연스러움.
  • 동시성(concurrency): 동시에 처리 중인 요청 수. 처리량 = 동시성 / 평균지연(리틀의 법칙).

둘을 묶는 지표.

  • Goodput: 단순 처리량이 아니라 SLA를 만족한 요청만 센 처리량. 배치를 키워 tokens/s를 높여도 p99가 SLA를 깨면 goodput은 떨어진다 — 운영의 궁극적 목표는 보통 goodput이다.
  • 비용: $/100만 토큰 또는 요청당 GPU-시간. 같은 모델·같은 SLA를 더 낮은 비용으로 내는 것이 최적화의 종착점. (구체 단가는 GPU·클라우드·시점 의존 → 확인 필요.)
지연 축처리량 축
TTFT — prefill이 지배tokens/s — 시스템 전체
TPOT — decode가 지배QPS — 요청 단위
p99 — 꼬리(SLA의 기준)concurrency — 동시 처리 수

둘을 묶으면 → goodput(SLA 만족 처리량), $/1M토큰(비용).

함정 예고: "우리 모델 빨라요"는 무의미하다. 무슨 지연을(어느 분위수), 무슨 부하에서(동시성·시퀀스 길이), 무슨 정밀도로 냈는지를 명시하지 않은 수치는 비교 불가다. 벤치마크는 항상 조건과 함께 읽고 쓴다.

5.1.4 사면체 트레이드오프 — 최적화의 지형

추론 최적화의 모든 결정은 네 꼭짓점 사이의 줄다리기다.

지연(Latency) 낮을수록 좋음 메모리·비용(Memory/Cost) 적을수록 좋음 정밀도(Accuracy) 높을수록 좋음 처리량(Throughput) 높을수록 좋음

네 꼭짓점은 동시에 최선일 수 없다 — 하나를 당기면 다른 축이 따라 움직인다.

축 사이의 대표적 상호작용(왜 그런지 메커니즘과 함께):

미는 축방법따라오는 대가
처리량 ↑배치 크기 ↑지연 ↑(큐 대기·큰 GEMM), 메모리 ↑(활성화·KV 캐시)
지연 ↓배치 ↓·전용 GPU처리량 ↓(GPU 놀림), 비용 ↑(요청당 자원↑)
메모리·비용 ↓양자화(FP8·INT8·FP4)정밀도 ↓(품질 손실 위험), 처리량 ↑(부수 이득)
메모리 ↓KV 캐시 압축·페이징구현 복잡↑, 약간의 지연/정밀도 영향 가능
정밀도 ↑고정밀(FP16/BF16) 유지메모리·비용 ↑, 처리량 ↓

마스터 노브 — 배치 크기. 사면체의 중심에는 거의 항상 배치 크기가 있다. 같은 모델·같은 GPU에서:

배치 ↑ GPU 활용률 ↑ tokens/s ↑ (처리량 좋아짐) 한 요청이 큐에서 더 기다림 + 큰 GEMM 개별 지연 ↑ 활성화·KV 캐시 메모리 ↑ OOM 위험·동시 요청 수 한계

그래서 "지연 우선" 배포는 작은 배치(또는 1), "처리량/비용 우선" 배포는 큰 배치로 간다. 둘 다 잡으려는 것이 동적·인플라이트 배칭(5.13·5.8)이고, 정밀도를 희생해 셋을 동시에 미는 것이 양자화(5.4~5.5·5.9)다.

루프라인 연결(1.10). 사면체가 추상적이지 않은 이유는, 추론의 상당 부분이 메모리 바운드라는 물리에 뿌리내리기 때문이다. 작은 배치의 행렬-벡터 연산(특히 LLM decode)은 산술 강도가 낮아 HBM 대역폭(1.9)에 묶인다. 그래서:

  • 배치를 키우면 같은 가중치 읽기로 더 많은 토큰을 처리 → 산술 강도↑ → 루프라인에서 컴퓨트 쪽으로 이동 → 처리량 효율↑. (배치가 "무비용 처리량"을 주는 물리적 이유.)
  • 양자화로 가중치를 절반(FP16→FP8)으로 줄이면 읽을 바이트가 절반 → 메모리 바운드 구간에서 ~2× 속도 + 메모리 절감. (양자화가 정밀도뿐 아니라 속도를 주는 이유.)

이 두 문장이 제5부 기법 대부분의 물리적 근거다.

5.1.5 무엇을 실행할 수 있나 — 최적화 레버 목록

사면체를 미는 구체 수단들. 각 레버가 어느 축을 어떤 대가로 미는지, 그리고 이후 어느 장에서 깊어지는지를 묶어 둔다 — 이것이 제5부 로드맵이다.

레버무엇을주로 미는 축깊어지는 곳
그래프 최적화레이어 융합·상수 폴딩·커널 오토튜닝·dead-layer 제거지연↓·처리량↑(메모리 트래픽·런치↓)5.2~5.3(TensorRT)
정밀도/양자화FP16·BF16·FP8·INT8·FP4로 가중치·활성화 축소메모리↓·처리량↑(정밀도 대가)5.4~5.5, 5.9
커널·어텐션 융합FlashAttention류 융합 커널지연↓·메모리↓3.6~3.7, 5.7
동적·인플라이트 배칭요청을 모아 GPU 채움, 끝난 요청 자리에 새 요청처리량↑(지연 균형)5.8, 5.13
KV 캐시 관리페이지드 KV·재사용·양자화메모리↓·처리량↑5.7~5.8
모델 병렬화(TP·PP)큰 모델을 여러 GPU로 분할메모리(모델이 한 GPU 초과 시 필수)·지연5.9, 4.13~4.14
디코딩 가속speculative decoding·메드사 등지연↓(TPOT)5.10
런치 오버헤드 제거CUDA Graphs·정적 그래프지연↓(작은 커널 다수일 때)2.11, 5.2
서빙·스케줄링모델 동시 적재·인스턴스·앙상블·라우팅처리량↑·활용률↑5.11~5.14(Triton)
하드웨어 선택추론 갈래 SKU·MIG로 분할비용↓·밀도↑4.1, 4.10, 7.5

핵심 통찰: 이 레버들은 직교가 아니라 상호작용한다. 예컨대 양자화(정밀도)는 메모리를 줄여 더 큰 배치(처리량)를 가능케 하고, 페이지드 KV(메모리)는 인플라이트 배칭(처리량)을 실용화한다. 그래서 추론 최적화는 "레버 하나 당기기"가 아니라 사면체 위에서 목표점(SLA·비용)을 향해 여러 레버를 함께 조율하는 일이다.

5.1.6 LLM 추론의 두 국면 — prefill vs decode

LLM(자기회귀 생성) 추론을 따로 떼어 보는 이유는, 한 요청 안에 성격이 정반대인 두 국면이 있기 때문이다. 이 구분이 제5부 LLM 장들(5.7~5.10)의 거의 모든 기법을 설명한다.

한 요청: 프롬프트 P(n_p 토큰) → 출력 n_g 토큰 생성.

prefilldecode
프롬프트 전체를 한 번에 forward토큰을 하나씩 n_g번 반복
모든 위치 병렬 → 큰 GEMM(행렬×행렬)매번 1토큰 → 행렬×벡터
산술 강도 높음 → 컴퓨트 바운드산술 강도 낮음 → 메모리 바운드
→ TTFT를 결정→ TPOT를 결정
KV 캐시를 '채운다'KV 캐시를 '읽고 1행 추가'

Prefill(프롬프트 처리) — 컴퓨트 바운드. 프롬프트의 모든 토큰을 동시에 처리한다. 행렬×행렬(GEMM)이라 텐서코어를 잘 채우고 산술 강도가 높다(1.10·1.11). 길이 n_p의 프롬프트는 한 번의 큰 forward. 이 단계가 TTFT를 좌우한다. 긴 프롬프트(RAG·긴 문맥)일수록 prefill이 부하가 크다.

Decode(토큰 생성) — 메모리 바운드. 자기회귀라 한 번에 토큰 하나씩 만든다. 매 스텝은 직전까지의 KV 캐시 전체 + 가중치 전체를 읽어 단 1개 토큰(배치면 배치 크기만큼)을 계산한다. 행렬×벡터에 가까워 산술 강도가 낮고 HBM 대역폭에 묶인다. n_g개 토큰을 만들려면 이 메모리 바운드 스텝을 n_g번 반복 — 그래서 긴 생성은 decode가 지배하고, TPOT가 사용자 체감 속도를 정한다.

두 국면의 비대칭이 낳는 설계 귀결:

  • 배칭의 효과가 다르다. decode는 메모리 바운드라 배치를 키우면 같은 가중치 읽기로 여러 요청을 처리 → 처리량이 거의 추가 비용 없이 오른다(5.1.4의 루프라인). prefill은 이미 컴퓨트 바운드라 배칭 이득이 작다.
  • 인플라이트(연속) 배칭(5.8)이 필요한 이유: 요청마다 출력 길이가 달라 어떤 요청은 일찍 끝난다. 정적 배치는 가장 긴 요청을 기다리며 GPU를 유휴 상태로 만들지만, 인플라이트 배칭은 끝난 요청 자리에 새 요청을 즉시 삽입해 decode GPU를 계속 채운다.
  • KV 캐시가 메모리·처리량의 핵심(5.7): decode가 매 스텝 읽는 KV 캐시는 시퀀스 길이×배치에 비례해 커진다. 이것이 동시 처리 가능한 요청 수의 상한을 정한다 → 페이지드 KV·양자화로 관리.
  • speculative decoding(5.10): decode가 메모리 바운드(연산 여유 있음)라는 점을 역이용 — 작은 모델로 여러 토큰을 추측하고 큰 모델로 한 번에 검증 → 메모리 읽기 1회로 여러 토큰 확정 → TPOT↓.
  • prefill/decode 분리(disaggregation): 같은 GPU에서 prefill(컴퓨트 바운드)과 decode(메모리 바운드)를 같이 실행하면, 한쪽에 맞춘 배치·설정이 다른 쪽엔 손해다(예: decode용 큰 배치가 프리필의 지연을 늘림). 그래서 두 국면을 서로 다른 GPU 풀로 분리해 각각 독립적으로 배치·스케일링을 최적화하는 접근이 있다 — prefill 풀은 컴퓨트에, decode 풀은 메모리 대역·동시성에 맞춰 튜닝. 대가는 두 풀 사이로 KV 캐시를 옮겨야 한다(풀 간 고속 링크 필요, 4.6~4.7). 활발히 발전 중인 서빙 아키텍처라 구현·성숙도는 시점 의존 — 이 책은 개념(왜 나뉘나)만 짚는다.

비-LLM 추론(이미지 분류·검출·임베딩 등)은 보통 단발 forward라 이 prefill/decode 이분이 없다. 그쪽은 배치·정밀도·융합이 주 레버이고 TensorRT(5.2)가 직접 맞닿는다. 제5부는 두 갈래(일반 추론=TensorRT/Triton, LLM 추론=TensorRT-LLM)를 모두 다룬다.

5.1.7 워크스루 — 추론 트레이드오프를 수치로

도구 없이, 사면체가 실제 숫자로 어떻게 움직이는지를 수계산으로 따라간다. (모든 값은 구조를 보여주는 개략 가정이다 — 실제는 실측.)

5.1.7.1 decode가 메모리 바운드임을 루프라인으로 확인

가정(개략): 어떤 디코더 LLM의 가중치가 W바이트(예: 13B 파라미터 × 2바이트(FP16) ≈ 26 GB). decode 한 스텝에서 배치 크기 B개 요청에 대해 토큰 1개씩 생성한다. (KV 캐시 읽기는 일단 무시하고 가중치만.)

  • 한 decode 스텝의 메모리 읽기 $\approx W$ (가중치 전체를 1회 읽음, 배치와 무관하게 1번)
  • 한 decode 스텝의 연산 $\approx 2 \times P \times B\,\mathrm{FLOP}$ ($P$=파라미터 수, 토큰당 ~$2P$ FLOP)
  • 산술 강도(FLOP/byte) $\approx (2 \cdot P \cdot B) / W = (2 \cdot P \cdot B) / (2 \cdot P) = B$ ($W=2P$ bytes(FP16))
  • → 산술 강도 $\approx$ 배치 크기 $B$ (FLOP/byte)

이것이 핵심이다: decode의 산술 강도는 대략 배치 크기와 같다. GPU의 루프라인 임계 강도(보통 수백 FLOP/byte 수준, 세대 의존)와 비교하면:

  • B = 1(단일 요청): 산술 강도 ≈ 1 → 임계점보다 훨씬 낮음 → 심하게 메모리 바운드. GPU 연산 유닛은 유휴 상태이고, HBM 대역폭만큼만 빠르다. 한 스텝 시간 ≈ W / (HBM 대역폭).
  • B 증가: 산술 강도 ≈ B로 올라감 → 임계점에 가까워질수록 컴퓨트 바운드로 전환 → 같은 가중치 읽기로 더 많은 토큰 → tokens/s가 거의 선형으로 증가(처리량 "무비용").
  • B가 임계점 초과: 컴퓨트 바운드 진입 → 더 키워도 tokens/s 이득은 둔화, 대신 지연·메모리만 증가.

수치 규모(개략): W ≈ 26 GB, HBM 대역폭 ≈ 3 TB/s(세대 의존, 확인 필요)라면 B=1 decode 한 스텝 ≈ 26e9 / 3e12 ≈ 8.7 ms → 약 115 tokens/s(단일 요청 상한, 개략). 같은 가중치 읽기로 B=32를 처리하면 시스템 tokens/s는 수십 배로 오르되(메모리 바운드 구간), 개별 요청의 TPOT는 큰 GEMM·경합으로 다소 늘어난다 — 처리량↑·지연↑의 사면체가 숫자로 드러난다.

정직: 위 대역폭·tokens/s는 가정에서 유도한 상한 개략치다. 실제는 KV 캐시 읽기, 어텐션, 커널 효율, 메모리 계층으로 더 낮고 모델·환경마다 다르다. 요점은 절댓값이 아니라 "B=1은 메모리 바운드, 배치가 처리량을 푼다"는 구조다.

5.1.7.2 KV 캐시 메모리 산수 — 동시 요청 수의 상한

decode가 매 스텝 읽는 KV 캐시가 동시 처리 가능한 요청 수를 정한다. 한 요청의 KV 캐시 크기(개략 공식):

  • KV bytes $\approx 2$ (K와 V) $\times L$ (레이어 수) $\times d_{\mathrm{kv}}$ (KV 헤드수 $\times$ 헤드차원) $\times S$ (시퀀스 길이) $\times \mathrm{precision\_bytes}$
  • 예(개략 가정): $L=40$, $d_{\mathrm{kv}}=5120$, $S=2048$, FP16(2B)
  • $\approx 2 \times 40 \times 5120 \times 2048 \times 2 \approx 1.7\,\mathrm{GB}$ / 요청

가용 HBM에서 가중치(W)를 빼고 남은 공간을 요청당 KV로 나누면 동시 요청 수의 상한이 나온다. 함의:

  • 시퀀스가 길수록(긴 문맥·RAG) KV가 선형으로 커져 동시 요청 수가 급감 → 처리량↓. 긴 문맥 서비스의 숨은 비용.
  • KV를 FP8/INT8로 양자화하면 절반 → 동시 요청 ~2× → 처리량↑(정밀도 약간 대가). (5.7~5.8)
  • 페이지드 KV(가상메모리식 페이지 관리)는 단편화를 없애 같은 HBM으로 더 많은 요청을 담는다 → 실효 처리량↑.
  • GQA/MQA(KV 헤드 공유, 3.7)는 KV 헤드수(→ d_kv)를 줄여 KV를 근본적으로 작게 만든다 — 그래서 최신 모델이 채택.

5.1.7.3 의사결정 워크스루 — SLA를 형상으로 풀기

상황: 챗 서비스. SLA = "p99 TTFT < 700ms, TPOT < 50ms(≈20 tokens/s 체감)". 비용 최소화가 목표.

① TPOT < 50ms 요구 → decode 스텝이 빨라야 함 → 메모리 바운드 완화 필요 정밀도: 가중치 FP8/INT-가중치 양자화로 가중치 읽기 절반 (5.9) 배치는 SLA가 허용하는 한도까지(처리량·비용↓) 키우되 TPOT 한계 감시 ② p99 TTFT < 700ms 요구 → prefill(컴퓨트 바운드) 충분히 빠른 GPU + 긴 프롬프트 주의 너무 큰 배치는 큐 대기로 TTFT 꼬리를 키움 → 인플라이트 배칭으로 균형(5.8) ③ 비용 최소 → 동시 요청 수↑ 위해 KV 양자화·페이지드 KV로 메모리 확보(5.7) 활용률↑ 위해 Triton 동적 배칭· 다중 인스턴스(5.12~5.13) ④ 검증 → 부하 생성기로 동시성을 높이며 p99 TTFT/TPOT· goodput 곡선을 그림 SLA를 깨기 직전의 동시성이 그 배포의 운영점. 거기서 $/1M토큰 계산.

요점: SLA(지연 제약) → 배치·정밀도·메모리 레버 → 측정으로 운영점 확정 의 순서. 사면체의 어느 축이 제약(constraint)이고 어느 축이 목적(objective)인지를 먼저 못 박는 것이 모든 추론 설계의 출발이다.

5.1.8 엔비디아 추론 스택의 지형 (제5부 지도)

개별 도구를 파기 전에 계층 지도를 둔다. 추론 스택은 대략 세 층이고, 각 층이 사면체의 다른 축을 주로 다룬다.

컴파일·최적화 계층 NIM이 위에 구축됨 엔진/모델을 서빙 그 아래는 우리가 배운 토대 마이크로서비스/플랫폼 계층 (제6부) NIM(6.7~6.8) — 컨테이너·OpenAI호환 API로 '제품화' 서빙 계층 (5.11~5.14, Triton Inference Server) · 모델 리포지토리·다중 백엔드 적재 · 동적/시퀀스 배칭, 다중 인스턴스, 앙상블·BLS · 처리량·활용률·운영 지표 → 사면체의 (처리량·비용) 축 TensorRT (5.2~5.6) · 일반 · ONNX→엔진, 레이어 융합 · 정밀도(INT8/FP8) 캘리브레이션 · 동적 shape·플러그인 → (지연·처리량·정밀도·메모리) TensorRT-LLM (5.7~5.10) · LLM · KV 캐시·페이지드 KV · 인플라이트 배칭 · TP/PP 병렬·speculative → LLM 특화 사면체 토대: CUDA·cuBLAS/cuDNN/CUTLASS·텐서코어· HBM·NCCL (제1~4부) — 모든 추론 커널이 결국 여기서 동작

비교 대상(5.15): vLLM·SGLang 등 오픈소스 서빙/추론 — 같은 사면체, 다른 구현.

각 계층을 한 줄로:

  • 컴파일·최적화 계층 — 모델 하나를 그 GPU에서 가장 빠른 실행 형태(엔진) 로 변환. 일반 모델은 TensorRT(5.2~5.6: 빌드·동적 shape·INT8/FP8·플러그인), LLM은 TensorRT-LLM(5.7~5.10: KV·인플라이트 배칭·양자화·병렬·speculative). 여기서 지연·정밀도·메모리 축을 주로 민다.
  • 서빙 계층 — 최적화된 엔진을 여러 모델·여러 요청을 동시에 운영. Triton(5.11~5.14: 리포지토리·동적 배칭·인스턴스·앙상블)이 처리량·활용률·비용 축을 민다. TensorRT 엔진뿐 아니라 PyTorch·ONNX·Python 백엔드도 같은 서버로 서빙.
  • 마이크로서비스 계층 — 위를 표준 API·컨테이너로 제품화(NIM, 제6부). 개발자가 모델 내부를 몰라도 OpenAI 호환 엔드포인트로 호출.
  • 오픈소스 대안(5.15) — vLLM·SGLang 등은 같은 사면체를 다른 설계로 푼다. 엔비디아 스택과 정직하게 비교해 선택하는 것이 5.15.

이 계층들은 교체할 수 있다. TensorRT 엔진을 Triton으로 서빙할 수도, PyTorch 모델을 Triton으로 바로 서빙할 수도, vLLM을 그대로 사용할 수도 있다. 제5부의 목표는 "엔비디아 도구를 외우기"가 아니라 각 계층이 사면체의 어느 축을 어떻게 푸는지를 이해해 상황에 맞게 조합·대체하는 안목이다.

5.1.9 중간 점검 (체크포인트)

  • [ ] 추론이 학습과 다른 점을 목표 함수(SLA·비용)·부하 통제·반복성 관점에서 셋 이상 설명한다.
  • [ ] TTFT·TPOT·p99·tokens/s·goodput을 정의하고, 각각을 prefill/decode/배칭 중 무엇이 지배하는지 연결한다.
  • [ ] 사면체 네 축을 대고, "배치를 키우면 무엇이 좋아지고 무엇이 나빠지나"를 루프라인 언어로 설명한다.
  • [ ] prefill(컴퓨트 바운드)과 decode(메모리 바운드)가 왜 다른지, 그 비대칭이 인플라이트 배칭·KV 관리·speculative를 왜 부르는지 말한다.
  • [ ] 주어진 SLA에서 어떤 레버(배치·정밀도·KV·배칭)를 어떤 순서로 당길지 워크스루를 짠다.

증상→의심: 단일 요청 tokens/s가 낮고 GPU 활용률도 낮다 → decode 메모리 바운드(정상) + 배칭 부재 → 동적/인플라이트 배칭으로 GPU 채우기. 처리량은 좋은데 p99가 SLA를 깬다 → 배치 과대로 큐 꼬리 증가 → 배치 상한·인플라이트 배칭으로 균형. 긴 문맥 요청에서 동시 처리 수가 급감 → KV 캐시 폭증 → 페이지드/양자화 KV·GQA. GPU는 한가한데 느리다 → 작은 커널 런치 오버헤드 → CUDA Graphs·융합(2.11·5.2).

5.1.10 트레이드오프·대안 — 어떤 배포를 고르나

추론 배포는 단일 정답이 없다. 대표 갈래를 ①②③로 펼친다.

① "프레임워크 단독"(PyTorch / torch.compile 직접 서빙).

  • 누구에게: 프로토타입·낮은 트래픽·잦은 모델 교체·연구. 최적화보다 개발 속도가 중요할 때.
  • 장: 변환 단계 없음, 디버깅 쉬움, 유연. 단: 그래프 융합·정밀도·배칭 최적화가 약해 비용/지연이 높다. 트래픽이 커지면 비효율이 누적.

② 컴파일 최적화(TensorRT / TensorRT-LLM) + 서빙(Triton).

  • 누구에게: production·일정 트래픽 이상·SLA·비용 압박. 모델이 안정적이고 효율이 곧 돈일 때.
  • 장: 융합·정밀도·배칭으로 지연·처리량·비용을 크게 개선, 운영 지표·다중 모델. 단: 빌드·캘리브레이션·동적 shape·버전 관리의 엔지니어링 비용, 모델 변경 시 재빌드.

③ 오픈소스 LLM 서빙(vLLM·SGLang 등, 5.15).

  • 누구에게: LLM 중심, 빠른 모델 지원·커뮤니티·이식성을 중시, 멀티-하드웨어 가능성.
  • 장: 페이지드 어텐션·연속 배칭이 기본 내장, 모델 지원 빠름, 설치 간편. 단: 특정 모델·특정 GPU에서 TRT-LLM 대비 최대 성능은 케이스마다 다름 → 실측 비교 필요.
결정 질문"예"면 기우는 쪽
트래픽이 작고 모델이 자주 바뀌나?① 프레임워크 직접
SLA·비용 압박이 크고 모델이 안정적인가?② TensorRT(-LLM)+Triton
LLM이고 모델 지원 속도·이식성이 중요한가?③ 오픈소스(또는 ②와 실측 비교)
비-LLM(비전·임베딩) 다수 모델을 한 서버에?② Triton(다중 백엔드)
내부에서 직접 운영하기 싫다(완제품 API)?NIM(제6부)

견해: "먼저 측정, 그다음 컴파일." 트래픽이 의미 있게 오르기 전에는 ①로 빠르게 출시해 실제 부하·SLA·시퀀스 분포 데이터를 모으고, 비용/지연이 아플 때 ②·③를 그 데이터로 벤치마크해 전환하는 것이 대개 합리적이다. 처음부터 TRT-LLM 파이프라인을 구축한 뒤 모델이 매주 바뀌면 빌드 비용이 부담으로 작용한다. 단, 트래픽이 클 것이 확실한 대규모 서비스는 처음부터 ②·③로 설계할 가치가 있다.

비엔비디아 정직: 오픈소스(vLLM·SGLang·TGI 등)와 다른 가속기(클라우드 자체 추론 칩 등)는 같은 사면체를 다르게 푼다. 엔비디아 스택의 강점은 컴파일러(TRT)·LLM 런타임(TRT-LLM)·서버(Triton)·마이크로서비스(NIM)가 하나의 생태계로 맞물리고 최신 하드웨어 기능(FP8/FP4·TMA)을 빨리 흡수한다는 데 있다. 그러나 특정 모델·SLA에서의 우열은 반드시 실측으로 정한다 — 벤치마크 슬라이드가 아니라 당신의 워크로드로.

5.1.11 흔한 함정

  • 평균만 보고 꼬리를 놓친다. 평균 지연이 좋아도 p99가 SLA를 깨면 실패. 배치 확대는 평균 처리량을 높이며 꼬리를 키울 수 있다 — 항상 분위수와 goodput으로 본다.
  • prefill과 decode를 하나로 취급. TTFT(prefill)와 TPOT(decode)는 병목이 달라 최적화도 다르다. "추론이 느리다"를 두 국면으로 분할해 진단하지 않으면 잘못된 레버를 조정한다.
  • 배치를 맹목적으로 키운다. 처리량은 오르지만 지연·메모리(KV)·OOM 위험이 따라온다. 메모리 바운드 구간을 벗어나면 처리량 이득도 둔화 — 배치는 SLA가 허용하는 최대까지만.
  • 양자화를 정밀도 검증 없이 켠다. FP8/INT8/FP4는 메모리·속도를 주지만 모델·태스크에 따라 품질이 무너질 수 있다. 대표 평가셋으로 정확도를 측정하고 켜야 한다(5.4~5.5). "양자화=무비용"이 아니다.
  • 벤치마크 조건을 숨긴다(또는 안 본다). 시퀀스 길이·동시성·배치·정밀도·GPU·SW 버전이 빠진 tokens/s는 비교 불가. 남의 수치도, 내 수치도 조건과 함께.
  • 런치 오버헤드를 GPU 성능 부족으로 오해. 작은 커널이 많은 모델은 GPU가 한가해도 느리다 — CUDA Graphs·융합(2.11·5.2)이 답이지 더 큰 GPU가 아니다.
  • 컴파일 비용을 무시하고 TRT부터 설치한다. 모델이 자주 바뀌면 재빌드·캘리브레이션·동적 shape 관리가 큰 부담. 트래픽·안정성이 받쳐줄 때 도입.
  • KV 캐시·긴 문맥의 메모리 비용 간과. 동시 요청 수 상한은 가중치가 아니라 KV 캐시가 정할 때가 많다. 긴 문맥 서비스는 KV 폭증을 설계 단계에서 계산해야 한다.

5.1.12 연습문제

연습 1 (지표 매핑). 다음 SLA 항목을 각각 prefill / decode / 배칭·스케줄링 중 무엇이 주로 결정하는지와 그 이유: (a) p99 TTFT < 300ms, (b) TPOT < 40ms, (c) 시스템 tokens/s 극대화, (d) 동시 1000요청에서 p99 유지.

정답

(a) prefill — 첫 토큰까지는 프롬프트 전체 forward(컴퓨트 바운드)가 지배. 긴 프롬프트·느린 prefill이 TTFT 꼬리를 만든다. (b) decode — 토큰 간 간격은 자기회귀 메모리 바운드 스텝의 속도(가중치·KV 읽기). 양자화·KV 관리가 직접 영향. (c) 배칭·스케줄링 — tokens/s는 GPU를 얼마나 채우느냐 = 인플라이트/동적 배칭으로 decode를 메모리 바운드 구간에서 다요청으로 채우는 일. (d) 배칭·스케줄링(+메모리) — 높은 동시성에서 p99를 지키려면 큐·배치 상한·KV 메모리(동시 요청 수 한계)를 함께 관리. prefill/decode 속도만으론 부족.

연습 2 (루프라인). decode가 메모리 바운드라는 것을, 산술 강도와 배치 크기의 관계로 설명하라. 배치를 1→16으로 키울 때 (a) 시스템 tokens/s, (b) 개별 요청 TPOT, (c) HBM에서 읽는 가중치 바이트가 각각 어떻게 변하는가.

정답

decode 한 스텝의 산술 강도 ≈ 배치 크기 B(FLOP/byte). B가 작으면 GPU 루프라인 임계점보다 훨씬 낮아 HBM 대역폭에 묶임(연산 유닛은 유휴 상태이고 가중치 읽기 시간이 지배). (a) tokens/s: 메모리 바운드 구간이라 거의 선형 증가(같은 가중치 읽기로 16배 토큰 처리). (b) 개별 TPOT: 약간 증가(더 큰 GEMM·경합)하되 메모리 바운드 구간에선 완만 — 그래서 처리량이 "무비용"처럼 보임. (c) 가중치 바이트: 거의 불변(가중치는 배치와 무관하게 스텝당 1회 읽음) — 이것이 배칭이 효율적인 물리적 이유. 단, KV 캐시 읽기는 배치에 비례해 증가.

연습 3 (KV 메모리). 어떤 LLM의 요청당 KV 캐시가 시퀀스 2K에서 1.6 GB라고 하자(개략). (a) 시퀀스를 8K로 늘리면 KV는? (b) 가용 KV 공간이 48 GB일 때 2K·8K 각각 동시 요청 수 상한은? (c) KV를 FP16→FP8로 바꾸면? 이 결과가 "긴 문맥 서비스는 비용이 크다"는 말과 어떻게 연결되나.

정답

(a) KV는 시퀀스 길이에 선형 → 8K는 약 6.4 GB(4배). (b) 2K: 48/1.6 ≈ 30요청, 8K: 48/6.4 ≈ 7~8요청. (c) FP8은 바이트 절반 → 2K ≈ 0.8 GB(동시 ~60), 8K ≈ 3.2 GB(동시 ~15). 연결: 동시 처리 가능한 요청 수(=처리량·비용 효율)는 흔히 가중치가 아니라 KV 캐시가 정하고, KV는 시퀀스 길이에 비례하므로 긴 문맥은 동시성을 낮춰 요청당 비용을 높인다. 그래서 페이지드 KV·KV 양자화·GQA·문맥 길이 정책이 긴 문맥 서비스의 핵심 레버다.

연습 4 (배포 선택). 다음에 5.1.10의 ①②③(프레임워크 직접 / TRT(-LLM)+Triton / 오픈소스 LLM 서빙) 중 어디서 시작할지와 이유: (a) 주간 트래픽 수천 건, 모델 매주 교체하는 사내 실험 챗봇, (b) 초당 수천 요청, 고정 비전 모델 10종을 한 서버에서 추론, (c) 대형 오픈웨이트 LLM을 가능한 낮은 비용으로 대규모 서비스.

정답

(a) ① 프레임워크 직접 — 트래픽 작고 모델이 자주 바뀌어 컴파일·재빌드 비용이 손해. 개발 속도 우선, 나중에 트래픽 데이터로 재평가. (b) ② Triton(+TensorRT) — 다수 비전 모델을 한 서버에서 다중 백엔드·동적 배칭으로 활용률 극대화, TensorRT로 융합·INT8. production·고QPS·고정 모델에 정확히 부합. (c) ③ 오픈소스 vs ② TRT-LLM 실측 비교 — 둘 다 페이지드 KV·연속 배칭을 제공. 대규모·비용 민감이면 둘을 당신의 모델·SLA로 벤치마크해 tokens/s·$/토큰이 나은 쪽. "슬라이드 수치"로 단정 금지.

연습 5 (사면체 추론). 한 팀이 "양자화로 메모리를 절반 줄였더니 처리량도 올랐다"고 보고했다. 이것이 사면체의 어느 축들이 함께 움직인 것인지, 메커니즘과 함께 설명하고, 이때 반드시 확인해야 할 대가는 무엇인지 답하라.

정답

메모리↓ → 처리량↑ 가 함께 움직였다. 메커니즘: ① 가중치(또는 KV) 바이트가 절반 → 메모리 바운드 구간에서 읽을 바이트 감소로 스텝이 빨라짐(처리량↑), ② 메모리 절감으로 더 큰 배치/더 많은 동시 요청이 가능 → 처리량 추가 상승. 반드시 확인할 대가: 정밀도(정확도) 축의 손실. FP8/INT8/FP4는 모델·태스크에 따라 품질이 떨어질 수 있으므로, 대표 평가셋으로 정확도를 측정해 SLA 품질 기준을 통과하는지 확인해야 한다(5.4~5.5). 정확도 검증 없는 "처리량↑"은 미완의 보고다.

5.1.13 요약 · 다음 장

  • 추론은 학습과 목표가 다르다 — 정해진 SLA(특히 p99) 안에서 처리량·비용을 최적화하는, 사용자 부하가 통제하는 무한 반복 게임이다. 추론비는 모델 TCO를 지배한다.
  • 모든 결정은 사면체 트레이드오프(지연·처리량·정밀도·메모리) 위에 있고, 그 중심 노브는 배치 크기다. 물리적 근거는 루프라인 — 추론의 많은 부분, 특히 LLM decode가 메모리 바운드다.
  • LLM 추론은 prefill(컴퓨트 바운드, TTFT) 과 decode(메모리 바운드, TPOT) 의 비대칭으로 갈리고, 이 비대칭이 인플라이트 배칭·KV 관리·speculative decoding을 부른다.
  • 최적화 레버(그래프 융합·양자화·배칭·KV·병렬·디코딩·서빙)는 상호작용하며, 엔비디아 스택은 컴파일(TensorRT/TRT-LLM) → 서빙(Triton) → 마이크로서비스(NIM) 로 계층화된다. 도구를 외우지 말고 각 계층이 사면체의 어느 축을 푸는지로 이해한다.
  • 정직: 모든 수치는 실측으로 확정하고, 양자화는 정확도 검증과 함께 켜며, 배포 선택은 당신의 워크로드 벤치마크로 정한다.

다음 장: 5.2 TensorRT I — ONNX→엔진 빌드 흐름. 사면체의 [지연·정밀도·메모리] 축을 미는 첫 도구를 직접 다룬다. 학습된 모델(ONNX 등)을 그 GPU에 특화된 최적화 엔진으로 컴파일하는 파이프라인 — 레이어 융합·커널 오토튜닝·정밀도 선택이 빌드 시점에 어떻게 일어나고, 어떻게 빌드·실행·검증하는지를 실습으로 따라간다.