LLM 추론 서빙, 무엇부터 봐야 할까?
프로덕션 LLM 서빙의 병목은 계산이 아니라 메모리 대역폭이다. KV 캐시를 어떻게 관리하느냐, 요청을 어떻게 묶느냐, GPU 메모리를 몇 %까지 채울 것인지—이 세 가지 설계 선택이 처리량과 지연 시간의 격차를 결정한다. 우리는 이 분석에서 추론 서빙 시스템의 내부 구조와 각 설계 지점의 트레이드오프를 뜯어본다.
KV 캐시가 처리량의 천장을 정하는 이유?
KV 캐시의 메모리 점유가 추론 서빙의 가장 중요한 제약이다.
LLM 추론에서 각 요청은 입력 시퀀스(프롬프트)와 생성 중인 출력 시퀀스의 모든 토큰에 대해 Key와 Value 벡터를 저장해야 한다. 예를 들어 13B 모델의 경우 각 토큰마다 약 104바이트(int8 양자화 기준)가 필요하고, 컨텍스트 길이 2,048이라면 단일 요청당 약 200MB 이상의 KV 캐시를 차지한다. A100 80GB 같은 고사양 GPU에서도 배치 크기는 수십 개로 제한된다.
이 제약은 선택의 연쇄를 만든다.
- 전체 메모리의 60~75%를 KV 캐시에 할당하는 것이 일반적 관행이다(모델 가중치는 2030%, 계산 버퍼는 515%).
- 컨텍스트 길이가 길어질수록 배치당 처리할 수 있는 요청 수가 지수적으로 감소한다.
- 요청마다 다른 컨텍스트 길이를 가지면 메모리 단편화가 심화되어 실제 배치 크기는 이론값보다 낮아진다.
이를 해결하려면 동적 배치 크기 조정과 토큰 단위 스케줄링(후술)이 필수다.
연속 배칭은 왜 기존 배칭을 대체했을까?
연속 배칭(Continuous Batching)은 기존의 고정 배치 방식과 달리 요청의 입출력 길이가 다를 때 각 요청의 생성 단계만큼만 연산을 수행한다.
전통적 배칭의 문제:
- 배치 내 모든 요청이 같은 단계까지 진행되어야 함 → 짧은 요청이 끝나도 대기
- 배치당 고정된 시간 간격 → 새 요청이 도착해도 다음 배치까지 대기
연속 배칭의 구조:
- 각 요청이 독립적으로 생성 단계를 진행
- 요청이 끝나면 즉시 배치에서 제거 → 메모리 즉시 해제
- 새 요청을 언제든 합류 가능 → 대기 시간 감소
- 토큰 단위로 GPU 작업을 스케줄 → 메모리 단편화 감소
실제 처리량 개선 폭은 상당하다. 고정 배치 방식 대비 동일 하드웨어에서 2~4배의 처리량 증가가 보고되는데, 이는 GPU 이용률이 높아지고 메모리 낭비가 줄기 때문이다(컨텍스트 길이 분산이 클수록 차이는 커짐).
다만 구현 복잡도가 높다. 각 요청의 위치를 추적하고, KV 캐시 내에서 요청별 슬롯을 동적으로 할당·회수해야 한다. 또한 GPU 커널이 가변 시퀀스 길이를 효율적으로 처리할 수 있어야 한다.
프리픽스 캐싱은 언제 필요한가?
프리픽스 캐싱은 요청들 사이에서 공유되는 프롬프트의 앞부분(또는 시스템 프롬프트)에 대한 KV 캐시를 재사용하는 기법이다.
효과가 극대화되는 시나리오:
- 동일한 시스템 프롬프트가 수천 개의 요청에 사용되는 경우 (대규모 채팅 서비스)
- RAG 시스템에서 동일한 문서 청크가 여러 쿼리의 맥락으로 반복되는 경우
- 프롬프트 템플릿이 고정되고 변수 부분만 바뀌는 경우
메모리 절감 규모:
프리픽스가 컨텍스트의 70%를 차지하면, 동일 프리픽스 100개 요청의 KV 캐시는 기존 대비 약 1 + 0.3 × (n-1) 배로 감소한다(n은 요청 수). 100개 요청이라면 단순 계산상 약 30배 메모리 절감.
구현상 주의점은 캐시 일관성이다. 프리픽스가 서로 다른 요청에서 수정되거나 추가되면 별도 캐시 슬롯 관리가 필요하고, 이는 메모리 관리 복잡도를 높인다. 또한 프리픽스 경계 자체가 토큰 단위로 정렬되어야 하므로, 임의의 길이 프리픽스는 실제 캐시 효율을 감소시킨다.
양자화는 처리량을 얼마나 높이나?
KV 캐시 양자화(int8, fp8, int4)는 메모리 점유를 줄여 더 많은 요청을 동시에 처리할 수 있게 한다.
메모리 감소:
- fp32 → int8: 75% 감소
- fp32 → int4: 87.5% 감소
이론적으로 배치 크기는 메모리 감소 비율만큼 증가 가능하다. 즉, int8 캐시는 fp32 대비 4배 배치에서 동일한 메모리 사용량을 유지하면서 처리량을 대폭 높인다.
품질 손실:
양자화 오차는 생성된 토큰의 정확도에 직접 영향을 미친다. 연구 데이터에 따르면:
- int8 KV 캐시: 대부분의 작업에서 1% 이하의 정확도 손실
- int4 KV 캐시: 작업과 모델에 따라 2~5% 손실 가능
다만 측정 방식이 중요하다. 정확도는 기준 모델(fp32)과 정량적으로 비교할 때만 의미 있고, 절대 성능 저하는 작업 난도(MMLU, GSM8K 등의 벤치마크 선택)에 따라 달라진다.
실제 운영:
양자화된 KV 캐시를 사용하더라도 모델 가중치는 보통 fp16 또는 int8로 유지된다(연산 정확도 때문). 따라서 메모리 절감은 전체 추론 서빙 메모리의 40~50% 수준에 머물 수 있다.
처리량 최적화와 지연 시간 사이의 선택은 어디서 결정되나?
고처리량 시스템과 저지연 시스템의 설계는 상반된다.
| 차원 | 고처리량 우선 | 저지연 우선 |
|---|---|---|
| 배치 크기 | 크게(32~128) | 작게(1~8) |
| 배치 대기 시간 | 길게(수십~수백ms) | 짧게(1~10ms) |
| KV 캐시 할당 | 최대 80%까지 | 여유있게 40~60% |
| 프리픽스 캐시 | 적극 활용 | 단순 구조 선호 |
| 양자화 | 필수 | 선택적 |
선택의 지점:
- 인터랙티브 애플리케이션(채팅): 첫 토큰 지연(TTFT, Time To First Token) < 100ms 요구 → 배치 크기 10 이하, 배치 대기 1~5ms
- 배치 추론 워크로드(요약, 번역): 처리량 최대화 → 배치 크기 128+, 대기 시간 무시
- 하이브리드: SLO 기반 동적 배치(지연 도달 시점에 배치 발송)
2026년 기준, 대부분 프로덕션 시스템은 이 양쪽 사이에서 타협한다. 예를 들어 배치 크기 1632, 배치 타임아웃 1050ms 같은 설정이 일반적이다.
GPU 메모리 압박을 제어하는 기준은?
GPU 메모리 할당 정책은 추론 품질과 처리량 사이의 직접적 트레이드오프다.
할당 비율의 의미:
- 80% 할당: KV 캐시와 배치 크기를 최대화. 계산 버퍼가 부족해 커널 성능 저하 가능(재컴파일, 스필 발생). OOM 위험도 증가.
- 70% 할당: 일반적 운영 범위. 계산 버퍼 충분, 메모리 할당/해제 예측 가능.
- 60% 이하: 안정성 우선. 메모리 단편화의 여유, 긴급 상황 대응 가능.
동적 조정:
- 요청 큐 길이가 길어지면 배치 크기를 줄이고 배치 빈도를 높임 → 처리 시간 연장, 지연 감소
- 요청 도착률이 낮으면 배치를 크게 만들되 대기 시간을 길게 → 처리량 감소, 지연 증가
실제 구현은 메모리 사용률 모니터링(현재 할당 / 전체 VRAM)에 기반한 피드백 루프로 동작한다.
서빙 엔진 선택의 기준: 정교함과 오버헤드의 경계
이 분석에서는 제품이 아니라 아키텍처 선택을 본다. 프로덕션 서빙 시스템은 크게 두 가지 복잡도 수준으로 나뉜다.
높은 복잡도(연속 배칭 + 동적 메모리 관리):
- 요청별 KV 캐시 슬롯을 동적으로 할당/해제
- 토큰 단위 스케줄링으로 GPU 이용률 최대화
- 처리량: 초당 수천 토큰 가능(A100 기준, 배치 크기 64+, 컨텍스트 길이 1k)
- 지연: 배치 타임아웃 20~50ms 기본값
중간 복잡도(정적 메모리 블록):
- 요청당 미리 정의된 메모리 블록 할당
- 배치 단위 스케줄링(연속 배칭은 지원하되 단순화)
- 처리량: 초당 수백천 토큰(배치 크기 1632)
- 지연: 배치 타임아웃 10~30ms
선택 기준은 요청 특성과 운영 역량이다.
- 요청이 매우 이질적(길이 편차 큼): 높은 복잡도 필요
- 요청이 동질적(길이 편차 작음): 중간 복잡도도 충분
- 모니터링/디버깅 역량 낮음: 중간 복잡도 권장
흔히 간과되는 실제 병목: 메모리 단편화와 재할당 오버헤드
벤치마크에서는 배치 크기와 이론적 처리량으로 평가되지만, 실제 운영에서는 메모리 관리 오버헤드가 무시 못한다.
단편화의 원인:
- 요청마다 다른 시퀀스 길이 → KV 캐시 슬롯 크기 불일치
- 요청이 끝날 때마다 메모리 해제 → 캐시 내 빈 공간 증가
- 동적 배치에서 요청이 수시로 합류/퇴출 → 메모리 할당/해제 반복
측정 가능한 영향:
메모리 할당/해제 호출이 초당 수백 회 발생하면, GPU 메모리 버스 경합과 커널 런칭 오버헤드로 처리량이 5~15% 감소할 수 있다. 이는 배치 크기가 작거나 컨텍스트 길이 분산이 클수록 심하다.
실제 운영 관행:
- 메모리 풀을 미리 할당(pre-allocation)하고 요청에 재할당 → 할당 오버헤드 제거
- 컨텍스트 길이별로 별도 큐 유지 → 단편화 감소
- 주기적 가비지 컬렉션(몇 초마다 미사용 블록 재정리) → 메모리 압축
이를 측정하려면 GPU 프로파일러로 메모리 할당 호출 빈도와 커널 런칭 시간을 추적해야 한다.
핵심 정리
-
KV 캐시는 추론 서빙의 가장 큰 메모리 소비자이며, 배치 크기의 직접적 제약이다. 전체 메모리의 60~75%를 할당하는 것이 일반적이다.
-
연속 배칭은 기존 고정 배치 대비 2~4배 처리량 향상을 가능하게 하지만, 메모리 관리 복잡도가 높다.
-
프리픽스 캐싱은 공유 프롬프트 비율이 높을 때(70% 이상) 메모리를 급격히 절감하지만, 구현 난도와 캐시 일관성 관리 필요.
-
KV 캐시 양자화(int8)는 메모리를 75% 절감하여 배치 크기를 4배 확대할 수 있으나, 대부분 시스템에서는 전체 메모리 절감이 40~50%에 머문다.
-
처리량 최적화와 저지연 시스템은 배치 크기, 배치 대기 시간, 메모리 할당 전략이 상반된다. 선택은 애플리케이션 SLO(Service Level Objective)에 따른다.
-
메모리 단편화와 할당 오버헤드는 벤치마크에 드러나지 않지만 실제 처리량을 5~15% 감소시킬 수 있다.
자주 묻는 질문
KV 캐시를 줄이려면 컨텍스트 길이를 제한해야 하나?
컨텍스트 길이 제한은 메모리 사용을 선형으로 줄이지만, 애플리케이션 기능성을 해친다. 대신 양자화, 프리픽스 캐싱, 메모리 재할당 정책 최적화를 우선 시도하는 게 낫다.
배치 크기는 얼마로 설정해야 하나?
인터랙티브 서비스는 816, 배치 추론은 64128을 기준으로 삼는다. 최적값은 하드웨어, 모델 크기, 컨텍스트 길이에 따라 달라지므로 부하 테스트로 측정해야 한다.
첫 토큰 지연을 개선하려면?
첫 토큰 지연은 주로 배치 대기 시간과 프롬프트 처리 시간에 의해 결정된다. 배치 타임아웃을 짧게(1~5ms), 또는 프롬프트 토큰을 별도 GPU에서 병렬 처리하면 개선된다.
int4 양자화를 KV 캐시에 쓸 때 품질 손실이 크나?
작업 난도에 따라 다르지만, 일반적으로 2~5% 정확도 손실이 보고된다. MMLU 같은 지식 기반 작업은 손실이 크고, 창작 작업은 적다. 실제 운영에서는 벤치마크로 검증 필수.
프리픽스 캐싱의 효율이 낮은 경우는?
프리픽스가 전체 컨텍스트의 30% 이하일 때 메모리 절감 효과가 미미하다. 또한 프리픽스가 요청마다 다르면(동적 프롬프트) 캐시 hit rate가 떨어져 오버헤드만 증가한다.
메모리 할당률을 어떻게 모니터링할까?
GPU 메모리 사용률(nvidia-smi) 모니터링은 부정확하다. 서빙 엔진 내부 메모리 할당 추적(CUDA memory profiler)이나 엔진 자체의 메모리 메트릭(할당된 슬롯 수, 활성 요청 수)으로 실시간 모니터링하는 게 맞다.
연속 배칭을 구현할 때 가장 어려운 부분은?
KV 캐시 슬롯 관리와 요청별 인덱싱이 핵심이다. 특히 슬롯을 효율적으로 재할당하면서 동시에 GPU 커널이 각 요청의 위치를 정확히 추적해야 하므로, 구현과 검증에 상당한 공수가 들어간다.