2026년 10월의 모델 서빙에서 엔진은 사실상 정해졌습니다(vLLM, SGLang). 설계의 승부는 엔진 바깥에서 납니다. 이 글은 요청 하나가 들어와 답이 나가기까지의 여정을 식당 운영에 빗대어 따라가며, 지금 통하는 설계와 그 근거를 정리합니다. 응답 시간을 대기·읽기·쓰기로 나눠 재는 법, 최대 처리량이 아니라 굿풋으로 용량을 세는 법, 엔진의 기본값(동시 처리 1,024개, 대기열 무제한)을 그대로 쓰면 안 되는 이유, 같은 대화를 같은 서버로 보내는 것만으로 처리량이 두 배가 되는 라우팅, 받을 수 없는 요청을 거절하는 입장 제어, GPU 사용률이 아닌 확장 신호, 수십 GB 모델의 콜드 스타트를 줄이는 방법, 세대별 양자화 선택, 그리고 규모별 구성까지. vLLM 0.30과 llm-d 0.10의 문서, 그리고 Together·Modal·Baseten·토스·네이버 등이 올해 공개한 운영 사례의 수치를 근거로 삼았습니다. 직접 움직여 보는 위젯 6개가 들어 있습니다.
모델 서빙(serving)은 학습이 끝난 모델을 실제 요청에 답하게 만드는 일입니다. 이름부터가 식당에서 왔고, 실제로 식당과 닮았습니다. 요리사(GPU)가 아무리 뛰어나도 주문을 받는 방식, 자리를 배정하는 방식, 손님이 몰릴 때의 대처가 엉망이면 그 식당은 느리고 비싸고 자주 문을 닫습니다.
2026년 10월의 서빙에는 이전과 다른 점이 하나 있습니다. 요리사와 주방 기구는 거의 정해졌습니다. 엔진은 vLLM과 SGLang으로 모였고, 쿠버네티스 위에서 여러 대를 묶는 방식도 한 방향으로 수렴했습니다. 그래서 설계의 무게가 "어떤 엔진을 쓸까"에서 "엔진 바깥을 어떻게 짤까"로 옮겨 왔습니다. 올해 공개된 장애 사례와 성능 개선 사례를 모아 보면, 거의 전부가 엔진 속이 아니라 엔진 앞뒤에서 벌어진 일입니다.
이 글은 요청 하나가 들어와서 답이 나가기까지의 여정을 따라가며, 정거장마다 지금 통하는 설계와 그 이유를 정리합니다. 수치와 설정 이름은 2026년 10월 3일 기준으로 각 프로젝트의 문서와 공개된 운영 사례에서 확인했습니다. 서빙을 빌릴지 직접 할지의 판단은 AI 플랫폼 특집의 서빙 사다리에서, 어떤 GPU에 올릴지는 GPU 고르는 법에서 다뤘으니, 이 글은 직접 서빙하기로 한 뒤의 설계에 집중합니다.
✅
2026년 10월의 기본 설계, 열 줄 요약.
① 엔진은 vLLM(또는 SGLang)으로 정해졌습니다. 고민할 곳은 엔진 바깥입니다.
② 응답 시간을 대기·읽기·쓰기로 나눠 재고, 용량은 최대 처리량이 아니라 굿풋으로 셉니다.
③ 엔진의 기본값은 운영값이 아닙니다. vLLM의 기본은 동시 처리 1,024개에 대기열 무제한입니다. 상한을 겁니다.
④ 가중치는 H100·H200이면 8비트(FP8), B200이면 4비트(NVFP4)가 기본입니다. 에이전트 서비스의 4비트는 내 평가로 확인합니다.
⑤ 같은 대화는 같은 서버로 보냅니다. 배정 규칙만 바꿔 처리량이 두 배, 첫 토큰 시간이 154초에서 0.9초가 된 측정이 있습니다.
⑥ 넘치는 요청은 엔진 밖에서 줄 세우고, 한도를 넘으면 바로 거절합니다.
⑦ 자동 확장의 신호는 진행 중인 요청 수와 대기열입니다. GPU 사용률은 쓰지 않습니다.
⑧ 급증은 확장으로 막을 수 없습니다. 새 서버는 분 단위로 뜹니다. 여유분과 빠른 시작으로 대비합니다.
⑨ 모델과 엔진도 배포물입니다. 버전을 고정하고, 일부 트래픽으로 먼저 내보내고, 몇 시간짜리 시험을 돌립니다.
⑩ 피크에 맞춰 산 GPU의 평균 사용률은 15~20%입니다. 늘 있는 부하만 전용으로 받고 나머지는 빌립니다.
설계는 측정에서 시작합니다. "느리다"는 말은 처방을 내릴 수 없는 진단입니다. 응답 한 번은 성격이 전혀 다른 세 구간으로 이뤄지기 때문입니다.
구간
식당으로 치면
길어지는 이유
줄이는 방법
대기
문 앞에서 줄 서기
용량보다 요청이 많음
입장 제어, 확장, 용량 계획 (6~8장)
입력 읽기 (프리필)
요리사가 주문서를 끝까지 읽기
입력이 김
캐시가 듣게 하기, 같은 서버로 보내기 (5장)
출력 쓰기 (디코드)
접시를 하나씩 내놓기
출력이 김, 동시 요청이 많음
출력 길이 제한, 배칭 조절, 더 빠른 메모리 (3·4장)
이 세 구간에서 서빙의 기본 지표가 나옵니다.
첫 토큰 시간(TTFT): 요청을 보내고 첫 글자가 나올 때까지. 대기와 입력 읽기를 합친 값입니다. 사용자가 "반응이 있다"고 느끼는 시점입니다.
토큰 간 시간(TPOT 또는 ITL): 글자가 이어져 나오는 간격. 뒤집으면 사용자 한 명이 받는 초당 토큰입니다.
굿풋(goodput): 위의 두 기준을 지키면서 낼 수 있는 처리량. 최대 처리량과 다른 숫자이고, 용량 계획은 이 숫자로 합니다.
기준을 얼마로 잡아야 할지 막막하다면 공개된 예시에서 출발할 수 있습니다.
용도
첫 토큰 시간
토큰 간 시간
출처
대화
200ms 이하
50ms 이하 (초당 20토큰 이상)
부하 시험 도구 GuideLLM 문서의 예시 (모두 p99)
검색 결합 응답(RAG)
300ms 이하
100ms 이하, 전체 3초 이하
코드 생성
500ms 이하
150ms 이하
8B 모델, 대화형
500ms
30ms
업계 벤치마크 MLPerf Inference의 대화형 시나리오 제한
120B 모델(gpt-oss-120B), 대화형
2,000ms
20ms
추론 모델(DeepSeek-R1), 대화형
1,500ms
15ms
예시일 뿐이지만 감을 줍니다. 큰 모델일수록 첫 토큰은 봐주고(2초), 대신 글이 나오기 시작하면 빨라야 한다(토큰 간 20ms, 초당 50토큰)는 것이 업계 벤치마크의 기준입니다.
재는 요령 세 가지를 붙입니다.
p99를 말하려면 표본이 필요합니다. GuideLLM 문서에 따르면 p95를 믿을 만하게 추정하려면 요청 72건, p99는 368건이 있어야 합니다. 열 번 돌려 보고 p99를 말할 수는 없습니다.
엔진의 기본 눈금을 확인합니다. vLLM이 내보내는 지연 시간 히스토그램의 가장 작은 구간이 0.3초입니다. 목표가 300ms 아래라면 구간을 직접 지정하지 않는 한 대시보드에서 차이가 보이지 않습니다.
추론 모델은 지표가 하나 더 필요합니다. 위젯에서 봤듯 서버가 재는 첫 토큰과 사용자가 보는 첫 글자가 다릅니다. 생각하는 토큰이 끝나고 답의 첫 글자가 나오는 시점을 따로 잽니다.
2. 레퍼런스 설계: 요청 하나가 지나는 길
2026년 10월에 직접 서빙을 한다면 구조는 대체로 아래와 같습니다. 규모에 따라 정거장 하나가 설정 몇 줄일 수도, 별도 시스템일 수도 있지만 역할은 같습니다.
눈여겨볼 점은 일곱 칸 가운데 모델을 실제로 돌리는 것은 한 칸(엔진)뿐이라는 것입니다. 나머지 여섯 칸은 요청을 받고, 나누고, 늘리고, 지켜보는 일입니다. 서빙을 처음 설계할 때는 엔진 설정에 시간을 쓰기 쉽지만, 운영에 들어가면 사고와 개선은 대부분 나머지 칸에서 나옵니다.
이 구조가 얼마나 차이를 만드는지 보여 주는 측정이 llm-d 저장소에 있습니다. 같은 장비(H100 16장, Qwen3-32B)에서 요청이 초당 60건 들어올 때, 쿠버네티스 기본 방식으로 순서대로 나눠 보낸 구성은 첫 토큰 시간 p90이 154.1초였고, 캐시와 부하를 보고 나눠 보낸 구성은 0.9초였습니다. 최대 처리량은 초당 7,049토큰 대 14,941토큰. GPU도 엔진도 모델도 같고, 2번 칸만 다릅니다.
추론 엔진이 하는 일의 핵심은 연속 배칭입니다. GPU는 요청 여러 개를 한 묶음으로 처리할 때 효율이 좋습니다. 예전 방식은 좌석이 찰 때까지 기다렸다 떠나는 버스였습니다. 먼저 탄 사람은 기다리고, 한 명이 늦게 끝나면 모두가 기다립니다. 지금의 엔진은 멈추지 않고 도는 곤돌라입니다. 한 요청이 끝나 자리가 비면 그 순간 대기 중인 다음 요청이 올라탑니다. 2026년에 쓸 만한 엔진은 모두 이 방식이고, 이것 하나로 처리량이 몇 배가 됩니다. 원리는 넷플릭스 LLM 서빙 2부에서 자세히 다뤘습니다.
설계자가 정할 것은 "곤돌라에 몇 명까지 태울까"입니다.
여기서 두 가지 원칙이 나옵니다.
첫째, 동시 처리 수에는 반드시 상한을 겁니다. 엔진에 맡겨 두면 들어오는 대로 태웁니다. 그러면 모두가 느려지고, 메모리가 바닥나면 더 나쁜 일이 생깁니다(6장). 상한은 위젯에서 본 두 한계, 곧 속도 기준과 KV 캐시 메모리 중 작은 쪽으로 정합니다.
둘째, 용량은 굿풋으로 셉니다. 벤치마크 자료의 "초당 수만 토큰"은 대개 동시 요청을 수백 개 태운 최대 처리량입니다. 그때 한 사람이 받는 속도는 서비스 기준에 한참 못 미칩니다. 실측 예를 하나 들면, GPU 클라우드 Jarvislabs가 H100 한 장에서 Qwen3-32B를 8비트로 돌렸을 때 제한 없이 밀어 넣은 처리량은 초당 2,795토큰이었지만 동시 요청 16개로 잰 값은 초당 576~749토큰이었습니다. 같은 장비의 숫자가 조건에 따라 네 배 차이 납니다. 내 서비스의 용량은 내 조건으로 재야 합니다.
기본값은 운영값이 아닙니다
vLLM 0.30의 기본 설정을 표로 옮기면 이 장의 요점이 분명해집니다.
설정
기본값
운영에서는
--max-num-seqs (동시 처리 수)
80GB급 이상 GPU에서 1,024
굿풋 시험으로 구한 값. 대개 수십
--max-num-queued-reqs (엔진 안 대기 한도)
없음 (무제한)
반드시 지정. 넘으면 엔진이 503으로 거절합니다 (0.29에서 추가)
--max-num-queued-tokens
없음
목표 첫 토큰 시간 × 프리필 처리량. 긴 입력이 줄을 막지 못하게 합니다
--max-model-len (문맥 길이 상한)
모델이 지원하는 최대
서비스가 실제로 쓰는 길이까지만
--max-num-batched-tokens
H100·H200급에서 8,192
작게 하면 토큰 간 시간이, 크게 하면 첫 토큰 시간이 좋아집니다
--gpu-memory-utilization
0.92
한 GPU에 엔진을 둘 이상 띄우면 나눠서 지정
접두사 캐시 · 쪼개 읽기(chunked prefill)
켜짐
그대로. 다만 실제 적중률을 지표로 확인
동시 처리 1,024개에 대기열 무제한. 엔진의 기본값은 "들어오는 대로 다 받는다"입니다. 벤치마크에서 최대 처리량을 내기에는 좋지만, 서비스에서는 6장에서 볼 사고의 조건입니다. vLLM 문서도 자동 확장에 대해서는 "간단하지 않은 주제"라며 권장 지표를 정해 주지 않습니다. 엔진은 도구를 주고, 한도를 정하는 것은 운영자의 몫입니다.
같은 맥락의 요령 둘.
형식 강제(구조화 출력)의 백엔드를 고정합니다. 기본값 auto는 릴리스마다 동작이 바뀔 수 있다고 문서에 적혀 있습니다. JSON 출력에 기대는 서비스라면 백엔드 이름을 명시합니다.
추측 디코딩은 한가할 때의 기술입니다. 작은 모델이 먼저 초안을 쓰고 큰 모델이 확인하는 방식인데, 문서는 이를 요청이 적거나 중간 정도이고 메모리 통로가 병목인 경우에 권합니다. 요청이 꽉 찬 서버에서는 얻는 것이 줄어듭니다.
엔진 선택 자체는 길게 고민할 일이 아닙니다. 기본은 vLLM이고, 접두사가 매우 긴 작업이나 초대형 모델에서는 SGLang을 함께 시험해 볼 만합니다. 수천억 토큰을 처리하는 Modal은 1조 파라미터급 모델을 SGLang으로 서빙한다고 밝혔습니다. 한때 표준이던 허깅페이스 TGI는 저장소가 보관 처리됐습니다.
GPU 메모리에는 두 가지가 올라갑니다. 모델 가중치와, 진행 중인 요청들의 KV 캐시(지금까지 읽은 내용의 기억)입니다. 가중치가 차지하고 남은 자리가 곧 동시에 받을 수 있는 요청의 수입니다. 그래서 가중치를 얼마나 줄일지가 처리량 설계의 일부입니다.
가중치를 구성하는 숫자의 자릿수를 줄이는 것을 양자화라고 합니다. 여행 가방의 압축 팩과 같습니다. 16비트를 8비트로 줄이면 절반, 4비트면 4분의 1이 됩니다. 문제는 얼마나 구겨지느냐입니다.
2026년에는 이 질문에 꽤 단단한 답이 있습니다.
방식
크기
품질
맞는 GPU
16비트 (원본)
1
기준
메모리가 남을 때
8비트 부동소수 (FP8)
1/2
사실상 무손실
H100·H200. 엔진이 FP8 연산을 그대로 가속
8비트 정수 (INT8)
1/2
1~3% 손실
T4 등 구형
4비트 가중치 (W4A16)
1/4
8비트에 근접
A100. FP8 가속이 없는 세대
4비트 부동소수 (NVFP4)
1/4
원본의 99% 이상 (제3자 평가)
B200·B300. 보정용 데이터 필요
품질 칸의 근거는 Red Hat 연구진이 50만 회 넘는 평가로 낸 논문과, 양자화 도구 llm-compressor의 세대별 권장입니다. NVFP4는 9월 말의 독립 평가에서 원본 대비 99.35%(Qwen 397B)와 100.84%(Llama 70B)를 기록했습니다. 정리하면 8비트는 걱정 없이, 4비트는 대체로 괜찮게 쓸 수 있습니다.
"대체로"에 붙는 단서가 있습니다. 에이전트입니다. 도구 호출 벤치마크로 16·8·4비트를 비교한 7월의 연구에서, 과제 점수는 비슷했지만 4비트 모델은 존재하지 않는 도구 이름을 지어내는 빈도가 최대 2.5배였습니다. 평균 점수에는 안 보이고 실수의 종류에서 드러나는 차이입니다. 도구를 부르는 에이전트 서비스라면 8비트를 기본으로 하고, 4비트로 내릴 때는 일반 벤치마크가 아니라 내 평가 세트로 확인하세요.
한편 품질이 떨어졌을 때 양자화만 의심하는 것도 흔한 오진입니다. Baseten은 새 모델을 출시 당일 서비스하며 얻은 경험으로 "품질 문제의 대부분은 양자화가 아니라 서버 앞단에서 나온다"고 썼습니다. 대화 형식을 조립하는 템플릿, 도구 호출을 해석하는 부분 같은 곳입니다. 토스도 엔진의 생각 토큰 종료 표시 처리 버그를 우회해 오류율을 0.2%에서 0.02%로 낮춘 사례를 공개했습니다.
KV 캐시의 자리 계산
가중치를 올리고 남은 메모리가 KV 캐시의 예산입니다.
메모리 예산 (H100 80GB에 32B 모델을 FP8로 올릴 때)
80GB × 0.92 (엔진 기본 사용률) = 73.6GB
− 가중치 32GB
= KV 캐시 예산 약 41GB
÷ 요청 하나 (문맥 8천 토큰 × 토큰당 약 0.23MB = 1.8GB)
= 동시에 받을 수 있는 요청 약 23개
토큰당 KV 캐시 크기는 모델마다 다릅니다. vLLM 문서는 70B 모델에서 토큰당 약 320KB라고 적습니다. 10만 토큰짜리 문맥 하나가 30GB를 차지한다는 뜻입니다. 여기서 두 가지 설계 결정이 나옵니다.
문맥 길이 상한을 실제 필요만큼만 엽니다. 모델이 100만 토큰을 지원한다고 그대로 열어 두면, 긴 요청 몇 개가 메모리를 다 차지합니다.
KV 캐시도 8비트로 줄일 수 있습니다. vLLM의 4월 측정으로 토큰당 비용이 원래의 54%가 되고 처리량이 약 15% 올랐습니다. 다만 문맥이 짧으면(H100 기준 약 7천 토큰 아래) 오히려 느릴 수 있고, 3비트까지 내리는 방식은 긴 문맥에서 품질이 크게 떨어졌습니다. 기본은 8비트까지입니다.
서버가 두 대 이상이면 "이 요청을 어느 서버로 보낼까"가 생깁니다. 일반 웹 서비스에서는 순서대로 돌리면 됩니다. LLM 서빙에서는 그것이 가장 흔한 성능 낭비입니다.
대화의 두 번째 턴은 첫 번째 턴의 내용을 전부 포함합니다. 첫 턴을 처리한 서버에는 그 계산 결과가 캐시로 남아 있어, 같은 서버가 받으면 새로 붙은 부분만 읽으면 됩니다. 다른 서버로 가면 처음부터 다시 읽습니다. 단골손님을 매번 다른 요리사에게 보내 취향을 처음부터 다시 묻는 것과 같습니다.
올해 공개된 실측은 일관됩니다.
사례
바꾼 것
결과
네이버클라우드 (4월)
llm-d 기반 접두사 인지 라우팅
처리량 2.1배, KV 캐시 활용도 25~45% → 90% 이상
테슬라 + Red Hat (4월)
순서대로 배정 → 접두사 캐시 인지
출력 토큰/초 3배, 첫 토큰 시간 절반
Cloudflare (4월)
세션 고정 헤더
피크 캐시 적중 60% → 80%
Google (3월)
지연 예측 모델로 서버 선택
첫 토큰 시간 중앙값 70% 감소
서버 수를 늘리지 않고 배정 규칙만 바꿔 처리량이 두세 배가 됩니다. 서빙 설계에서 투자 대비 효과가 가장 큰 항목입니다. 직접 눌러 볼 수 있는 시뮬레이터는 AI 플랫폼 특집 5장에 있습니다.
구현은 세 단계로 볼 수 있습니다. 필요한 만큼만 올라가면 됩니다.
1
세션 고정. 대화 ID나 사용자 ID를 헤더에 싣고, 앞단에서 그 값으로 서버를 고릅니다. 설정 몇 줄이면 됩니다. 다만 고정만 하면 긴 대화가 한 서버에 몰립니다. 수천억 토큰을 처리하는 Modal은 단순 해시 고정만으로는 지연 기준을 맞추지 못했고, 부하를 함께 보는 라우터로 서버 간 부하 편차를 평균의 절반 아래로 낮췄다고 밝혔습니다.
2
캐시와 부하를 함께 보는 배정. 캐시가 있는 서버를 우선하되 그 서버가 바쁘면 다른 곳으로 보냅니다. llm-d의 기본 방식입니다. 구글은 이를 "붙을 수 있을 때까지 붙이고, 포화되면 푼다"는 규칙 하나로 정리했고, 5만 5천 토큰짜리 긴 프롬프트에서 입력 처리량 2.9배를 보고했습니다.
3
읽기와 쓰기의 분리. 긴 입력을 읽는 일과 글을 쓰는 일을 다른 서버가 맡습니다. 큰 규모에서 쓰는 방식이고 조건이 붙습니다.
3단계의 조건은 분명합니다. vLLM 프로젝트의 9월 안내서는 긴 입력을 읽는 요청 때문에 다른 사용자의 글 쓰기가 끊기는 것(토큰 간 시간 p99 초과)이 측정될 때 분리하라고 권합니다. L40S 두 장으로 한 실험에서, 한 서버가 둘을 같이 할 때 토큰 간 시간 p99가 23ms에서 263ms로 튀었고 분리하자 25~52ms로 유지됐습니다. 반대로 첫 토큰 시간이 문제이거나 서버 사이로 캐시를 옮기는 통로가 느리면 분리는 손해입니다. 처음부터 분리하지 말고, 측정이 그렇게 말할 때 분리합니다.
그리고 라우팅을 손보기 전에 확인할 것이 하나 있습니다. 캐시가 켜져 있는가. 토스는 8월에 공개한 글에서, 한 모델의 접두사 캐시가 기본으로 꺼져 있던 것을 발견해 켜자 첫 토큰 시간이 20초 가까이에서 그 10분의 1로 줄고 캐시 적중률이 90%를 넘었다고 밝혔습니다. 링크드인은 채용 도우미 요청의 절반 이상이 앞부분을 공유한다고 했습니다. 캐시가 들을 여지는 대개 생각보다 큽니다.
서빙 시스템에서 가장 흔한 대형 사고는 "조금 느려지다가 갑자기 전부 멈추는" 유형입니다. 원인은 대개 같습니다. 받을 수 없는 요청을 받았기 때문입니다.
Akamai가 6월에 공개한 실험이 이 과정을 잘 보여 줍니다. 사용자 32명이 4,000토큰짜리 요청을 동시에 보내자, GPU 메모리에 들어갈 수 있는 것보다 세 배 넘는 KV 캐시가 필요해졌습니다. 엔진은 요청을 거절하지 않고 안에서 줄을 세웠고, 첫 토큰 시간은 10초, 20초, 30초를 지나 55초 안팎에서 멈췄습니다. 그 동안 서버가 돌려준 상태 코드는 계속 정상(200)이었습니다. 일반적인 서버 감시로는 보이지 않는 장애입니다.
식당 안내원이 "지금은 자리가 없습니다"라고 말하는 것은 불친절이 아닙니다. 들여보내 놓고 한 시간을 세워 두는 것이 불친절입니다. 서빙도 같습니다.
설계는 세 겹입니다.
겹
하는 일
요령
엔진의 상한
동시 처리 수와 문맥 길이를 제한
3장에서 구한 값으로. 엔진이 감당 못 할 요청은 처음부터 받지 않습니다
엔진 밖의 대기열
넘치는 요청을 앞단에서 줄 세우기
줄의 길이에 한도를 둡니다. 엔진 안의 줄은 보이지 않고 끝없이 자라지만, 바깥의 줄은 재고 다룰 수 있습니다
거절
한도를 넘으면 바로 "나중에 다시"(429)
대화형 요청을 배치 요청보다 먼저 받는 우선순위를 둡니다. llm-d는 요청 대기 한도 60초, 우선순위 묶음당 5,000건을 기본값으로 둡니다
여기에 두 가지를 더합니다. 요청마다 최대 출력 토큰과 시간 제한을 겁니다. 1장에서 봤듯 시간을 쓰는 것은 출력이고, 끝없이 쓰는 요청 하나가 자리를 오래 차지합니다. 그리고 클라이언트의 재시도를 다스립니다. 거절당한 클라이언트가 즉시 다시 보내면 급증은 더 커집니다. 우버는 9월 글에서 재시도를 전체 요청의 약 10%로 묶는 '재시도 예산'으로 한 번의 사고에서 950만 건의 불필요한 요청을 막았다고 밝혔습니다. 서빙 서버만이 아니라 부르는 쪽의 설계이기도 합니다.
웹 서버는 CPU 사용률을 보고 늘립니다. 같은 방식으로 GPU 사용률을 보면 실패합니다. Together가 7월에 공개한 실험이 분명합니다. 확장 기준 세 가지(진행 중인 요청 수 8개, 첫 토큰 시간 p95 300ms, GPU 사용률 75%)를 걸고 부하를 올렸더니 실제로 서버를 늘린 것은 진행 중인 요청 수 기준뿐이었습니다. 나머지 둘은 끝까지 발동하지 않았습니다. 글의 표현으로는, 엔진의 대기열이 이미 밀리고 있는데 GPU 사용률은 60%로 읽힐 수 있습니다.
신호
평가
GPU 사용률
쓰지 않습니다. 요청 하나로도 높게 찍히고, 밀리고 있어도 낮게 찍힙니다
진행 중인 요청 수 (복제본당)
기본 신호. 3장에서 구한 동시 처리 상한의 일정 비율을 목표로 둡니다
대기 중인 요청 수 · 대기 시간
가장 직접적인 신호. 0보다 크면 이미 늦은 것이므로 진행 중 요청과 함께 봅니다
KV 캐시 사용률
긴 문맥 서비스에서 보조 신호. 구글은 여러 클러스터 사이에서 이 값이 40%를 넘으면 다른 클러스터로 넘깁니다
첫 토큰 시간
경보에는 좋지만 확장 신호로는 늦고 흔들립니다
llm-d의 안내서는 GPU 사용률을 "전혀 믿을 수 없는 신호"라고 못 박고, 대기열에 요청이 1건이라도 있거나 복제본당 진행 중 요청이 16개를 넘으면 늘리는 구성을 기본으로 제시합니다. 반대편의 사례도 있습니다. vLLM에 딸려 오는 배포 템플릿은 지금도 CPU 사용률 80%를 확장 기준 기본값으로 두고 있습니다. 템플릿을 그대로 쓰면 틀린 신호로 확장하게 됩니다.
늘리기 전에 볼 것도 있습니다. 토스는 대기열이 밀리는데 KV 캐시 사용률은 1%도 안 되는 상황을 발견했습니다. GPU는 한가한데 동시 처리 상한이 너무 낮게 잡혀 있었던 것입니다. 상한을 20으로 올리자 서버를 두 배로 늘리지 않고도 네 배의 트래픽을 받을 여지가 생겼습니다. Modal의 조언과 같습니다. 한 대를 먼저 다 쓰고, 그다음에 늘립니다.
새 서버는 얼마나 빨리 뜨나
두 번째 차이는 시간입니다. 웹 서버는 몇 초면 뜨지만 모델 서버는 수십 GB의 가중치를 받아 GPU에 올리고 엔진을 준비해야 합니다. Together의 측정으로 H100 서버 한 대가 준비되는 데 86초, 한 대에서 두 대가 되는 데 약 2분 30초가 걸렸습니다. 그들의 결론은 한 문장입니다. 급증은 확장으로 벗어날 수 없습니다.
콜드 스타트는 여러 단계의 합이고, 단계마다 줄이는 방법이 다릅니다.
단계
줄이는 방법
공개된 수치
가중치 받기
노드 로컬 디스크와 클러스터 안 캐시에 미리 두기. 컨테이너 이미지처럼 층으로 관리하기
Baseten: 140GB 모델을 50대가 동시에 받아도 원본에서는 한 번만 내려받음. KServe 이미지 볼륨: 캐시된 140GB 모델 서버가 11.7초에 시작 (저장소에서 받으면 40분)
가중치를 GPU에 올리기
가중치를 빠르게 읽는 적재 방식, 옆 서버에서 바로 받기
vLLM의 적재 옵션: 30B 모델 57.4초 → 1.8초 (H200). llm-d: 옆 서버에서 받아 30.3초 → 0.9초
엔진 준비 (컴파일 등)
컴파일 결과를 디스크에 남겨 재사용, 준비 범위 줄이기
vLLM 0.30: 엔진 초기화 28.9초 → 8.2초 (H200). Runpod: Qwen3-32B 서버 전체 324초 → 91초
전체를 건너뛰기
준비가 끝난 상태를 통째로 저장했다가 복원
Modal: vLLM 부팅 95.7초 → 13.8초
그래도 수십 초는 남습니다. 그래서 설계는 이렇게 됩니다.
여유분을 둡니다. 평소에 한두 대를 더 띄워 두는 것이 가장 확실한 콜드 스타트 대책입니다.
늘리기는 빨리, 줄이기는 천천히. Together의 기본 축소 대기는 5분입니다. 줄였다가 바로 다시 늘리는 진동이 가장 비쌉니다.
알 수 있는 급증은 미리 늘립니다. 출근 시간, 배치 시작 시각처럼 예측되는 것은 시각 기준으로 올려 둡니다.
0대까지 줄이는 것은 시작 시간이 수십 초 안일 때만. 그렇지 않으면 첫 요청이 시간 초과로 끝납니다.
Modal은 이를 이렇게 정리합니다. 비용은 짧은 순간의 피크를 따라가고 가치는 긴 시간의 평균을 따라가므로, 서버가 뜨는 시간이 곧 사용률의 상한입니다. 빨리 뜰수록 여유분을 덜 둬도 되고, 그만큼 덜 놀립니다.
8. 용량 계획: 거꾸로 셉니다
지금까지의 숫자를 모으면 "GPU 몇 장이 필요한가"에 답할 수 있습니다.
기본값으로 계산해 보면 불편한 숫자가 나옵니다. 피크에 맞춰 GPU를 잡으면 평균 사용률이 15% 안팎입니다. 이것은 계산기 속의 가정이 아니라 현실의 평균입니다. 벨기에 연구소 imec의 분석은 기업 GPU의 평균 사용률을 15~22%로 봤고, Modal은 예약한 용량이 대개 30% 미만으로 쓰인다고 했습니다.
같은 imec 분석의 두 숫자가 판단 기준을 줍니다. H200 4장짜리 서버가 값싼 오픈 모델 API보다 싸지려면 5년 동안 사용률 89%를 유지해야 합니다. 반면 B200 8장 서버는 비싼 프런티어 모델 API와 비교하면 사용률 15%만 넘어도 이깁니다. 직접 서빙이 싼지는 무엇의 대안이냐에 달렸습니다. 값싼 오픈 모델을 토큰으로 사는 것과 겨루면 어렵고, 프런티어 모델의 일부 일을 가져오는 것이라면 쉽습니다.
사용률을 올리는 설계는 세 가지입니다. 늘 있는 부하만 전용 GPU로 받고 넘치는 피크는 토큰 과금 API로 넘깁니다. 밤과 주말에는 색인, 요약, 평가 같은 배치를 같은 GPU에 돌립니다. 그리고 7장의 방법으로 서버가 빨리 뜨게 만들어 여유분을 줄입니다.
규모 감각을 위한 실례 하나. Together가 공개한 핀테크 고객의 코딩 에이전트는 입력 길이가 중앙값 8만 1천 토큰, p95 17만 8천 토큰이고 피크가 초당 7건입니다. 여기에 B200 56장(4장짜리 복제본 14개)을 씁니다. 초당 7건이라는 숫자만 보면 서버 몇 대면 될 것 같지만, 긴 문맥을 다루는 에이전트는 요청 수가 아니라 토큰으로 세야 한다는 것을 보여 줍니다.
9. 바꾸기와 보기: 모델도 배포물입니다
모델 파일과 엔진은 소프트웨어 배포물처럼 다뤄야 합니다. 올해의 사고 기록이 그 이유입니다.
누가
무슨 일이
배울 점
vLLM 프로젝트 (7월 회고)
0.20.0 출시 후 긴급 패치를 두 번 냄. 해당 모델·하드웨어 조합을 돌려 보는 검증이 없었음
프로젝트는 이후 매일 밤 모델·하드웨어 조합 17가지를 검증하고 의존성을 전부 고정. 사용자도 엔진 버전을 고정하고 내 조합으로 시험한 뒤 올립니다
Mistral (1월)
분당 400MB씩 메모리가 새서 몇 시간 뒤 서버가 죽음. 원인은 통신 라이브러리의 설정 하나
10분짜리 시험에는 안 보입니다. 몇 시간 돌리는 시험이 필요합니다
네이버 플레이스 (8월)
요청마다 쌓인 캐시 항목이 지워지지 않아 몇 시간 뒤 메모리 부족
같은 교훈. 가장 흔한 장애 유형이라고 밝혔습니다
Anthropic (2025년 9월 회고)
부하 분산 설정 변경으로 짧은 요청 일부가 긴 문맥용 서버로 잘못 배정돼 응답 품질이 떨어짐
라우팅 변경은 성능뿐 아니라 품질을 바꿀 수 있습니다. 운영 트래픽에 대한 품질 평가를 상시로 돌립니다
Together (7월)
GPU 메모리의 오류 정정 실패가 가장 흔한 하드웨어 고장이고, 가중치를 조용히 망가뜨림
GPU 단계에서 실패한 요청을 장애로 셉니다. 하드웨어 오류 로그에 경보를 겁니다
여기서 운영 규칙이 나옵니다.
버전을 고정하고, 일부에게 먼저 내보냅니다. Together가 공개한 방식은 트래픽을 5%, 25%, 50%, 100%로 올리며 단계마다 지연과 오류를 자동으로 검사하는 것입니다. 순서도 중요합니다. 새 버전 쪽 서버를 먼저 늘리고, 트래픽을 옮기고, 그다음에 옛 버전을 비웁니다. 쿠버네티스에서는 게이트웨이의 가중치 분할로 구현하며, KServe 문서는 새 버전의 가중치를 0이 아니라 1에서 시작하라고 권합니다. 트래픽이 전혀 없던 서버로 갑자기 보내면 순간적인 실패가 납니다.
새 서버는 '준비됨'을 따로 확인합니다. 토스증권은 쿠버네티스가 노드를 준비됐다고 표시하는 것과 GPU가 실제로 일할 수 있는 것을 구분해, 새 노드가 다섯 단계 점검(마지막 단계는 실제로 토큰을 생성해 보는 것)을 통과해야 트래픽을 받게 했습니다. Modal은 클라우드 여러 곳에서 GPU 2만 장 이상을 굴리며, 커널 로그와 GPU 진단 지표를 지켜보는 수동적 점검만으로 문제의 대부분을 잡는다고 했습니다. GPU가 90도를 넘으면 성능이 절반으로 떨어진다는 관찰도 함께 실었습니다.
여기에 앞단의 거절 건수(429)와 응답 품질의 표본 평가를 더하면 기본 대시보드가 됩니다. 정상 응답 코드만 보는 감시는 6장의 사고를 놓칩니다.
10. 규모별로 무엇을 지을까
같은 원칙도 규모에 따라 구현이 다릅니다.
규모
소: GPU 1~2장
중: 수 장~수십 장
대: 수십 장 이상, 긴 문맥
전형적인 경우
사내 챗봇, 부서 서비스, 시제품
여러 모델을 여러 팀이 쓰는 사내 플랫폼
외부 고객 대상 서비스, 코딩 에이전트
구성
서버 한두 대에 엔진을 컨테이너로. 쿠버네티스 없이도 됩니다
쿠버네티스 위에 KServe 또는 llm-d
여러 클러스터·리전을 하나의 용량 풀로
앞단
프록시 하나에 한도와 대기열
게이트웨이와 엔드포인트 선택기
지역·우선순위·규제를 보는 전역 라우팅
라우팅
한 대면 필요 없음. 두 대면 세션 고정
캐시와 부하를 함께 보는 배정
읽기·쓰기 분리, 여러 층의 KV 캐시
확장
고정 대수. 넘치면 외부 API로
진행 중 요청 기준 자동 확장, 가중치 캐시
예측 확장, 상태 복원으로 빠른 시작
장애 대비
외부 API 폴백
복제본 2대 이상, 일부 트래픽 먼저 내보내기
두 시설 이상에 가중치, 각자 전체 부하 감당
먼저 할 일
상한 걸기, 재기
라우팅과 확장 신호
전담 팀, 계층별 원인 추적
작게 시작하는 쪽에 드리는 말은, 쿠버네티스가 전제 조건이 아니라는 것입니다. GPU 두 장이면 서버 한 대, 엔진 컨테이너 하나, 앞단 프록시 하나로 충분하고, 이 글의 원칙(상한, 대기열, 거절, 측정)은 그 구성에서도 그대로 적용됩니다. 표준 도구인 llm-d조차 5월부터 쿠버네티스 없이 파일로 서버 목록을 주는 방식을 지원합니다.
큰 쪽의 기준도 공개돼 있습니다. Together는 가용성 99.9%의 조건을 "가중치가 두 시설에 있고, 각 시설이 혼자 전체 부하를 받을 수 있고, 둘 다 실제로 트래픽을 받고 있을 것"으로 정리했습니다. Fireworks는 같은 서비스의 성공률이 한 리전일 때 99.269%, 여러 리전에 걸쳤을 때 99.992%였다고 밝혔습니다.
작은 모델도 서빙입니다
임베딩, 리랭커, 분류기 같은 작은 모델은 LLM 옆에서 더 많은 요청을 받습니다. 여기서의 요령은 다릅니다. 모델이 작아 메모리는 문제가 아니고, 묶어서 처리하기와 앞뒤 처리의 위치가 성능을 정합니다. 네이버 플레이스는 리랭커와 감성 분석 모델을 vLLM의 임베딩 계열 실행기로 옮기고 전처리·후처리를 같은 프로세스 안에 넣어, 리랭커 처리량을 초당 64건에서 397건으로(6.2배), 감성 모델의 응답 시간 중앙값을 101ms에서 16ms로 줄였다고 8월에 공개했습니다. LLM용 엔진이 작은 모델에도 쓸 만해졌다는 뜻이고, 한 엔진으로 운영을 통일할 수 있다는 뜻이기도 합니다.
그리고 모든 요청이 큰 모델로 갈 필요는 없습니다. LY의 이미지 검수 시스템은 전통적인 분류 모델이 90% 이상을 걸러 내고 나머지만 멀티모달 LLM으로 보냅니다. 가장 싼 서빙은 큰 모델을 부르지 않는 것입니다.