청크를 4배 키웠는데 TTFT가 0.4% 움직였습니다
vLLM 벤치마크를 돌려 p99 TTFT를 보고 계신다면, 그 숫자가 모델이 아니라 부하 생성기를 잴 가능성이 높습니다. 저희가 B200 한 장에서 확인한 바로는 같은 엔드포인트가 부하를 던지는 방식만 바꿔도 꼬리 지연이 열한 배 갈렸습니다. 더 곤란한 건 그다음입니다. 병목의 정체가 바뀌면서, 고쳐야 할 노브까지 바뀌었습니다.
글의 핵심 개념을 형상화했습니다.
아무 일도 일어나지 않은 실험
시작은 평범한 최적화였습니다. 동시성 128에서 TTFT p99가 5.38초로 나왔습니다. 목표가 1.5초였으니 한참 초과입니다. 반면 토큰 간 지연은 25.6밀리초로 예산에 여유가 있었습니다. 첫 토큰만 늦고 그다음은 멀쩡한 상황이었습니다.
교과서적인 처방이 있습니다. chunked prefill의 청크 크기를 키우는 것입니다. 프리필을 큰 덩어리로 밀어 넣으면 첫 토큰이 빨리 나옵니다. 대신 그 덩어리 뒤에서 기다리는 디코드가 손해를 봅니다. 토큰 간 지연에 여유가 있으니 그 손해를 감당하고 TTFT를 사 오면 될 것 같았습니다.
같은 모델, 같은 튜닝, 청크 크기만 8,192에서 32,768로 올린 엔드포인트를 하나 더 띄웠습니다. 노브가 실제로 먹었는지 엔진 로그에서 확인까지 했습니다.
| 청크 | 처리량 | TTFT p99 | 토큰당 에너지 |
|---|---|---|---|
| 8,192 | 3,434 tok/s | 5.380초 | 0.283 J |
| 32,768 | 3,366 tok/s | 5.401초 | 0.286 J |
0.4% 나빠졌습니다. 네 배를 키웠는데 소수점 아래에서만 움직였습니다.
NotebookLM이 소스를 종합해 생성한 인포그래픽입니다.
왜 안 움직였나
노브가 고장 난 게 아니었습니다. 그 노브가 손댈 수 있는 양이 애초에 정해져 있었습니다.
저희 벤치마크는 요청 128개를 동시에 던집니다. 입력이 각 2,048토큰이니 도착하는 순간 26만 토큰어치 프리필이 한꺼번에 쌓입니다. 이 총량은 청크 크기와 무관하게 고정입니다. 청크는 그 일을 어떻게 자를지를 정할 뿐 얼마나 할지를 바꾸지 않습니다.
그리고 p99 TTFT는 그 줄의 맨 끝에 선 요청이 언제 첫 토큰을 받는지입니다. 맨 끝 요청은 앞의 모든 프리필이 끝나야 자기 차례가 옵니다. 자르는 방식을 바꿔도 앞의 총량이 같으면 맨 끝 사람의 대기는 같습니다.
청크 크기는 끼어들기의 세밀함을 조절하는 노브입니다. 줄의 길이를 줄이는 노브가 아닙니다. 저희는 줄이 긴 문제를 끼어들기 노브로 풀려 했습니다.
줄을 세운 건 저희였습니다
여기서 질문이 바뀝니다. 왜 128개가 한꺼번에 도착했을까요.
실제 서비스에서는 그렇게 도착하지 않기 때문입니다. 사용자는 각자 자기 시간에 요청을 보내며 그 간격은 대체로 지수분포에 가깝습니다. 128명이 같은 밀리초에 버튼을 누르는 건 부하 테스트 도구가 만드는 상황이지 트래픽이 만드는 상황이 아닙니다.
그래서 도착 과정 하나만 바꿔 보았습니다. 요청 구성은 한 글자도 건드리지 않았습니다. 같은 프롬프트와 같은 출력 길이를 같은 엔드포인트에 지수분포 간격으로 흘려보냈습니다.
| 도착 방식 | 처리량 | TTFT p99 | TPOT p99 |
|---|---|---|---|
| 동시 128개 | 3,434 tok/s | 5.380초 | 해당 없음 |
| 푸아송 12/초 | 3,113 tok/s | 0.477초 | 71.7밀리초 |
처리량 91%를 내면서 꼬리 지연이 열한 배 좋습니다.
부하가 가벼워서가 아닙니다. 리틀의 법칙으로 계산해 보면 푸아송 쪽이 평균적으로 더 많은 요청을 안고 돌았습니다. 큐가 얕아서가 아니라 줄이 한꺼번에 생기지 않아서입니다. 도착이 흩어지면 프리필도 흩어지며 맨 끝에 서는 사람이라는 개념 자체가 흐려집니다.
진짜 곤란한 건 그다음입니다
숫자가 좋아진 것보다 중요한 변화가 있습니다. 막는 지표가 바뀌었습니다.
동시 도착에서는 TTFT가 SLO를 깼고 토큰 간 지연은 여유였습니다. 푸아송에서는 정반대입니다. 도착률 12에서 TTFT는 0.477초로 여유가 넘치는데 TPOT가 71.7밀리초로 예산을 넘깁니다. 첫 토큰은 빨리 나오는데 그다음이 끊깁니다.
병목의 정체가 바뀌면 처방도 바뀝니다.
TTFT가 병목이면 프리필 용량 문제입니다. 프리필과 디코드를 분리해 서로 다른 복제본에 태우거나 유입 자체를 조절하는 쪽으로 갑니다. TPOT가 병목이면 디코드 쪽 문제입니다. 배치 구성과 스케줄링, GPU 클럭 같은 실행 속도 축을 봅니다. 완전히 다른 작업이고, 완전히 다른 몇 주가 걸립니다.
만약 저희가 동시 도착 측정만 보고 로드맵을 짰다면, 실제로는 존재하지 않는 병목을 풀려고 프리필 분리에 몇 주를 썼을 것입니다. 그리고 다 만들고 나서 실 트래픽에서 아무 효과가 없다는 걸 발견했을 것입니다.
알고도 틀렸습니다
여기서 변명을 하나 접겠습니다. “동시 도착이 최악 코너인 건 큐잉 이론 상식 아니냐”는 지적이 맞습니다.
저희 제품 요구사항 문서에는 일정 부하와 푸아송과 급증 트래픽을 모두 쓰라고 적혀 있습니다. 저희가 쓴 문장입니다. 그런데도 최악 코너 하나만 재고 그 위에서 “이 운영점은 SLO 밖이다”라는 제품 결론을 냈습니다.
읽었는데도 틀렸다는 게 이게 자명하지 않다는 증거라고 생각합니다. 대부분의 벤치마크 도구가 기본으로 동시성 N을 고정해 던집니다. 그게 편하고 숫자도 재현성 있게 나오기 때문입니다. 재현성 있는 숫자와 의미 있는 숫자는 다릅니다.
그래서 무엇을 하면 되나
세 가지를 제안드립니다.
첫째, 도착 과정을 벤치마크 결과에 함께 적으십시오. “TTFT p99 5.4초”는 절반만 말한 문장입니다. “동시성 128 일괄 발사에서 TTFT p99 5.4초”가 완결된 문장입니다. 저희는 이제 절감률이든 지연이든 부하 모델과 SLO 임계를 함께 적지 않으면 인용하지 않기로 했습니다.
둘째, 병목의 정체를 매번 다시 확인하십시오. 지난번에 TTFT가 병목이었다고 이번에도 그런 게 아닙니다. 부하 형태가 바뀌면 정체가 바뀝니다. 노브를 고르기 전에 무엇이 예산을 먼저 소진하는지부터 보십시오.
셋째, 포화 근처를 따로 재십시오. 저희 용량은 초당 13.4건이었는데 도착률 13.5에서 TTFT 중앙값이 0.25초에서 2.07초로 튀었습니다. 그 직전인 12까지는 아주 평온합니다. 평온한 구간만 재고 운영 여유를 정하면 절벽 바로 앞에 서게 됩니다.
Metis에서 이 결과를 쓰는 방식
저희는 이 측정을 추론 서빙 플랫폼 Metis의 운영 기준에 반영했습니다. 테넌트에게 처리량과 지연을 약속할 때 그 숫자가 나온 부하 모델을 함께 명시하고, 용량 계획에서 포화 무릎 앞에 여유를 두도록 했습니다. 온프레미스나 소버린 환경처럼 GPU를 더 사서 문제를 덮을 수 없는 배포에서는 이 차이가 그대로 비용이 됩니다. 존재하지 않는 병목을 풀려고 GPU를 늘리는 것만큼 비싼 오해가 없습니다.
경계
정직하게 밝힐 것이 있습니다. 이 측정은 B200 한 장, 모델 하나, 워크로드 형태 하나입니다. 도착률별로 한 번씩만 쟀기 때문에 개별 백분율은 인용 등급이 아니고, 이 글에서도 절감률 수치는 일부러 쓰지 않았습니다. 열한 배라는 격차는 반복 편차로 뒤집힐 크기가 아니라서 방향만 말씀드립니다. 반복 측정은 다음 작업으로 남겨 두었습니다.
그리고 측정 중 같은 노드의 다른 GPU도 함께 돌았습니다. GPU 전력은 장치별로 격리되지만 CPU와 PCIe는 공유하므로, 전력보다 지연 수치의 신뢰도가 낮습니다.
실험 조건은 B200 한 장에 Qwen3.8-27B NVFP4 체크포인트, vLLM 0.24, 입력 2,048 / 출력 256 고정입니다. 원본 측정 기록은 저희 백서 저장소의 측정 원장에 sha256과 함께 보관합니다. 측정 전에 판정 기준을 문서로 고정했고 사후에 고치지 않았습니다.
NotebookLM이 소스를 종합해 생성한 인포그래픽입니다.
참고 자료
- vLLM Metrics. 이 글의 TTFT·TPOT 분위수는 vLLM이 직접 노출하는 히스토그램에서 뽑았습니다. 자기 스택에서 같은 값을 보려면 여기부터 보시면 됩니다.
- vLLM Optimization and Tuning. chunked prefill과
max_num_batched_tokens가 무엇을 조절하는지에 대한 공식 설명입니다. - vLLM Disaggregated Prefilling. TTFT가 진짜 병목일 때 검토하게 되는 프리필·디코드 분리입니다.
- Little’s law. 푸아송 쪽이 더 무거운 부하였다는 판단의 근거입니다. 평균 재차 요청 수는 도착률과 체류시간의 곱입니다.