LiteLLM을 Rust로 이전합니다. 벤치마크 결과는 다음과 같습니다.
요약
LiteLLM이 메모리 효율성과 성능 향상을 위해 핵심 런타임을 Python에서 Rust로 마이그레이션합니다. PyO3를 활용한 단계적 전환을 통해 기존 API 호환성을 유지하면서도 처리량은 15배 높이고 메모리 사용량은 11배 줄이는 것을 목표로 합니다.
핵심 포인트
- Rust 전환을 통해 요청당 오버헤드를 150배 감소시킴
- 메모리 사용량을 11배 절감하여 OOM 문제 해결
- PyO3를 이용해 Python과 Rust를 단계적으로 결합하는 전략 채택
- 기존 config.yaml 및 API 호환성을 완벽히 유지
우리는 LiteLLM을 AI 게이트웨이 (AI gateway)로 사용하고 있습니다. 100개 이상의 프로바이더 (providers), 하나의 OpenAI 호환 API. 잘 작동하고, 확장 가능하며, 우리는 이를 선호합니다. 하지만 1년 동안 Python 프록시 (proxy)를 통해 트래픽을 처리하면서 한 가지 문제가 계속 우리를 괴롭혔습니다. 바로 메모리 (memory)입니다.
동시 부하 (concurrent load) 상황에서 Python 프록시는 약 359MB까지 치솟습니다. 이를 포드 (pods), 리전 (regions), 재시도 (retries) 단위로 곱해보면 상황은 심각해집니다. 최악의 타이밍에 OOM (Out of Memory) 킬이 발생합니다. 어떤 느낌인지 아실 겁니다.
LiteLLM은 방금 전체 핫 패스 (hot path)를 Rust로 마이그레이션한다고 발표했습니다. 재작성 (rewrite)이 아닙니다. v2도 아닙니다. 동일한 config.yaml, 동일한 데이터베이스, 동일한 API를 유지합니다. 내부의 런타임 (runtime)이 더 빨라질 뿐입니다.
저는 그들의 벤치마크 (benchmark) 수치를 살펴보았습니다. 실제 데이터입니다.
수치
| Rust 게이트웨이 (gateway) | LiteLLM Python | |
|---|---|---|
| 요청당 오버헤드 (Per-request overhead) | ~0.05ms | ~7.5ms |
| ... |
15배의 처리량 (throughput). 11배 적은 메모리. 150배 낮은 요청당 오버헤드. 테스트 하네스 (harness)가 레포지토리 (repo)에 체크인되어 있어 직접 재현할 수 있습니다.
대부분의 워크로드 (workloads)에서 게이트웨이 오버헤드는 모델 지연 시간 (model latency)에 비하면 노이즈에 불과합니다. Claude 호출은 500ms에서 30s가 걸립니다. 7ms와 0.05ms의 차이가 누가 신경이나 쓰겠습니까. 하지만 분류 배치 (classification batches), 대규모 임베딩 (embeddings at scale), 또는 컴플리션 (completions)을 몰아치는 코딩 에이전트 (coding agents)와 같은 고처리량 (high-throughput) 작업에서는 그 차이가 빠르게 누적됩니다.
구현 방식
이 마이그레이션은 깔끔한 4단계 계획으로 진행됩니다:
Stage 0: 순수 Python (현재)
Stage 1: PyO3를 통한 Rust 코어 (core), Python은 여전히 I/O 수행
Stage 2: FastAPI 씬 쉘 (thin shell), 전체 핫 패스 (hot path)를 Rust로 구현
...
제가 이 방식에서 좋게 보는 점은 모든 것을 한꺼번에 뒤집지 않는다는 것입니다. 각 라우트 (route)가 개별적으로 이동합니다. 먼저 OCR (가장 작은 표면적, 스트리밍 없음)부터 시작합니다. 그다음 /v1/messages (스트리밍 추가). 그다음 /chat/completions (가장 큰 파라미터 표면적). 한 번에 하나의 프로바이더씩, 매 단계마다 패리티 체크 (parity check) 게이트를 거칩니다.
Rust 코어는 순수 변환 (transforms)을 담당합니다. 요청을 프로바이더 요청으로 변환하고, 응답을 다시 되돌리며, 스트림 청크 (stream chunks)를 처리하고, 토큰 (tokens)을 계산합니다. 소켓 (sockets), 비밀 정보 (secrets), 데이터베이스 액세스 (database access)는 없습니다. Python은 Stage 3까지 I/O를 계속 담당합니다. 깔끔한 분리입니다.
타임라인 (Timeline)
8월 15일 - litellm.ocr() → Rust
9월 1일 - /messages, /chat/completions → Rust
9월 15일 - Router (부하 분산 (load balancing), 폴백 (fallbacks), 재시도 (retries)) → Rust
...
변하지 않는 것 (What stays the same)
여러분이 중요하게 생각하는 모든 것이 동일합니다:
- 동일한
config.yaml - 동일한 데이터베이스 및 스키마 (schema)
- 동일한 클라이언트 API, 동일한 요청/응답 형태 (request/response shapes)
- 동일한 제공자 (providers), 라우팅 (routing), 키 (keys)
- 커스텀 Python 플러그인은 사이드카 (sidecar)에서 계속 작동합니다
Rust 바이너리를 배포하면 약 65MB의 메모리를 사용하며, 오버헤드는 1ms 미만으로 유지됩니다. 여러분의 설정 중 바뀌는 것은 아무것도 없습니다.
이것이 중요한 이유 (Why this matters)
LiteLLM에 대해 "Python은 느리다"라고 주장하던 논거는 항상 과장이었습니다. 게이트웨이 (Gateway) 오버헤드는 일반적인 LLM 호출 시 전체 지연 시간 (latency)의 0.3%에 불과합니다. 우리는 몇 주 전에 실제 수치로 이를 증명했습니다.
하지만 이제는 그 주장조차 사라졌습니다. 1ms 미만의 오버헤드, 32MB 메모리, 단일 인스턴스에서 초당 6,782개의 요청 (6,782 req/s). 100개 이상의 제공자 (providers)를 지원하면서 이보다 더 가벼운 게이트웨이를 찾기는 어려울 것입니다.
블로그 포스트에는 전체 아키텍처 다이어그램 (architecture diagrams)과 재현 가능한 벤치마크 설정 (reproducible benchmark setup)이 포함되어 있습니다: docs.litellm.ai/blog/litellm-rust-launch
다른 분들도 Rust를 통해 AI 게이트웨이를 운영하고 계신지 궁금합니다. 여러분의 설정은 어떤 모습인가요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기