16장. vLLM 서빙 벤치마킹과 RAG 최적화
벤치마크를 바르게 재기
달리기 기록을 잴 때 몸을 풀지 않고 처음 뛴 기록이나, 바람이 다른 날의 기록을 견주면 공정하지 않습니다. 같은 코스, 같은 조건에서 몇 번 뛰어 봐야 실력을 압니다. 서버의 속도도 조건을 맞춰 재야 견줄 수 있습니다.
1번에서 몸풀기 요청을 보내 모델을 GPU 에 올려 둡니다. 첫 요청에는 모델을 올리는 시간이 섞이기 때문입니다. 2번에서 모든 요청의 입력과 출력 길이를 맞춥니다. 3번에서 동시성을 1, 2, 4, 8 처럼 늘려 가며 잽니다. 4번에서 여러 번 재어 흔들림을 봅니다. 몸풀기가 워밍업, 같은 코스가 같은 입력입니다.
바르게 재기 위한 점검표
| 점검 | 하지 않으면 |
|---|---|
| 몸풀기 요청을 먼저 보낸다 | 첫 요청에 모델 올리는 시간이 섞인다 |
출력 길이를 맞춘다(num_predict, max_tokens) | 답이 짧게 끝난 쪽이 빨라 보인다 |
temperature 0, 씨앗 고정 | 실행마다 출력 길이가 달라진다 |
| 같은 PC 에서 다른 무거운 일을 멈춘다 | GPU 를 나눠 써서 느려진다 |
| 여러 번, 여러 동시성에서 잰다 | 한 번의 우연을 실력으로 본다 |
몸풀기의 효과
import numpy as np
# 같은 요청을 다섯 번 보낸 지연(초, 예시). 첫 번째에는 모델을 올리는 시간이 섞였다
times = [6.8, 1.21, 1.19, 1.24, 1.20]
print(f"모두의 평균: {np.mean(times):.2f}초")
print(f"첫 요청을 뺀 평균: {np.mean(times[1:]):.2f}초")코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
times | 같은 요청을 다섯 번 보낸 지연(초, 예시 숫자)이다 |
np.mean(times) | 다섯 값 모두의 평균이다 |
times[1:] | 첫 번째 값을 빼고 둘째부터 끝까지 고른다. 몸풀기 요청을 뺀 것이다 |
{...:.2f} | 소수 둘째 자리까지 적는다 |
이 코드가 뜻하는 것
추운 아침에 자동차 시동을 걸면 처음 몇 분은 엔진이 데워지느라 굼뜹니다. 그 첫 몇 분을 차의 속도로 적으면 차를 잘못 판단합니다. 여기서 첫 시동이 첫 요청, 엔진이 데워지는 시간이 모델을 GPU 에 올리는 시간입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
times = [6.8, 1.21, ...] | 첫 요청만 6.8초, 나머지는 1.2초 안팎이다 | 시동 직후만 느렸다 |
np.mean(times) | 2.33초 | 시동 시간까지 섞은 평균 |
np.mean(times[1:]) | 1.21초 | 데워진 뒤의 실제 빠르기 |
몸풀기를 빼지 않으면 서버가 실제보다 두 배 가까이 느리게 보입니다. 그래서 벤치마크는 몸풀기 요청을 한 번 보내고 그 결과는 버린 뒤에 잽니다.
주의할 점
- 교안의 숫자는 이 PC(GTX 1650, 4GB) 한 대에서 잰 것입니다. GPU, 드라이버, 엔진 판이 다르면 숫자가 크게 달라지므로, 같은 방법으로 자기 환경에서 다시 잽니다.
- 벤치마크용 질문과 실제 사용자의 질문은 길이가 다를 수 있습니다. 가능하면 실제 기록(15장의 질문, 실습 5의 질문 기록)과 비슷한 길이로 잽니다.