연재 중집필 중인 책입니다. 아직 본문이 비어 있거나 채워지는 중인 장이 있습니다.

제 1 장

서빙 지연의 지표

추론 엔진에 모델을 올리고 요청 하나에 응답이 돌아오면 모델이 동작한다는 것까지는 확인된다. 서비스로 운영할 수 있는지는 그다음 문제로, 동시에 들어오는 요청 수십 개가 각자 얼마나 기다리는지를 재야 판단할 수 있다. 이 판단의 기준이 되는 것이 지연 지표다. 지표를 잘못 고르면 사용자가 느린 서비스를 겪는 동안에도 대시보드는 정상으로 보인다.

벤치마크의 조건

추론 엔진에 딸린 벤치마크 도구는 측정을 단순하게 하려고 흔히 세 가지 조건을 둔다. 요청을 한 번에 하나씩 보내고, 입력과 출력 길이를 고정하고, 처음 몇 번의 실행은 워밍업으로 버린다. 세 조건 모두 반복 측정의 분산을 줄이는 데는 쓸모가 있지만 실제 트래픽과는 거리가 있다.

요청을 하나씩 보내면 GPU는 그 요청 하나만 계산한다. 실제 서비스에서는 여러 요청이 같은 GPU를 나눠 쓰고 엔진이 그 요청들을 어떻게 묶어 어떤 순서로 계산하느냐에 따라 요청마다 기다리는 시간이 달라진다.

길이를 고정하면 긴 요청이 다른 요청을 붙잡는 효과가 측정에서 빠진다. 같은 대화형 서비스 안에서도 짧은 질문은 프롬프트가 수십 토큰이지만 대화 이력과 검색 문서를 붙인 요청은 수천 토큰을 넘는다. 출력 길이도 몇 토큰에서 수천 토큰까지 넓게 퍼진다.

워밍업을 버리는 조건은 가장 느린 요청을 지운다. 서버를 띄운 직후의 요청은 커널 준비와 메모리 할당 비용까지 치르는데, 오토스케일로 서버가 자주 뜨고 내려가는 환경에서는 이 비용이 사용자에게 그대로 보인다.

그래서 벤치마크 수치는 그 장비와 모델로 낼 수 있는 상한에 가깝다. 실제 트래픽에서의 지연은 운영 중인 요청의 길이 분포와 도착 패턴을 그대로 재현해 다시 재야 알 수 있다.

첫 토큰까지의 시간과 토큰 간격

언어 모델은 응답을 토큰 단위로 하나씩 만든다. 엔진은 먼저 프롬프트 전체를 읽어 첫 토큰을 내고 그 뒤로는 방금 만든 토큰을 입력에 덧붙여 다음 토큰을 만든다. 그래서 응답을 스트리밍하는 서비스에서 사용자가 겪는 지연은 두 구간으로 나뉜다.

지표정의주로 무엇에 따라 늘어나는가
첫 토큰까지의 시간 (TTFT)요청을 보낸 뒤 첫 토큰이 도착할 때까지프롬프트 길이, 대기열에서 기다린 시간
토큰 간격 (TPOT)첫 토큰 이후 출력 토큰 하나에 걸리는 평균 시간같은 GPU에서 동시에 생성 중인 요청 수, 새 요청의 프리필이 끼어드는 빈도

TTFT는 time to first token, TPOT는 time per output token의 약자다. DistServe는 두 값에 지연 목표를 따로 두고 서빙 시스템을 설계한다. 출력 토큰이 n개인 요청의 전체 응답 시간은 대략 다음과 같이 나뉜다.

전체 응답 시간 ≈ TTFT + TPOT × (n − 1)

두 지표가 나빠지는 원인도 나뉜다. 첫 토큰을 내려면 프롬프트를 끝까지 읽어야 하므로 TTFT는 프롬프트가 길수록 늘어나고, 요청이 GPU에 올라가지 못하고 대기열에서 기다린 시간도 TTFT에 그대로 더해진다. TPOT는 프롬프트 길이에 훨씬 덜 민감한 대신, 한 스텝에 함께 계산하는 요청이 많아지거나 다른 요청의 프롬프트 처리가 중간에 끼어들 때 늘어난다.

그래서 요청 하나의 시작부터 끝까지를 한 숫자로 재는 전체 응답 시간만으로는 원인을 가를 수 없다. 첫 토큰이 2초 늦고 나머지가 빨리 나온 요청과, 첫 토큰은 바로 나왔지만 토큰 간격이 내내 길었던 요청이 같은 값으로 기록되기 때문이다. 스트리밍 서비스라면 두 지표를 요청마다 따로 남긴다.

평균과 백분위

지연은 평균 대신 백분위로 본다. 트래픽은 시간대에 따라 몰렸다 빠지기를 반복하므로 하루 전체를 평균 내면 피크 시간대의 느린 요청이 한가한 시간대의 빠른 요청 수천 건에 묻힌다.

p50은 요청 절반이 그 값보다 빨랐다는 뜻이고 p99는 요청 100개 중 가장 느린 1개를 빼면 나머지가 모두 그 값 안에 들어왔다는 뜻이다. p99가 드물게 보여도 사용자 단위로는 자주 만나는 값이다. 하루에 요청을 100번 보내는 사용자는 p99보다 느린 응답을 하루 평균 한 번 겪고, 사용자가 수백 명이면 서비스 전체로는 하루 수백 번이 된다.

백분위를 낼 시간 창도 좁힌다. 하루 단위 p99는 한가한 시간대의 요청에 희석되므로 피크 시간대만 따로 떼어 계산해야 사용자가 겪는 값에 가까워진다. 지연 목표를 정할 때도 “피크 30분 구간의 TTFT p99”처럼 지표, 백분위, 시간 창을 함께 적는다.

동시 요청 수와 용량

장비 하나가 감당할 수 있는 부하는 동시 요청 수를 늘려 가며 찾는다. 실제 트래픽에서 뽑은 프롬프트·출력 길이 분포로 요청을 만들고 동시 요청 수를 단계적으로 올리면서 단계마다 TTFT와 TPOT의 백분위를 기록한다.

동시 요청을 늘리면 두 지표는 한동안 거의 그대로 있다가 어느 지점에서 꺾인다. 꺾이는 모양으로 원인을 가늠할 수 있다.

  • TPOT가 먼저 오른다: 한 스텝에 함께 계산하는 요청이 늘어 스텝 시간 자체가 길어졌다
  • TTFT가 갑자기 튄다: 새 요청이 GPU에 올라가지 못하고 대기열에서 기다렸다. KV 캐시를 담을 메모리가 찼거나 엔진의 동시 처리 상한에 걸린 경우다

두 지표가 지연 목표를 넘기 직전의 동시 요청 수가 그 설정의 실제 용량이다. 이 값은 모델, 엔진 설정, 길이 분포가 바뀌면 함께 바뀌므로 셋을 고정한 채로 기록한다. 균일한 길이로 잰 용량에는 긴 요청이 다른 요청을 붙잡는 효과가 빠져 있어 실제보다 크게 나온다.

요청마다 남길 값

지연의 원인을 나중에 가르려면 요청 단위로 다음 값을 남긴다.

값쓰임
프롬프트 토큰 수 · 출력 토큰 수길이 분포 재현, TTFT와 프롬프트 길이의 관계 확인
대기열 대기 시간TTFT 가운데 GPU에 올라가기 전에 쓴 시간
TTFT · TPOT사용자가 겪는 지연
종료 사유종료 토큰, 길이 상한, 취소, 오류의 구분

GPU 쪽에서는 메모리 점유와 함께 연산기와 메모리 대역폭이 실제로 얼마나 쓰이고 있는지를 본다. nvidia-smi가 보여 주는 GPU 사용률은 이름과 달리 연산기가 얼마나 바쁜지를 재는 값이 아니어서, 이 숫자가 100%여도 장비에 여유가 많이 남아 있을 수 있다. 이 차이는 생성이 프리필과 디코드로 나뉘고, 프리필은 연산 성능에, 디코드는 메모리 대역폭에 묶인다는 데서 나온다.

측정의 기준1 / 18