LLM 서빙 · 서빙이 학습과 다른 이유 · 이론
prefill 과 decode 는 다른 일이다
한 줄 요약
LLM 추론은 두 국면으로 나뉜다. 프롬프트를 한꺼번에 처리하는 prefill 은 연산 병목이고, 토큰을 하나씩 만드는 decode 는 메모리 대역폭 병목이다.
왜 이게 필요했나
학습에서는 하나의 지표만 봐도 됩니다 — 초당 처리 토큰 수입니다. 서빙에서는 그것으로 부족합니다. 사용자가 체감하는 것은 두 가지이고, 둘은 서로 다른 원인에서 나옵니다.
TTFT(Time To First Token)는 요청을 보낸 뒤 첫 토큰이 도착하기까지의 종단 간 시간입니다. 대화형 서비스에서 200ms 를 예시 SLO 로 둘 수 있지만, 실제 목표는 제품 경험, 모델 크기, 프롬프트 길이와 배포 환경을 기준으로 정해야 합니다. TTFT 에는 네트워크, 요청 큐, 스케줄링, 토큰화와 prefill 이 모두 포함됩니다. 긴 프롬프트에서는 전체 어텐션을 계산하는 prefill 이 주요 구성요소가 되기 쉽지만, 항상 TTFT 전체를 단독으로 결정하는 것은 아닙니다.
ITL 또는 TPOT(Inter-Token Latency, Time Per Output Token)은 그 뒤 토큰이 하나씩 나오는 간격입니다. 사람이 읽는 속도보다 빠르면 됩니다. 이 값은 decode 단계가 결정합니다.
두 국면의 병목이 다르다는 것이 핵심입니다. prefill 은 행렬 곱이 크게 일어나므로 연산 능력에 묶입니다. decode 는 토큰 하나마다 모델 가중치 전체를 한 번씩 읽어야 하므로 메모리 대역폭에 묶입니다. 그래서 decode 는 배치를 키워도 시간이 별로 안 늘어납니다 — 어차피 가중치를 읽는 시간이 지배하기 때문입니다. 이 성질이 배칭이 극적으로 효과적인 이유입니다.
어떻게 동작하나
KV 캐시가 새로 등장하는 자원입니다. 트랜스포머는 각 토큰에서 이전 모든 토큰의 키와 값을 참조합니다. 매번 다시 계산하면 O(n²) 이므로, 계산해 둔 키와 값을 메모리에 쌓아 둡니다. 이것이 KV 캐시입니다.
문제는 크기입니다. 공식은 이렇습니다.
KV 바이트 = 2 x 레이어 수 x 은닉 차원 x 시퀀스 길이 x 배치 x dtype 바이트7B 모델(32층, 은닉 4096)을 fp16 으로 4K 컨텍스트, 배치 1 로 돌리면 2 x 32 x 4096 x 4096 x 1 x 2 = 2GiB 입니다. 컨텍스트를 128K 로 늘리면 64GiB 입니다. 모델 가중치가 14GB 인데 KV 캐시가 64GB 를 먹습니다. 배치 8 이면 512GiB 로 GPU 한 장에 절대 안 들어갑니다.
그래서 서빙 시스템의 설계가 대부분 KV 캐시 관리 이야기가 됩니다. PagedAttention 은 KV 캐시를 고정 크기 블록으로 나눠 OS 의 가상 메모리처럼 비연속 할당을 가능하게 해서 내부 단편화를 줄입니다. GQA 는 모델의 KV 헤드 수에 따라 키·값 헤드를 그룹으로 공유해 캐시 크기를 줄입니다. KV 캐시 양자화(INT8, INT4)는 dtype 바이트를 줄이지만 지원 여부와 정확도 영향은 서버·모델별로 확인해야 합니다.
현장에서 만나는 모습
측정에서 자주 하는 실수가 TTFT 와 ITL 을 평균으로 뭉개는 것입니다. 총 지연을 총 토큰 수로 나누면 두 지표가 섞여 아무것도 못 봅니다. 반드시 따로 재고 각각의 p50, p95, p99 를 봐야 합니다.
그리고 GPU 메모리 사용률 설정값(예: vLLM 의 gpu_memory_utilization)이 중요합니다. 일부 전용 GPU 환경에서는 0.90 안팎을 출발점으로 삼지만, 모델 서버 버전·양자화·CUDA 그래프와 공존 프로세스에 따라 안전한 값은 달라집니다. 너무 높이면 CUDA OOM 이 나고, 너무 낮추면 KV 캐시에 쓸 공간이 줄어 동시 처리량이 떨어지므로 실제 피크 부하로 검증해야 합니다.
다음 확인에서 볼 것
먼저 퀴즈에서 TTFT 와 ITL 의 병목, KV 캐시 용량 조건을 구분합니다. 다음 모듈부터 토큰 스트리밍 서버를 직접 만들고, 배칭 스케줄러를 시뮬레이션하고, KV 캐시 계산기를 작성합니다.