LLM 엔지니어링16장 · vLLM 서빙 벤치마킹과 RAG 최적화7 / 22← 이전목차다음 →MetaContents

16장. vLLM 서빙 벤치마킹과 RAG 최적화

서빙 성능 지표

택배를 기다릴 때 "주문하고 언제 출발했나(첫 소식)", "출발한 뒤 얼마나 빨리 오나", "다 받기까지 얼마나 걸렸나"를 따로 느낍니다. 택배사는 "하루에 몇 상자를 나르나"를 봅니다. LLM 서버도 사용자가 느끼는 시간과 서버가 해내는 양을 따로 잽니다.

첫 토큰까지의 시간, 토큰 사이 시간, 전체 지연, 처리량의 네 지표를 나란히 놓은 비교 그림

왼쪽 셋은 사용자 한 명이 느끼는 시간입니다. TTFT 는 첫 글자가 보일 때까지, TPOT 은 글이 흘러나오는 빠르기, 지연은 다 받기까지입니다. 오른쪽 처리량은 서버 전체가 1초에 만드는 토큰 수입니다. 첫 소식이 TTFT, 배송 빠르기가 TPOT, 다 받기까지가 지연, 하루 나르는 상자 수가 처리량입니다.

지표 정리

지표뜻계산좋은 방향
TTFT첫 토큰까지첫 조각을 받은 시각 − 보낸 시각짧게
TPOT토큰 사이 시간(지연 − TTFT) ÷ (출력 토큰 − 1)짧게
지연요청 하나의 전체 시간다 받은 시각 − 보낸 시각짧게
처리량1초에 만든 토큰 수모든 출력 토큰 ÷ 걸린 시간크게
p50, p95지연의 가운데와 느린 쪽시간을 늘어놓고 50%, 95% 자리짧게

지표 계산하기

Python
import numpy as np

# 요청 여섯 개의 (보낸 뒤 첫 토큰까지 초, 다 받기까지 초, 출력 토큰 수) - 예시 숫자
reqs = [(0.21, 1.9, 60), (0.25, 2.1, 64), (0.19, 1.8, 58), (0.30, 2.4, 64), (1.80, 3.9, 64), (0.22, 2.0, 62)]
ttft = np.array([r[0] for r in reqs])
lat = np.array([r[1] for r in reqs])
tpot = np.array([(r[1] - r[0]) / (r[2] - 1) for r in reqs])
print(f"TTFT 평균 {ttft.mean():.2f}초 · p50 {np.percentile(ttft, 50):.2f} · p95 {np.percentile(ttft, 95):.2f}")
print(f"TPOT 평균 {tpot.mean() * 1000:.0f}ms · 지연 p50 {np.percentile(lat, 50):.2f}초 · p95 {np.percentile(lat, 95):.2f}초")

다섯째 요청처럼 줄을 서느라 첫 토큰이 늦은 요청은 평균보다 p95 에 잘 드러납니다.

코드에 나오는 함수

코드쉬운 뜻
reqsrequests(요청들)의 줄임말이다. 요청마다 (TTFT, 지연, 출력 토큰 수)를 적은 목록이다
np.array([...])숫자 목록을 NumPy 배열로 바꾼다. 평균, 백분위수를 한 번에 계산할 수 있다
(r[1] - r[0]) / (r[2] - 1)첫 토큰 뒤의 시간을 나머지 토큰 수로 나눈다. TPOT 이다
ttft.mean()평균을 구한다
np.percentile(ttft, 95)percentile(백분위수)을 구한다. 값을 작은 것부터 늘어놓았을 때 95% 자리의 값이다
tpot.mean() * 1000초를 밀리초(ms, millisecond, 1000분의 1초)로 바꾼다

이 코드가 뜻하는 것

택배 여섯 상자의 기록을 모아 "보통은 얼마나 걸렸고, 늦은 쪽은 얼마나 걸렸나"를 따로 보는 일입니다. 여기서 상자 하나가 요청 하나, 출발 소식이 TTFT, 받기까지가 지연입니다.

줄하는 일쉽게 말하면
ttft, lat, tpot요청 여섯 개에서 세 지표를 뽑는다상자마다 출발까지, 다 받기까지, 이동 빠르기
첫 printTTFT 평균 0.50초, p50 0.23, p95 1.43보통은 0.2초대인데, 한 상자가 늦어 평균과 p95 가 끌려 올라갔다
둘째 printTPOT 평균 30ms, 지연 p50 2.05초, p95 3.52초출발한 뒤 빠르기는 비슷하고, 늦은 상자는 3.5초쯤 걸렸다

TTFT 의 p50 은 0.23초인데 평균은 0.50초입니다. 늦은 요청 하나(1.80초)가 평균을 두 배 넘게 끌어올렸습니다. 가운데 값(p50)과 느린 쪽 값(p95)을 함께 보면 이런 요청이 바로 보입니다.

작게 줄여서 눈으로 보기

숫자 다섯 개로 평균, p50, p95 가 어떻게 다른지 봅니다. 숫자는 설명용입니다.

Python
import numpy as np

lat = np.array([1, 2, 3, 4, 10])     # 요청 다섯 개의 지연(초, 설명용 숫자)
print("평균:", lat.mean())
print("p50:", np.percentile(lat, 50))
print("p95:", round(np.percentile(lat, 95), 2))
출력
평균: 4.0
p50: 3.0
p95: 8.8
결과읽는 법
평균: 4.0다섯을 더해 5로 나눴다. 하나뿐인 10초가 평균을 끌어올렸다
p50: 3.0늘어놓은 1, 2, 3, 4, 10 의 한가운데 값이다. 10초의 영향을 받지 않는다
p95: 8.895% 자리가 넷째(4)와 다섯째(10) 사이라 둘 사이를 비율로 나눈 값이다. 느린 쪽을 잘 드러낸다

주의할 점

  • 평균만 보면 가끔 아주 느린 요청이 묻힙니다. 사용자 불만은 느린 쪽에서 나오므로 p95 를 함께 적습니다.
  • 처리량과 지연은 함께 움직입니다. 동시 요청을 늘리면 처리량은 늘거나 그대로지만 지연은 길어집니다. "지연 p95 가 몇 초 안일 때의 처리량"처럼 조건을 붙여 말합니다.
← 이전 절16장 · 연속 배치다음 절 →16장 · 벤치마크를 바르게 재기