rvLLM 소개
LLM(Large Language Model) 추론 서버를 운영해본 분이라면 Python 기반 vLLM의 느린 시작 시간과 무거운 의존성, 그리고 예측 불가능한 GC(가비지 컬렉터) 일시 정지를 경험해보셨을 겁니다. rvLLM은 이 문제를 정면으로 해결하기 위해 Rust로 처음부터 완전히 재작성한 LLM 추론 엔진입니다. OpenAI 호환 API를 그대로 제공하면서도, Python 런타임 없이 단일 정적 바이너리 하나만으로 배포할 수 있도록 설계되었습니다.
rvLLM은 40개의 직접 작성한 CUDA 커널, 순수 f16 엔드-투-엔드 연산, CUDA 그래프 리플레이, 퓨즈드 커널 디코드를 탑재하여 H100 SXM 80GB에서 Qwen2.5-1.5B 기준 최대 40,714 tok/s를 달성합니다. 시작 시간은 vLLM 대비 20배 빠른 6초, 바이너리 크기는 31배 작은 16MB로, LLM 서빙 인프라의 경량화를 원하는 개발자들에게 실질적인 대안이 됩니다.
rvLLM 프로젝트는 개발자 Andy Norris가 Claude와 렌탈 GPU만으로 22시간 만에 완성한 것으로, 2026년 3월 27일 오픈소스로 공개되었습니다.
rvLLM vs Python vLLM 비교
rvLLM의 가장 큰 차별점은 Python 런타임 의존성을 완전히 제거한 것입니다. 아래 표는 두 엔진의 주요 특성을 비교한 것입니다:
| 항목 | rvLLM | Python vLLM |
|---|---|---|
| 시작 시간 | 6초 | ~120초 |
| 바이너리 크기 | 16MB | ~500MB |
| CPU 메모리 | 348MB | ~1GB |
| 의존성 | 없음 (정적 바이너리) | PyTorch + 500MB 패키지 |
| P95 레이턴시 분산 | 34ms (1.4%) | 190ms (12%) |
| GC 일시 정지 | 없음 | 있음 |
| GIL | 없음 | 있음 |
Python vLLM과의 HTTP 벤치마크(퓨전 적용 전, Qwen2.5-7B 기준)에서는 처리량이 아직 vLLM 대비 0.67x 수준이지만, 직접 엔진 경로(HTTP 오버헤드 없음) 기준 N=128에서는 12,624 tok/s로 측정되었습니다. HTTP 헤드-투-헤드 비교는 현재 진행 중입니다.
rvLLM의 핵심 아키텍처와 최적화 기법
CUDA 그래프 리플레이
CUDA 그래프 리플레이(CUDA Graph Replay)는 rvLLM 성능 향상의 가장 큰 단일 요인입니다. 이전 구현에서는 13개 배치 크기에 대해 그래프가 시작 시 캡처되었지만, temperature == 0.0(탐욕적 디코딩)인 요청에만 리플레이가 적용되는 조건이 걸려 있어 실제로는 리플레이가 전혀 이루어지지 않았습니다. CUDA 그래프는 샘플링이 아닌 순전파 패스(GEMM, 어텐션, 정규화)만 캡처하기 때문에, 이 조건을 제거하자 모든 디코드 스텝이 사전 캡처된 그래프를 리플레이할 수 있게 되어 스텝당 약 254번의 커널 런치 호출이 제거되었습니다. 그 결과 단번에 +178% 처리량 개선이 이루어졌습니다.
추가로 발견된 문제는 그래프 리플레이 일관성 버그였습니다. 이전 구현에서는 CudaGraph::replay()가 호출자의 CUDA 스트림이 아닌 캡처된 스트림에서 실행되어, 메타데이터(블록 테이블, 컨텍스트 길이)의 HtoD 업로드와 CUDA 스트림 순서가 어긋났습니다. 이를 호출자의 스트림에서 실행하도록 수정하여 스테일 메타데이터 문제를 해결했습니다.
퓨즈드 CUDA 커널
rvLLM은 다수의 커널을 하나로 합치는 퓨전(Fusion) 전략을 적극 활용합니다. 각 레이어에서 Add+RMSNorm+QKV GEMV, Add+RMSNorm+GateUp GEMV, SiLU*Mul+Down GEMV를 각각 단일 퓨즈드 커널로 처리하여 레이어당 총 6번의 커널 호출을 절감합니다. 활성화 버퍼도 제거되어 메모리 대역폭 효율이 높아집니다. 현재는 JIT 커널 퓨전(crates/rvllm-fusion/) 코드젠이 준비된 상태로, 이 기능이 완성되면 추가적인 처리량 향상이 기대됩니다.
PagedAttention과 FlashAttention-3
KV 캐시 관리는 PagedAttention(블록 테이블 기반)으로 구현되어 있으며, 어텐션 연산은 직접 작성한 CUDA 커널로 구현된 FlashAttention-2/3를 사용합니다. GQA(Grouped Query Attention) 최적화가 적용된 FA3 어텐션 커널은 Qwen2.5(12 헤드 / 2 KV 헤드) 기준 KV 대역폭을 6배 절감합니다. f16 KV 캐시를 기본으로 사용하고, FP8 E4M3 양자화 KV 캐시도 지원합니다.
Rust의 시스템 수준 이점
Python의 GIL(Global Interpreter Lock) 문제로 인해 vLLM의 스케줄러, 토크나이저, 출력 처리는 싱글 스레드로 동작합니다. rvLLM은 Rust의 Rayon 병렬 처리를 통해 배치 샘플링(64개 시퀀스)에서 Python 대비 8.5배 빠른 성능을 보입니다. GC가 없어 메모리는 스코프를 벗어나는 즉시 결정론적으로 해제되며, P95 레이턴시 분산이 1.4%로 vLLM의 12%보다 훨씬 안정적입니다.
rvLLM의 벤치마크 결과
H100 SXM 80GB 직접 엔진 벤치마크
아래는 HTTP 오버헤드 없는 직접 엔진 경로에서 greedy 디코딩, 요청당 32 출력 토큰 기준 측정한 결과입니다 (2026-03-30, Phase 5 커널 퓨전 이후):
Qwen2.5-7B f16
| N | tok/s | wall_ms |
|---|---|---|
| 1 | 108 | 296 |
| 32 | 3,911 | 261 |
| 64 | 7,300 | 280 |
| 128 | 12,624 | 324 |
Qwen2.5-1.5B f16
| N | tok/s | wall_ms |
|---|---|---|
| 1 | 240 | 133 |
| 64 | 15,812 | 129 |
| 128 | 26,161 | 156 |
| 256 | 40,714 | 194 |
CPU 샘플링 컴포넌트 벤치마크
GPU 순전파 사이에 CPU에서 실행되는 연산의 Python(numpy) 대비 속도입니다:
| 연산 | Rust | Python | 속도 향상 |
|---|---|---|---|
| Combined penalties (2K 토큰) | 2.6 µs | 63 µs | 24x |
| Multinomial 샘플링 (32K vocab) | 12 µs | 66 µs | 5.5x |
| 배치 샘플링 (64개, Rayon) | 4.3 ms | 36.4 ms | 8.5x |
최적화 진행 이력
| Phase | N=1 tok/s | N=32 tok/s | 핵심 변경 사항 |
|---|---|---|---|
| Phase 4 | 130 | 3,467 | CUDA 그래프 캡처 완성 |
| Phase 5 | 174 | 4,276 | 10-에이전트 스웜: 캐스트 감소, 퓨즈드 연산 |
| Full f16 | 200 | - | 전체 f16 커널 |
| 9-에이전트 커널 | 236 | 5,123 | 크로스-레이어 퓨전, memset 제거 |
| GPU 전용 스레드 | 218 | 6,098 | GPU 전용 OS 스레드 |
rvLLM 지원 모델 아키텍처
| 아키텍처 | 모델 | 상태 |
|---|---|---|
| LlamaForCausalLM | Llama 2/3, CodeLlama, Vicuna | 동작 확인 |
| MistralForCausalLM | Mistral 7B, Mistral Nemo | 동작 확인 |
| Qwen2ForCausalLM | Qwen2, Qwen2.5 | 동작 확인 |
| PhiForCausalLM | Phi-2, Phi-3, Phi-3.5 | 구현됨 |
| GemmaForCausalLM | Gemma, Gemma 2 | 구현됨 |
| MixtralForCausalLM | Mixtral 8x7B, 8x22B | 구현됨 |
| DeepseekV2ForCausalLM | DeepSeek-V2, DeepSeek-V2.5 | 구현됨 |
지원 GPU는 V100(sm_70)부터 RTX 5090/Blackwell(sm_120)까지이며, CUDA 12.8+ 이상이면 B100/B200도 지원합니다.
rvLLM 설치 및 사용법
설치
# crates.io에서 설치
cargo install rvllm
# PyPI에서 설치
pip install rvllm
서버 실행
# vLLM과 완전히 동일한 명령어 형식
rvllm serve --model Qwen/Qwen2.5-7B-Instruct --port 8000
# GPU 메모리 설정 및 최대 시퀀스 수 조정
rvllm serve \
--model Qwen/Qwen2.5-7B-Instruct \
--gpu-memory-utilization 0.90 \
--max-num-seqs 256 \
--dtype auto
Python 바인딩 사용
import rvllm
# 빠른 샘플링 (Rayon 병렬 처리, 서버 불필요)
sampler = rvllm.Sampler()
result = sampler.sample(logits=[1.0, 2.0, 3.0], temperature=0.8, top_k=50)
# 토크나이저
tok = rvllm.Tokenizer.from_pretrained("Qwen/Qwen2.5-1.5B")
ids = tok.encode("Hello world")
# 병렬 배치 샘플링 (Python 순차 처리 대비 8배 빠름)
results = rvllm.sample_batch(
logits_batch=[[1.0, 2.0] * 16000] * 64,
temperature=0.8, top_p=0.95, seed=42,
)
벤치마크 실행
rvllm benchmark --model Qwen/Qwen2.5-7B-Instruct
소스 빌드 (GPU 없는 개발 환경)
# Mock-GPU 백엔드로 GPU 없이 개발 가능
cargo build --workspace --features mock-gpu
cargo test --workspace
라이선스
rvLLM은 Apache-2.0 라이선스로 공개되어 있어 개인 및 상업적 목적으로 자유롭게 사용할 수 있습니다.
rvLLM 프로젝트 GitHub 저장소
이 글은 GPT 모델로 정리한 글을 바탕으로 한 것으로, 원문의 내용 또는 의도와 다르게 정리된 내용이 있을 수 있습니다. 관심있는 내용이시라면 원문도 함께 참고해주세요! 읽으시면서 어색하거나 잘못된 내용을 발견하시면 덧글로 알려주시기를 부탁드립니다. ![]()
파이토치 한국 사용자 모임
이 정리한 이 글이 유용하셨나요? 회원으로 가입하시면 주요 글들을 이메일
로 보내드립니다! (기본은 Weekly지만 Daily로 변경도 가능합니다.)
아래
쪽에 좋아요
를 눌러주시면 새로운 소식들을 정리하고 공유하는데 힘이 됩니다~ ![]()
