벤치마크
벤치마크 (Benchmarks)
가짜 OpenAI 엔드포인트에 대해 테스트한 LiteLLM Gateway (Proxy Server) 벤치마크예요.
LiteLLM Gateway는 1k RPS에서 8ms P95 지연 시간을 가집니다 (벤치마크 참고).
고처리량 프로파일: 50K~100K 토큰 프롬프트로 3,000 RPS
큰 프롬프트는 짧은 채팅 요청과 다른 게이트웨이 워크로드를 만듭니다. 토큰 카운팅, 예산 검사, 지출 추적, 메트릭 수집 모두 모델-프로바이더 호출 전이나 후에 발생하며, 높은 요청 볼륨에서 병목이 될 수 있어요.
이 벤치마크는 고처리량 배포 프로파일을 v1.101.0 과 비교합니다. 이 프로파일은 Rust 토큰 카운팅, 공유 데이터베이스 연결, 격리된 메트릭 및 지출 처리, 트래픽 기반 자동 스케일링을 결합합니다.
고처리량 프로파일은 아직 개발 중이며 nightly 빌드에서 제공됩니다. 이 결과는 완전한 프로파일의 가장 이른 사용 가능 버전을 사용한 것입니다.
출처: 문서
본문
결과
| 카테고리 | 지표 | 고처리량 프로파일 | v1.101.0 | 변경 |
|---|---|---|---|---|
| 배포 | 게이트웨이 pods | 33 | 132 | 4x 적음 |
| pod당 workers | 4 | 1 | ||
| 총 workers | 132 | 132 | 동일 | |
| 처리량 | Requests/sec | 3.00K | 0.19K | 16x |
| Tokens/sec | 224.61M | 6.92M | 32x | |
| 예상 tokens/30 days | 582.20T | 17.94T | 32x | |
| 신뢰성 | HTTP 200 rate (Locust) | 100.00% | 92.07% | |
| 요청 지연 p50 | 30.581 ms | 6.950 s | 227x | |
| p95 | 54.029 ms | 27.451 s | 508x | |
| p99 | 91.645 ms | 29.826 s | 325x | |
| 첫 토큰까지 시간 p50 | 31.667 ms | 9.400 s | 297x |
프로파일은 100% 클라이언트 가시 성공으로 전체 3,000 RPS 목표에 도달했습니다. 기준선은 약 190 RPS에 정착했고 92.07%의 요청에 성공 응답을 반환했습니다.
테스트 설정
| 테스트 차원 | 구성 |
|---|---|
| 로드 생성기 | 마스터 하나와 30개 workers가 있는 분산 Locust |
| 트래픽 | 각각 초당 요청 하나인 3,000명의 시뮬레이션 사용자 |
| 요청 믹스 | 50K, 75K, 100K 토큰 프롬프트를 같은 비율로 |
| 스트리밍 | 요청의 50% |
| 엔드포인트 | max_tokens: 16 인 /v1/chat/completions |
| 인증 | 예산이 있는 가상 키 — 입장 토큰 카운팅과 예산 예약 실행됨 |
| 모델 | 응답 캐싱이 비활성화된 인프로세스 mock 모델 |
| 네트워크 경로 | 공개 AWS Application Load Balancer |
| 클라이언트 타임아웃 | 60초 |
| 실행 시간 | 고처리량 프로파일: 24m 22s. 기준선: 5m 7s. |
mock 모델은 게이트웨이 요청 경로를 활성 상태로 유지하면서 프로바이더 비용과 프로바이더 지연 시간을 제거합니다. 테스트는 인증, 예산, 토큰 카운팅, 지출 추적, 메트릭을 여전히 포함합니다.
두 배포 모두 총 132개 게이트웨이 workers를 실행하고 528 GiB 메모리를 요청했습니다. 고처리량 프로파일은 pod당 4개 workers로 33 pods를, 132 vCPU를 요청했습니다. 기준선은 pod당 worker 하나로 132 pods를, 264 vCPU를 요청했습니다.
무엇이 차이를 만들었나
아래 각 변경은 완전한 프로파일을 테스트하기 전에 개별적으로 측정되었습니다.
| 변경 | 고객 영향 | 측정 효과 |
|---|---|---|
| Rust 입장 토큰 카운팅 | 디스패치 전에 큰 프롬프트를 세는 CPU 감소 | 50K/75K/100K 카운트가 46/53/100 ms에서 4.9/6.8/10.2 ms로 감소 |
| pod당 PgBouncer | 데이터베이스 연결이 worker마다 곱해지는 것 방지 | Postgres가 11 |
| 지출 수집 sidecar | 지출 처리를 추론 workers에서 분리 | 700 RPS에서 p99가 1.8 s에서 830 ms로 감소. 총 컴퓨팅은 거의 동일 |
| 메트릭 sidecar | Prometheus 스크레이프를 추론 workers에서 분리 | sidecar가 700 RPS에서 pod당 약 2 millicores 사용 |
| 더 높은 CPU burst 한도 | pod의 모든 workers가 함께 스로틀링되는 것 방지 | 700 RPS에서 p99가 830 ms에서 670 ms로 감소 |
| 게이트웨이 keep-alive | 스케일링 중 로드 밸런서 연결 유효 유지 | ALB 생성 502 응답이 200 RPS 테스트에서 15에서 0으로 감소 |
| RPS 및 TPS 자동 스케일링 | CPU가 포화되기 전에 트래픽에 반응 | 200-user 로드 스텝 후 약 48초에 새 replicas 추가 |
| 입장 토큰 카운트 재사용 | mock 테스트에서 같은 큰 스트리밍 프롬프트를 두 번 세는 것 방지 | 스트리밍 mock 요청이 비스트리밍 요청 약 30 ms 내에 완료 |
지표 읽는 방법
- 초당 요청, 초당 토큰, 예상 토큰, 요청 지연 시간은 게이트웨이의 Prometheus 메트릭에서 나옵니다.
- 첫 토큰까지 시간은 Locust에서 나오며, 요청 전송부터 첫 스트리밍 이벤트 수신까지의 시간을 측정합니다. 요청 업로드, 로드 밸런서, 게이트웨이 입장 작업을 포함합니다.
- HTTP 200 비율은 게이트웨이에 도달하지 못한 실패를 포함하므로 Locust에서 나옵니다.
v1.101.0 실행에는 5,118개의 클라이언트 가시 실패가 있었습니다: 4,546개 클라이언트 타임아웃/연결 드롭, 457개 HTTP 504, 115개 HTTP 502. 게이트웨이는 이 요청들을 받지 못했으므로 자체 성공 메트릭은 100%를 보였지만 Locust는 92.07%를 보였습니다.
Locust 처리량을 읽을 때는 POST 행을 사용하세요. 각 스트리밍 요청은 TTFT 행도 만들므로, 스트리밍이 활성화되면 Locust Aggregated 행이 실제 요청보다 더 많은 항목을 셉니다.
벤치마크 범위
이것은 완전한 프로파일의 before-after 비교이며 단일 변수 테스트가 아닙니다. 배포는 다른 pod 형태를 사용했고 다른 길이로 실행되었습니다. 위 표의 개별 효과는 200~1,000 RPS의 별도 A/B 테스트에서 나옵니다.
인프로세스 mock 모델은 프로바이더 지연 시간을 제외합니다. 이 결과는 이 특정 트래픽 형태에 대한 게이트웨이 용량을 측정하며, 보편적인 프로덕션 크기 조정 지침으로 취급하지 마세요. worker 수, pod 리소스, HPA 목표를 고르기 전에 대표 워크로드를 측정하세요.
아래 섹션은 4 CPU / 8 GB 머신의 가짜 OpenAI 엔드포인트에 대한 짧은 요청 본문을 사용합니다. 이 큰 프롬프트 벤치마크와 직접 비교할 수 없습니다.
테스트에 사용된 머신 스펙
LiteLLM을 배포한 각 머신은 다음 스펙을 가졌습니다:
- 4 CPU
- 8GB RAM
구성
- 데이터베이스: PostgreSQL. 크기 조정은 Database Sizing 참고
- Redis: 미사용. 프로덕션에서 권장; Redis Sizing 참고
- 로드 생성기: Locust, 1000명 사용자, 각 요청 사이 0.5s~1s 씩 생각 시간. 숫자를 자신의 실행과 비교하기 전에 Locust Settings 참고
2개 인스턴스 LiteLLM Proxy
이 테스트에서 기준 지연 특성은 fake-openai-endpoint에 대해 측정됩니다.
성능 메트릭
| 타입 | 이름 | 중앙값 (ms) | 95%ile (ms) | 99%ile (ms) | 평균 (ms) | 현재 RPS |
|---|---|---|---|---|---|---|
| POST | /chat/completions | 200 | 630 | 1200 | 262.46 | 1035.7 |
| Custom | LiteLLM Overhead Duration (ms) | 12 | 29 | 43 | 14.74 | 1035.7 |
| Aggregated | 100 | 430 | 930 | 138.6 | 2071.4 |
4개 인스턴스
| 타입 | 이름 | 중앙값 (ms) | 95%ile (ms) | 99%ile (ms) | 평균 (ms) | 현재 RPS |
|---|---|---|---|---|---|---|
| POST | /chat/completions | 100 | 150 | 240 | 111.73 | 1170 |
| Custom | LiteLLM Overhead Duration (ms) | 2 | 8 | 13 | 3.32 | 1170 |
| Aggregated | 77 | 130 | 180 | 57.53 | 2340 |
핵심 발견
- LiteLLM 인스턴스를 2에서 4로 두 배로 늘리면 중앙값 지연이 절반: 200 ms → 100 ms.
- 고백분위수 지연이 크게 감소: P95 630 ms → 150 ms, P99 1,200 ms → 240 ms.
- workers를 CPU 수와 같게 설정하면 최적 성능.
네트워크 Mock으로 벤치마킹 설정
프록시 오버헤드를 벤치마킹하는 가장 빠른 방법은 network_mock 모드를 사용하는 것입니다. 이는 httpx transport 레이어에서 아웃바운드 요청을 가로채 캔 응답을 반환하므로 mock 프로바이더를 설정할 필요가 없어요.
- proxy config 생성:
model_list:
- model_name: db-openai-endpoint
litellm_params:
model: openai/gpt-5.6-terra
api_key: "sk-fake-key"
api_base: "https://api.openai.com"
litellm_settings:
network_mock: true
callbacks: []
num_retries: 0
request_timeout: 30
general_settings:
master_key: "sk-<your-litellm-master-key>"
- 프록시 시작:
litellm --config benchmark_config.yaml --port 4000 --num_workers 8
- 벤치마크 스크립트 실행:
python scripts/benchmark_mock.py --requests 2000 --max-concurrent 200 --runs 3
벤치마킹 스크립트는 여기에서 얻습니다.
이것은 실제 또는 가짜 프로바이더에 대한 네트워크 지연 없이 핫 경로의 순수 프록시 오버헤드를 측정합니다.
가짜 OpenAI 엔드포인트 설정
부하 테스트와 벤치마킹을 위해 가짜 OpenAI 프록시 서버를 사용할 수 있습니다. LiteLLM은 다음을 제공합니다:
- 호스티드 엔드포인트: https://exampleopenaiendpoint-production.up.railway.app/ 의 무료 호스티드 fake 엔드포인트 사용
- 셀프 호스티드: github.com/BerriAI/example_openai_endpoint 로 자체 가짜 OpenAI 프록시 서버 설정
테스트에 이 config를 사용하세요:
model_list:
- model_name: "fake-openai-endpoint"
litellm_params:
model: openai/any
api_base: https://exampleopenaiendpoint-production.up.railway.app/ # or your self-hosted endpoint
api_key: "test"
/realtime API 벤치마크
가짜 realtime 엔드포인트에 대해 테스트한 /realtime 엔드포인트의 종단 간 지연 벤치마크예요.
성능 메트릭
| 지표 | 값 |
|---|---|
| 중앙값 지연 시간 | 59 ms |
| p95 지연 시간 | 67 ms |
| p99 지연 시간 | 99 ms |
| 평균 지연 시간 | 63 ms |
| RPS | 1,207 |
테스트 설정
| 카테고리 | 사양 |
|---|---|
| 부하 테스트 | Locust: 1,000명 사용자, 0.5s~1s 생각 시간, 500 ramp-up |
| 시스템 | 4 vCPUs, 8 GB RAM, 4 workers, 4 인스턴스 |
| 데이터베이스 | PostgreSQL (Redis 미사용) |
인프라 권장 사항
위 실행은 단일 PostgreSQL 인스턴스와 Redis 없이 수행되었는데, 이것은 프로덕션 구성이라기보다 벤치마크 구성입니다. 각 요청율의 인스턴스 크기, 확장 시 배포가 살아남는지 결정하는 연결 수학, AWS/Azure/GCP의 구체적인 관리 서비스 선택은 Database Sizing 및 Redis Sizing 참고. 함께 가는 게이트웨이 측 구성은 Production Best Practices 참고.
Locust 설정
- 1000명 Users
- 500 user Ramp Up
wait_time = between(0.5, 1)— 모든 사용자가 요청 사이 0.5s~1s 대기
이 숫자를 재현할 때 생각 시간이 중요한 이유
Locust 사용자는 응답을 기다리거나 자는 데 시간을 보냅니다. 평균 생각 시간 0.75s와 ~110ms 응답으로, 1000명 사용자 각각은 약 0.86s마다 요청 하나를 완료합니다. 따라서 실행은 ~1160 RPS를 제공하고 어느 순간 약 130개 요청을 진행 중으로 유지합니다. 위 지연 열이 설명하는 것은 사용자 수가 아니라 이 진행 중 깊이(in-flight depth)입니다.
생각 시간이 없는 폐쇄 루프 클라이언트는 다른 것을 측정합니다. 이전 것 반환 즉시 다음 요청을 보내는 1000개 동시 workers는 1000개 요청을 진행 중으로 유지하는데, 이는 이 실행들의 큐 깊이보다 약 8배입니다. 게이트웨이가 포화되면 처리량은 고정되고, Little's Law에 따라 각 클라이언트가 관찰하는 지연은 진행 중 요청 수 / 처리량 입니다. 따라서 같은 배포가, 같은 RPS에서, 클라이언트가 그만큼 더 많은 작업을 큐했기 때문에 약 8배 지연을 보고합니다. 지연과 동시성은 독립적이지 않으며, 둘 중 하나의 숫자도 다른 것 없이는 의미가 없습니다.
위 표와 비교하려면 0.5s~1s 생각 시간을 유지하거나, 클라이언트의 진행 중 요청 수를 약 130 근처로 유지하고 지연과 함께 보고하세요. RPS를 먼저 보고하는 것도 가치가 있습니다: 실행이 이 표보다 높은 RPS와 높은 지연을 보이면 게이트웨이가 이 벤치마크보다 빠르고 클라이언트가 더 깊이 큐잉하고 있는 것입니다.
LiteLLM 오버헤드 측정 방법
litellm의 모든 응답에는 x-litellm-overhead-duration-ms 헤더가 포함됩니다. 이는 LiteLLM Proxy가 추가한 지연 오버헤드(ms)입니다.
locust에서 이걸 측정하려면 다음 코드를 사용하세요:
import os
import uuid
from locust import HttpUser, task, between, events
# Custom metric to track LiteLLM overhead duration
overhead_durations = []
@events.request.add_listener
def on_request(request_type, name, response_time, response_length, response, context, exception, start_time, url, **kwargs):
if response and hasattr(response, 'headers'):
overhead_duration = response.headers.get('x-litellm-overhead-duration-ms')
if overhead_duration:
try:
duration_ms = float(overhead_duration)
overhead_durations.append(duration_ms)
# Report as custom metric
events.request.fire(
request_type="Custom",
name="LiteLLM Overhead Duration (ms)",
response_time=duration_ms,
response_length=0,
)
except (ValueError, TypeError):
pass
class MyUser(HttpUser):
wait_time = between(0.5, 1) # Random wait time between requests
def on_start(self):
self.api_key = os.getenv('API_KEY', 'sk-<your-litellm-api-key>')
self.client.headers.update({'Authorization': f'Bearer {self.api_key}'})
@task
def litellm_completion(self):
# no cache hits with this
payload = {
"model": "db-openai-endpoint",
"messages": [{"role": "user", "content": f"{uuid.uuid4()} This is a test there will be no cache hits and we'll fill up the context" * 150}],
"user": "my-new-end-user-1"
}
response = self.client.post("chat/completions", json=payload)
if response.status_code != 200:
# log the errors in error.txt
with open("error.txt", "a") as error_log:
error_log.write(response.text + "\n")
LiteLLM vs Portkey 성능 비교
테스트 구성: 인스턴스당 4 CPUs, 8 GB RAM | 로드: 1k 동시 사용자, 500 ramp-up | 버전: Portkey v1.14.0 | LiteLLM v1.79.1-stable | 테스트 시간: 5분
멀티 인스턴스 (4×) 성능
| 지표 | Portkey (no DB) | LiteLLM (with DB) | Comment |
|---|---|---|---|
| 총 요청 | 293,796 | 312,405 | LiteLLM이 더 높음 |
| 실패 요청 | 0 | 0 | 동일 |
| 중앙값 지연 | 100 ms | 100 ms | 동일 |
| p95 지연 | 230 ms | 150 ms | LiteLLM이 더 낮음 |
| p99 지연 | 500 ms | 240 ms | LiteLLM이 더 낮음 |
| 평균 지연 | 123 ms | 111 ms | LiteLLM이 더 낮음 |
| 현재 RPS | 1,170.9 | 1,170 | 동일 |
지연 시간 메트릭은 낮을수록 좋고, 요청과 RPS는 높을수록 좋습니다.
기술적 인사이트
Portkey — 장점: 낮은 메모리 사용량, 최소한의 스파이크로 안정적인 지연. 단점: CPU 사용률이 ~40%로 한정되어 가용 컴퓨팅 리소스를 활용하지 못함, I/O timeout 장애 3회 발생.
LiteLLM — 장점: 가용 CPU 용량을 완전히 사용, 강력한 연결 처리와 초기 워밍업 스파이크 후 낮은 지연. 단점: 초기화 중과 요청당 메모리 사용량이 높음.
로깅 콜백
GCS Bucket 로깅
GCS Bucket 사용은 기본 Litellm Proxy와 비교해 지연, RPS에 영향이 없습니다.
| 지표 | 기본 Litellm Proxy | GCS Bucket 로깅이 있는 LiteLLM Proxy |
|---|---|---|
| RPS | 1133.2 | 1137.3 |
| 중앙값 지연 (ms) | 140 | 138 |
LangSmith 로깅
LangSmith 사용은 기본 Litellm Proxy와 비교해 지연, RPS에 영향이 없습니다.
| 지표 | 기본 Litellm Proxy | LangSmith가 있는 LiteLLM Proxy |
|---|---|---|
| RPS | 1133.2 | 1135 |
| 중앙값 지연 (ms) | 140 | 132 |