vLLM 빠른 시작: 고성능 LLM 서빙

OpenAI API를 사용한 빠른 LLM 추론

Page content

vLLM은 UC 버클리의 Sky Computing Lab에서 개발한 대규모 언어 모델(LLM)을 위한 고처리량, 메모리 효율적인 추론 및 서빙 엔진입니다.

혁신적인 PagedAttention 알고리즘을 통해 vLLM은 전통적인 서빙 방법보다 14~24배 더 높은 처리량을 달성하며, 프로덕션 LLM 배포에 대한 최고 선택지가 되었습니다.

vllm 로고

vLLM이란?

vLLM(가상 LLM)은 2023년에 발표된 빠른 LLM 추론 및 서빙을 위한 오픈소스 라이브러리로, 프로덕션 배포에 대한 산업 표준이 되었습니다. PagedAttention이라는 획기적인 메모리 관리 기술을 도입하여 서빙 효율성을 크게 향상시켰습니다.

주요 기능

높은 처리량 성능: vLLM은 동일한 하드웨어에서 HuggingFace Transformers보다 14~24배 더 높은 처리량을 제공합니다. 이와 같은 성능 향상은 지속적인 배치, 최적화된 CUDA 커널, 메모리 조각화를 제거하는 PagedAttention 알고리즘에서 비롯됩니다.

OpenAI API 호환성: vLLM은 OpenAI의 형식과 완전히 호환되는 내장 API 서버를 제공합니다. 이는 OpenAI에서 자체 호스팅 인프라로 이전할 때 애플리케이션 코드를 변경하지 않고도 원활한 마이그레이션이 가능하게 합니다. 단순히 API 클라이언트를 vLLM의 엔드포인트로 연결하면 투명하게 작동합니다.

PagedAttention 알고리즘: vLLM의 성능의 핵심 혁신은 PagedAttention으로, 가상 메모리 페이지 개념을 어텐션 메커니즘에 적용합니다. KV 캐시에 연속적인 메모리 블록을 할당하는 대신, PagedAttention은 고정 크기의 블록으로 나누어 필요 시 할당할 수 있도록 합니다. 이는 메모리 낭비를 최대 4배까지 줄이고, 훨씬 더 큰 배치 크기를 가능하게 합니다.

지속적인 배치: 정적 배치에서 모든 시퀀스가 완료될 때까지 기다리는 것과 달리, vLLM은 지속적인(롤링) 배치를 사용합니다. 하나의 시퀀스가 완료되면 즉시 새로운 시퀀스가 배치에 추가됩니다. 이는 GPU 활용률을 최대화하고, 들어오는 요청의 지연 시간을 최소화합니다.

다중 GPU 지원: vLLM은 텐서 병렬성 및 파이프라인 병렬성을 지원하여 대규모 모델을 여러 GPU에 걸쳐 분산 처리할 수 있습니다. 단일 GPU 메모리에 맞지 않는 모델도 지원하며, 2개에서 8개 이상의 GPU 구성까지 지원합니다.

광범위한 모델 지원: LLaMA, Mistral, Mixtral, Qwen, Phi, Gemma 및 기타 여러 인기 모델 아키텍처와 호환됩니다. HuggingFace Hub의 지시 조정 모델 및 기초 모델 모두 지원합니다.

vLLM을 사용해야 할 경우

vLLM은 특정 시나리오에서 강점을 발휘합니다:

프로덕션 API 서비스: 많은 동시 사용자에게 LLM을 API를 통해 제공해야 하는 경우, vLLM의 높은 처리량 및 효율적인 배치 기능이 최적의 선택입니다. 챗봇, 코드 어시스턴트, 콘텐츠 생성 서비스를 운영하는 회사는 초당 수백 개의 요청을 처리하는 데 이 기능을 활용할 수 있습니다.

높은 동시성 워크로드: 애플리케이션이 많은 동시 사용자가 요청을 보내는 경우, vLLM의 지속적인 배치 및 PagedAttention 기능은 동일한 하드웨어로 더 많은 사용자를 서비스할 수 있게 합니다.

비용 최적화: GPU 비용이 걱정되는 경우, vLLM의 우수한 처리량은 동일한 트래픽을 처리하기 위해 더 적은 GPU를 사용할 수 있게 하여 인프라 비용을 직접 줄일 수 있습니다. PagedAttention으로부터 얻은 4배의 메모리 효율성은 더 작고 저렴한 GPU 인스턴스 사용을 가능하게 합니다.

Kubernetes 배포: vLLM의 무상태 설계 및 컨테이너 친화적인 아키텍처는 Kubernetes 클러스터에 이상적입니다. 하중 상태에서 일관된 성능과 간단한 리소스 관리가 클라우드 네이티브 인프라와 잘 통합됩니다.

vLLM을 사용하지 말아야 할 경우: 로컬 개발, 실험, 단일 사용자 시나리오에서는 Ollama와 같은 도구가 더 간단한 설정으로 더 나은 사용자 경험을 제공합니다. vLLM의 복잡성은 프로덕션 워크로드에서 성능 우위를 위해 정당화됩니다.

vLLM 설치 방법

사전 조건

vLLM을 설치하기 전에 시스템이 다음 요구사항을 충족하는지 확인하세요:

  • GPU: NVIDIA GPU, compute capability 7.0 이상 (V100, T4, A10, A100, H100, RTX 20/30/40 시리즈)
  • CUDA: 11.8 이상 버전
  • Python: 3.8~3.11
  • VRAM: 7B 모델은 최소 16GB, 13B는 24GB 이상, 더 큰 모델은 40GB 이상
  • 드라이버: NVIDIA 드라이버 450.80.02 이상

pip를 통한 설치

가장 간단한 설치 방법은 pip를 사용하는 것입니다. 이 방법은 CUDA 11.8 이상의 시스템에서 작동합니다:

# 가상 환경 생성 (권장)
python3 -m venv vllm-env
source vllm-env/bin/activate

# vLLM 설치
pip install vllm

# 설치 확인
python -c "import vllm; print(vllm.__version__)"

다른 CUDA 버전을 사용하는 시스템에서는 적절한 바이너리를 설치하세요:

# CUDA 12.1
pip install vllm==0.4.2+cu121 -f https://github.com/vllm-project/vllm/releases

# CUDA 11.8
pip install vllm==0.4.2+cu118 -f https://github.com/vllm-project/vllm/releases

Docker를 통한 설치

Docker는 특히 프로덕션 환경에서 가장 신뢰할 수 있는 배포 방법입니다:

# 공식 vLLM 이미지 끌어오기
docker pull vllm/vllm-openai:latest

# GPU 지원으로 vLLM 실행
docker run --runtime nvidia --gpus all \
    -v ~/.cache/huggingface:/root/.cache/huggingface \
    -p 8000:8000 \
    --ipc=host \
    vllm/vllm-openai:latest \
    --model mistralai/Mistral-7B-Instruct-v0.2

--ipc=host 플래그는 다중 GPU 설정에서 필요한 프로세스 간 통신을 가능하게 합니다.

소스에서 빌드

최신 기능이나 커스텀 수정이 필요한 경우 소스에서 빌드하세요:

git clone https://github.com/vllm-project/vllm.git
cd vllm
pip install -e .

vLLM 빠른 시작 가이드

첫 번째 모델 실행

명령줄 인터페이스를 사용하여 모델을 시작하세요:

# OpenAI 호환 API로 Mistral-7B 다운로드 및 제공
python -m vllm.entrypoints.openai.api_server \
    --model mistralai/Mistral-7B-Instruct-v0.2 \
    --port 8000

vLLM은 HuggingFace Hub에서 모델을 자동으로 다운로드(캐시되지 않은 경우)하고 서버를 시작합니다. 서버가 준비되었음을 나타내는 출력을 볼 수 있습니다:

INFO:     Started server process [12345]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000

API 요청 보내기

서버가 실행 중이면 OpenAI Python 클라이언트 또는 curl을 사용하여 요청을 보낼 수 있습니다:

curl 사용:

curl http://localhost:8000/v1/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "mistralai/Mistral-7B-Instruct-v0.2",
        "prompt": "vLLM이란 무엇인지 한 문장으로 설명해주세요:",
        "max_tokens": 100,
        "temperature": 0.7
    }'

OpenAI Python 클라이언트 사용:

from openai import OpenAI

# vLLM 서버로 설정
client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="not-needed"  # vLLM은 기본적으로 인증이 필요하지 않습니다
)

response = client.completions.create(
    model="mistralai/Mistral-7B-Instruct-v0.2",
    prompt="vLLM이란 무엇인지 한 문장으로 설명해주세요:",
    max_tokens=100,
    temperature=0.7
)

print(response.choices[0].text)

채팅 완성 API:

response = client.chat.completions.create(
    model="mistralai/Mistral-7B-Instruct-v0.2",
    messages=[
        {"role": "system", "content": "도움이 되는 어시스턴트입니다."},
        {"role": "user", "content": "PagedAttention이란 무엇인가요?"}
    ],
    max_tokens=200
)

print(response.choices[0].message.content)

고급 설정

vLLM은 성능 최적화를 위해 다양한 파라미터를 제공합니다:

python -m vllm.entrypoints.openai.api_server \
    --model mistralai/Mistral-7B-Instruct-v0.2 \
    --port 8000 \
    --gpu-memory-utilization 0.95 \  # GPU 메모리의 95% 사용
    --max-model-len 8192 \            # 최대 시퀀스 길이
    --tensor-parallel-size 2 \        # 2개의 GPU에서 텐서 병렬성 사용
    --dtype float16 \                 # FP16 정밀도 사용
    --max-num-seqs 256                # 최대 배치 크기

주요 파라미터 설명:

  • --gpu-memory-utilization: GPU 메모리 사용량 (0.90 = 90%). 값이 높을수록 더 큰 배치를 허용하지만, 메모리 스파이크에 대한 여유가 줄어듭니다.
  • --max-model-len: 최대 컨텍스트 길이. 이 값을 줄이면 더 큰 배치를 위한 메모리가 절약됩니다.
  • --tensor-parallel-size: 모델을 분할할 GPU 수.
  • --dtype: 가중치의 데이터 타입 (float16, bfloat16, float32). FP16이 일반적으로 최적입니다.
  • --max-num-seqs: 배치에서 처리할 최대 시퀀스 수.

vLLM vs Ollama 비교

vLLM과 Ollama는 모두 로컬 LLM 호스팅에 인기 있는 선택지이지만, 다른 사용 사례를 대상으로 합니다. 각 도구를 사용해야 할 시점에 대한 이해는 프로젝트의 성공에 큰 영향을 줄 수 있습니다.

성능 및 처리량

vLLM은 다중 사용자 시나리오에서 최대 처리량을 위해 설계되었습니다. PagedAttention 알고리즘과 지속적인 배치 기능은 수백 개의 동시 요청을 효율적으로 처리할 수 있습니다. 벤치마크에 따르면, vLLM은 표준 구현보다 1424배, 고 동시성 상태에서는 Ollama보다 24배 더 높은 처리량을 달성합니다.

Ollama는 단일 사용자 상호작용을 최적화하고, 개별 요청에 대한 낮은 지연 시간을 제공합니다. vLLM의 다중 사용자 처리량과는 차이가 있지만, 개발 및 개인 사용에 대한 탁월한 성능을 제공합니다. 더 빠른 냉시작 시간과 비활성 리소스 소비를 줄입니다.

사용 용이성

Ollama는 단순성에서 압도적인 우위를 차지합니다. 설치는 단일 명령 (curl | sh)으로 가능하며, 모델 실행은 ollama run llama2처럼 간단합니다. 정량화된 버전의 모델 라이브러리가 포함되어 있으며, 다양한 하드웨어 프로필에 최적화되어 있습니다. 사용자 경험은 Docker와 유사합니다 – 끌어오기, 실행, 그리고 바로 시작할 수 있습니다.

vLLM은 더 많은 설정이 필요합니다: Python 환경 관리, CUDA 설치, 서빙 파라미터에 대한 이해, 수동 모델 지정이 필요합니다. 학습 곡선은 더 가파르지만, 하드웨어에서 최대 성능을 뽑아내는 세부적인 제어를 제공합니다. 이 복잡성은 프로덕션 배포에서 필요합니다.

API 및 통합

vLLM은 OpenAI 호환 REST API를 기본 제공하여 기존 애플리케이션에서 OpenAI API로의 대체가 가능합니다. 이는 클라우드 제공업체에서 자체 호스팅 인프라로의 프로덕션 서비스 마이그레이션 시 코드 변경 없이 매우 중요합니다.

Ollama은 간단한 REST API와 Python/JavaScript 라이브러리를 제공합니다. 기능적으로는 OpenAI 호환성이 없어, OpenAI 형식을 기대하는 애플리케이션과 통합할 때 코드 변경이 필요합니다. 그러나 Ollama-OpenAI 어댑터와 같은 커뮤니티 프로젝트가 이 격차를 해소합니다.

메모리 관리

vLLM의 PagedAttention 알고리즘은 동시 요청에 대한 우수한 메모리 효율성을 제공합니다. 동일한 VRAM으로 표준 구현보다 2~4배 더 많은 동시 사용자를 서비스할 수 있습니다. 이는 프로덕션 배포에서 직접적인 비용 절감으로 이어집니다.

Ollama은 단일 사용자 시나리오에 적합한 간단한 메모리 관리를 사용합니다. 자동으로 모델의 로딩/언로딩을 관리하지만, 이는 개발에 편리하지만 고 동시성 프로덕션 사용에는 최적화되지 않습니다.

다중 GPU 지원

vLLM은 텐서 병렬성 및 파이프라인 병렬성을 원ative로 지원하여 2~8개 이상의 GPU에 걸쳐 모델을 효율적으로 분산합니다. 이는 70B 파라미터 LLM과 같은 큰 모델을 단일 GPU에 맞지 않는 경우에 필수적입니다.

Ollama은 현재 다중 GPU 지원이 제한되어 있으며, 주로 단일 GPU에서 가장 잘 작동합니다. 이는 분산 추론이 필요한 매우 큰 모델에 적합하지 않습니다.

사용 사례 추천

vLLM을 선택할 때:

  • 많은 동시 사용자에게 LLM API를 제공해야 할 때
  • 클라우드 배포에서 요청당 비용을 최적화해야 할 때
  • Kubernetes 또는 컨테이너 오케스트레이션 플랫폼에서 실행할 때
  • 기존 애플리케이션에 OpenAI API 호환성이 필요할 때
  • 다중 GPU 지원이 필요한 대규모 모델을 제공할 때
  • 성능과 처리량이 필수적인 요구사항일 때

Ollama를 선택할 때:

  • 로컬 개발 및 실험
  • 단일 사용자 상호작용 (개인 어시스턴트, 챗봇)
  • 빠른 프로토타이핑 및 모델 평가
  • LLM에 대한 학습이 필요하지만 인프라 복잡성 없이
  • 개인 워크스테이션 또는 데스크탑에서 실행할 때
  • 간단함과 사용 용이성이 우선시될 때

많은 팀은 두 도구 모두를 사용합니다: Ollama는 개발 및 실험에, vLLM은 프로덕션 배포에 사용합니다. 이 조합은 개발자 생산성을 유지하면서 프로덕션 성능을 보장합니다.

vLLM vs Docker 모델 러너 비교

Docker는 최근 Model Runner (이전에는 GenAI Stack)를 로컬 AI 모델 배포를 위한 공식 솔루션으로 발표했습니다. 이는 vLLM과 어떻게 비교되는가?

아키텍처 철학

Docker Model Runner는 “AI용 Docker"라는 목표를 가지고 있으며, 컨테이너를 실행하는 것과 동일한 간단하고 표준화된 방식으로 로컬에서 AI 모델을 실행할 수 있도록 설계되었습니다. 이는 다양한 모델과 프레임워크에 걸쳐 일관된 인터페이스를 제공합니다.

vLLM은 LLM 서빙에 집중한 전문적인 추론 엔진이며, 최대 성능을 위해 설계되었습니다. 이는 더 낮은 수준의 도구이며, Docker로 컨테이너화해야 하며, 완전한 플랫폼은 아닙니다.

설정 및 시작

Docker Model Runner 설치는 Docker 사용자에게 간단합니다:

docker model pull llama3:8b
docker model run llama3:8b

이 Docker의 이미지 워크플로와의 유사성은 이미 컨테이너를 사용하는 개발자들에게 즉시 익숙하게 됩니다.

vLLM은 더 많은 초기 설정 (Python, CUDA, 의존성) 또는 사전 빌드된 Docker 이미지 사용이 필요합니다:

docker pull vllm/vllm-openai:latest
docker run --runtime nvidia --gpus all vllm/vllm-openai:latest --model <모델 이름>

성능 특성

vLLM은 PagedAttention 알고리즘과 지속적인 배치 기능 덕분에 다중 사용자 시나리오에서 우수한 처리량을 제공합니다. 프로덕션 API 서비스가 초당 수백 개의 요청을 처리해야 하는 경우, vLLM의 최적화는 일반적인 서빙 접근법보다 2~5배 더 높은 처리량을 제공합니다.

Docker Model Runner은 사용 편의성보다 최대 성능에 집중합니다. 이는 로컬 개발, 테스트 및 중간 규모의 워크로드에 적합하지만, vLLM이 스케일에서 우수한 최적화를 제공하는 것과는 차이가 있습니다.

모델 지원

Docker Model Runner은 인기 있는 모델에 대한 정리된 라이브러리를 제공하며, 단일 명령으로 접근할 수 있습니다. Stable Diffusion, Whisper 및 기타 AI 모델을 포함한 여러 프레임워크를 지원하므로, 다양한 AI 워크로드에 더 적합합니다.

vLLM은 LLM 추론에 특화되어 있으며, transformer 기반 언어 모델에 깊은 지원을 제공합니다. HuggingFace 호환 LLM은 지원하지만, 이미지 생성이나 음성 인식과 같은 다른 AI 모델 유형에는 확장되지 않습니다.

프로덕션 배포

vLLM은 Anthropic, Replicate 및 기타 회사에서 일일 수십억 토큰을 처리하는 프로덕션 환경에서 테스트되었습니다. 무거운 부하 상태에서도 안정적인 성능을 제공하며, 프로덕션 LLM 서빙의 표준이 되었습니다.

Docker Model Runner은 더 최근에 발표되었으며, 개발 및 로컬 테스트 시나리오에 더 적합합니다. 프로덕션 트래픽을 처리할 수 있지만, 프로덕션 배포에 필요한 검증된 기록과 성능 최적화는 부족합니다.

통합 생태계

vLLM은 프로덕션 인프라 도구와 통합: Kubernetes 오퍼레이터, Prometheus 메트릭, Ray 분산 서빙, 그리고 기존 애플리케이션에 대한 OpenAI API 호환성.

Docker Model Runner은 Docker의 생태계와 Docker Desktop과 자연스럽게 통합됩니다. Docker에 표준화된 팀은 이 통합으로 일관된 경험을 제공하지만, 특화된 LLM 서빙 기능은 적습니다.

각각 사용할 때

vLLM을 사용할 때:

  • 프로덕션 LLM API 서비스
  • 고처리량, 다중 사용자 배포
  • 클라우드 배포에서 비용 효율성을 최적화해야 할 때
  • Kubernetes 및 클라우드 네이티브 환경
  • 확장성과 성능이 필수적인 경우

Docker Model Runner를 사용할 때:

  • 로컬 개발 및 테스트
  • 다양한 AI 모델 유형 (LLM뿐만 아니라)
  • Docker 생태계에 깊이 투자한 팀
  • 인프라 설정 없이 빠른 실험
  • 학습 및 교육 목적

혼합 접근법: 많은 팀은 Docker Model Runner를 로컬에서 편리하게 사용하여 개발하고, vLLM을 프로덕션에서 성능을 위해 배포합니다. Docker Model Runner 이미지도 vLLM 컨테이너를 실행할 수 있어, 두 접근법을 결합할 수 있습니다.

프로덕션 배포 최고의 실천 방법

Docker 배포

생산용 Docker Compose 구성 파일을 생성하세요:

version: '3.8'

services:
  vllm:
    image: vllm/vllm-openai:latest
    runtime: nvidia
    environment:
      - CUDA_VISIBLE_DEVICES=0,1
    volumes:
      - ~/.cache/huggingface:/root/.cache/huggingface
      - ./logs:/logs
    ports:
      - "8000:8000"
    command: >
      --model mistralai/Mistral-7B-Instruct-v0.2
      --tensor-parallel-size 2
      --gpu-memory-utilization 0.90
      --max-num-seqs 256
      --max-model-len 8192      
    restart: unless-stopped
    shm_size: '16gb'
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 2
              capabilities: [gpu]

Kubernetes 배포

Kubernetes에서 vLLM을 배포하여 생산 규모를 달성하세요:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-server
spec:
  replicas: 2
  selector:
    matchLabels:
      app: vllm
  template:
    metadata:
      labels:
        app: vllm
    spec:
      containers:
      - name: vllm
        image: vllm/vllm-openai:latest
        args:
          - --model
          - mistralai/Mistral-7B-Instruct-v0.2
          - --tensor-parallel-size
          - "2"
          - --gpu-memory-utilization
          - "0.90"
        resources:
          limits:
            nvidia.com/gpu: 2
        ports:
        - containerPort: 8000
        volumeMounts:
        - name: cache
          mountPath: /root/.cache/huggingface
      volumes:
      - name: cache
        hostPath:
          path: /mnt/huggingface-cache
---
apiVersion: v1
kind: Service
metadata:
  name: vllm-service
spec:
  selector:
    app: vllm
  ports:
  - port: 80
    targetPort: 8000
  type: LoadBalancer

모니터링 및 가시성

vLLM은 모니터링을 위해 Prometheus 메트릭을 제공합니다:

import requests

# 메트릭 가져오기
metrics = requests.get("http://localhost:8000/metrics").text
print(metrics)

모니터링해야 할 주요 메트릭:

  • vllm:num_requests_running - 활성 요청
  • vllm:gpu_cache_usage_perc - KV 캐시 사용률
  • vllm:time_to_first_token - 지연 시간 메트릭
  • vllm:time_per_output_token - 생성 속도

성능 최적화

GPU 메모리 사용률 최적화: --gpu-memory-utilization 0.90에서 시작하고 관찰된 행동에 따라 조정하세요. 더 높은 값은 더 큰 배치를 허용하지만, 트래픽 스파이크 시 OOM 오류 위험이 있습니다.

최대 시퀀스 길이 조정: 사용 사례가 전체 컨텍스트 길이를 필요로 하지 않는 경우, --max-model-len을 줄이세요. 이는 더 큰 배치를 위한 메모리를 해제합니다. 예를 들어, 4K 컨텍스트만 필요하다면 --max-model-len 4096을 설정하세요.

적절한 양자화 선택: 모델이 지원하는 경우, 양자화된 버전(8비트, 4비트)을 사용하여 메모리 사용량을 줄이고 처리량을 증가시킬 수 있습니다:

--quantization awq  # AWQ 양자화 모델 사용
--quantization gptq # GPTQ 양자화 모델 사용

프리픽스 캐싱 활성화: 반복적인 프롬프트(예: 시스템 메시지가 있는 챗봇)를 위한 프리픽스 캐싱을 활성화하세요:

--enable-prefix-caching

이 기능은 공통 프리픽스의 KV 값을 캐시하여, 동일한 프롬프트 프리픽스를 공유하는 요청의 계산을 줄입니다.

일반적인 문제 해결

메모리 부족 오류

증상: 서버가 CUDA 메모리 부족 오류로 인해 크래시합니다.

해결책:

  • --gpu-memory-utilization을 0.85 또는 0.80로 줄이세요
  • 사용 사례가 허용하는 경우 --max-model-len을 줄이세요
  • --max-num-seqs를 줄여 배치 크기를 줄이세요
  • 양자화된 모델 버전을 사용하세요
  • 텐서 병렬성을 활성화하여 더 많은 GPU에 분산하세요

낮은 처리량

증상: 서버가 예상보다 적은 요청을 처리합니다.

해결책:

  • --max-num-seqs를 증가시켜 더 큰 배치를 허용하세요
  • 여유가 있다면 --gpu-memory-utilization을 증가시켜 보세요
  • htop으로 CPU 병목 현상을 확인하세요 – 더 빠른 CPU를 고려하세요
  • nvidia-smi로 GPU 사용률을 확인하세요 – 95% 이상이어야 합니다
  • FP32를 사용하는 경우 FP16으로 전환하세요: --dtype float16

첫 토큰 생성 지연

증상: 생성이 시작되기 전에 높은 지연 시간이 발생합니다.

해결책:

  • 지연 시간이 중요한 애플리케이션에 작은 모델을 사용하세요
  • 반복적인 프롬프트에 대해 프리픽스 캐싱을 활성화하세요
  • --max-num-seqs를 줄여 지연 시간을 우선시하세요
  • 지원되는 모델에 대해 예측적 생성을 고려하세요
  • 텐서 병렬성 구성 최적화

모델 로딩 실패

증상: 서버가 시작되지 않거나 모델을 로딩하지 못합니다.

해결책:

  • 모델 이름이 HuggingFace 형식과 정확히 일치하는지 확인하세요
  • HuggingFace Hub로의 네트워크 연결 상태를 확인하세요
  • ~/.cache/huggingface에 충분한 디스크 공간이 있는지 확인하세요
  • 게이트된 모델인 경우 HF_TOKEN 환경 변수를 설정하세요
  • huggingface-cli download <모델>을 사용하여 수동으로 다운로드해 보세요

고급 기능

예측적 생성

vLLM은 작은 드래프트 모델이 토큰을 제안하고, 큰 타겟 모델이 검증하는 예측적 생성을 지원합니다. 이는 생성 속도를 1.5~2배 빠르게 만들 수 있습니다:

python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-2-70b-chat-hf \
    --speculative-model meta-llama/Llama-2-7b-chat-hf \
    --num-speculative-tokens 5

LoRA 어댑터

기본 모델 위에 여러 LoRA 어댑터를 서빙하는 데, 여러 전체 모델을 로딩하지 않고도 가능합니다:

python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-2-7b-hf \
    --enable-lora \
    --lora-modules sql-lora=./path/to/sql-adapter \
                   code-lora=./path/to/code-adapter

그 후 요청별로 사용할 어댑터를 지정할 수 있습니다:

response = client.completions.create(
    model="sql-lora",  # SQL 어댑터 사용
    prompt="이를 SQL 쿼리로 변환해주세요: 이 달에 생성된 모든 사용자 보여주세요"
)

다중 LoRA 서빙

vLLM의 다중 LoRA 서빙은 수십 개의 미세 조정 어댑터를 최소한의 메모리 오버헤드로 호스팅할 수 있습니다. 이는 고객별 또는 작업별 모델 변형을 제공하는 데 이상적입니다:

# 특정 LoRA 어댑터와 함께 요청
response = client.chat.completions.create(
    model="meta-llama/Llama-2-7b-hf",
    messages=[{"role": "user", "content": "SQL 쿼리 작성"}],
    extra_body={"lora_name": "sql-lora"}
)

프리픽스 캐싱

반복적인 프롬프트 프리픽스를 위한 자동 프리픽스 캐싱을 활성화하여, KV 캐시를 재계산하지 않도록 하세요:

--enable-prefix-caching

이 기능은 특히 다음과 같은 경우에 효과적입니다:

  • 고정된 시스템 프롬프트가 있는 챗봇
  • 일관된 컨텍스트 템플릿이 있는 RAG 애플리케이션
  • 요청 간 반복되는 few-shot 학습 프롬프트

프리픽스 캐싱은 공통 프롬프트 프리픽스를 공유하는 요청의 첫 토큰 시간을 50~80% 줄일 수 있습니다.

통합 예시

LangChain 통합

from langchain.llms import VLLMOpenAI

llm = VLLMOpenAI(
    openai_api_key="EMPTY",
    openai_api_base="http://localhost:8000/v1",
    model_name="mistralai/Mistral-7B-Instruct-v0.2",
    max_tokens=512,
    temperature=0.7,
)

response = llm("PagedAttention을 간단한 용어로 설명해주세요")
print(response)

LlamaIndex 통합

from llama_index.llms import VLLMServer

llm = VLLMServer(
    api_url="http://localhost:8000/v1",
    model="mistralai/Mistral-7B-Instruct-v0.2",
    temperature=0.7,
    max_tokens=512
)

response = llm.complete("vLLM이란 무엇인가요?")
print(response)

FastAPI 애플리케이션

from fastapi import FastAPI
from openai import AsyncOpenAI

app = FastAPI()
client = AsyncOpenAI(
    base_url="http://localhost:8000/v1",
    api_key="not-needed"
)

@app.post("/generate")
async def generate(prompt: str):
    response = await client.completions.create(
        model="mistralai/Mistral-7B-Instruct-v0.2",
        prompt=prompt,
        max_tokens=200
    )
    return {"result": response.choices[0].text}

성능 벤치마크

실제 성능 데이터는 vLLM의 이점을 보여줍니다:

처리량 비교 (Mistral-7B, A100 GPU 사용):

  • vLLM: 64개의 동시 사용자로 약 3,500 토큰/초
  • HuggingFace Transformers: 동일한 동시성으로 약 250 토큰/초
  • Ollama: 동일한 동시성으로 약 1,200 토큰/초
  • 결과: vLLM은 기본 구현보다 14배 향상된 성능을 제공합니다.

메모리 효율성 (LLaMA-2-13B):

  • 표준 구현: 24GB VRAM, 32개의 동시 시퀀스
  • vLLM + PagedAttention: 24GB VRAM, 128개의 동시 시퀀스
  • 결과: 동일한 메모리로 4배 더 많은 동시 요청이 가능합니다.

부하 하의 지연 시간 (Mixtral-8x7B, 2개의 A100 사용):

  • vLLM: 100 req/s에서 P50 지연 시간 180ms, P99 지연 시간 420ms
  • 표준 서빙: 100 req/s에서 P50 지연 시간 650ms, P99 지연 시간 3,200ms
  • 결과: vLLM은 고부하 상태에서도 일관된 지연 시간을 유지합니다.

이러한 벤치마크는 왜 vLLM이 성능이 중요한 프로덕션 LLM 서빙의 표준이 되었는지를 보여줍니다.

비용 분석

vLLM을 선택한 경우의 비용 고려 사항:

시나리오: 하루 1M 요청 처리

표준 서빙 사용 시:

  • 필요: 8개의 A100 GPU (80GB)
  • AWS 비용: $32/시간 × 24 × 30 = $23,040/월
  • 1M 토큰당 비용: $0.75

vLLM 사용 시:

  • 필요: 2개의 A100 GPU (80GB)
  • AWS 비용: $8/시간 × 24 × 30 = $5,760/월
  • 1M 토큰당 비용: $0.19
  • 절약: $17,280/월 (75% 감소)

이 비용 우위는 규모가 커질수록 더 커집니다. 수십억 토큰을 월간으로 처리하는 조직은 vLLM의 최적화된 서빙을 사용하여 수십만 달러의 비용을 절약할 수 있습니다.

보안 고려사항

인증

vLLM은 기본적으로 인증을 포함하지 않습니다. 프로덕션에서는 역방향 프록시 수준에서 인증을 구현하세요:

# Nginx 구성
location /v1/ {
    auth_request /auth;
    proxy_pass http://vllm-backend:8000;
}

location /auth {
    proxy_pass http://auth-service:8080/verify;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}

또는 Kong, Traefik, AWS API Gateway와 같은 API 게이트웨이를 사용하여 기업용 등급의 인증 및 요청 제한을 수행하세요.

네트워크 분리

vLLM은 인터넷에 직접 노출되지 않은 프라이빗 네트워크에서 실행하세요:

# Kubernetes 네트워크 정책 예시
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: vllm-access
spec:
  podSelector:
    matchLabels:
      app: vllm
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: api-gateway
    ports:
    - protocol: TCP
      port: 8000

요청 제한

남용을 방지하기 위해 요청 제한을 구현하세요:

# Redis를 사용한 요청 제한 예시
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
import redis
from datetime import datetime, timedelta

app = FastAPI()
redis_client = redis.Redis(host='localhost', port=6379)

@app.middleware("http")
async def rate_limit_middleware(request, call_next):
    client_ip = request.client.host
    key = f"rate_limit:{client_ip}"
    
    requests = redis_client.incr(key)
    if requests == 1:
        redis_client.expire(key, 60)  # 60초 윈도우
    
    if requests > 60:  # 분당 60 요청
        raise HTTPException(status_code=429, detail="요청 제한 초과")
    
    return await call_next(request)

모델 접근 제어

다중 테넌트 배포의 경우, 사용자가 어떤 모델에 접근할 수 있는지 제어하세요:

ALLOWED_MODELS = {
    "user_tier_1": ["mistralai/Mistral-7B-Instruct-v0.2"],
    "user_tier_2": ["mistralai/Mistral-7B-Instruct-v0.2", "meta-llama/Llama-2-13b-chat-hf"],
    "admin": ["*"]  # 모든 모델
}

def verify_model_access(user_tier: str, model: str) -> bool:
    allowed = ALLOWED_MODELS.get(user_tier, [])
    return "*" in allowed or model in allowed

마이그레이션 가이드

OpenAI에서 vLLM으로

OpenAI에서 자체 호스팅 vLLM으로 마이그레이션은 API 호환성 덕분에 간단합니다:

이전 (OpenAI):

from openai import OpenAI

client = OpenAI(api_key="sk-...")
response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=[{"role": "user", "content": "안녕하세요"}]
)

이후 (vLLM):

from openai import OpenAI

client = OpenAI(
    base_url="https://your-vllm-server.com/v1",
    api_key="your-internal-key"  # 인증이 필요한 경우
)
response = client.chat.completions.create(
    model="mistralai/Mistral-7B-Instruct-v0.2",
    messages=[{"role": "user", "content": "안녕하세요"}]
)

변경해야 할 부분은 두 가지: base_urlmodel 이름. 나머지 코드는 동일하게 유지됩니다.

Ollama에서 vLLM으로

Ollama는 다른 API 형식을 사용합니다. 다음과 같이 전환할 수 있습니다:

Ollama API:

import requests

response = requests.post('http://localhost:11434/api/generate',
    json={
        'model': 'llama2',
        'prompt': '하늘은 왜 파란가요?'
    })

vLLM 등가:

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="not-needed")
response = client.completions.create(
    model="meta-llama/Llama-2-7b-chat-hf",
    prompt="하늘은 왜 파란가요?"
)

코드베이스의 모든 API 호출을 업데이트해야 하지만, OpenAI 클라이언트 라이브러리는 더 나은 오류 처리와 기능을 제공합니다.

HuggingFace Transformers에서 vLLM으로

직접적인 Python 사용 마이그레이션:

HuggingFace:

from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-Instruct-v0.2")
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.2")

inputs = tokenizer("안녕하세요", return_tensors="pt")
outputs = model.generate(**inputs, max_new_tokens=100)
result = tokenizer.decode(outputs[0])

vLLM:

from vllm import LLM, SamplingParams

llm = LLM(model="mistralai/Mistral-7B-Instruct-v0.2")
sampling_params = SamplingParams(max_tokens=100)

outputs = llm.generate("안녕하세요", sampling_params)
result = outputs[0].outputs[0].text

vLLM의 Python API는 배치 추론에 더 간단하고 훨씬 빠릅니다.

vLLM의 미래

vLLM은 빠르게 발전하며 흥미로운 기능들이 도입될 예정입니다:

분리된 서빙: 프리필(프롬프트 처리)과 디코드(토큰 생성)를 다른 GPU에 분리하여 자원 사용률을 최적화합니다. 프리필은 계산에 의존하고, 디코드는 메모리에 의존하기 때문에, 전용 하드웨어에서 실행하여 효율성을 높입니다.

다중 노드 추론: 100B 이상의 파라미터를 가진 매우 큰 모델을 여러 머신에 분산하여 서빙할 수 있도록 합니다. 이는 단일 노드 설정으로는 너무 크기 때문에 필요한 경우에 사용됩니다.

향상된 양자화: llama.cpp에서 사용하는 GGUF와 같은 새로운 양자화 형식을 지원하고, AWQ/GPTQ의 통합을 개선하여 양자화된 모델에 대한 성능을 향상시킵니다.

예측적 생성 개선: 더 효율적인 드래프트 모델과 적응형 예측 전략을 사용하여 정확도 손실 없이 더 빠른 속도 향상을 달성합니다.

어텐션 최적화: FlashAttention 3, 100K 이상의 토큰을 위한 링 어텐션, 그리고 기타 최첨단 어텐션 메커니즘을 지원합니다.

더 나은 모델 커버리지: 다중 모달 모델(시각-언어 모델), 오디오 모델, 그리고 특화된 아키텍처에 대한 지원을 확장합니다.

vLLM 프로젝트는 UC 버클리, Anyscale 및 더 넓은 오픈소스 커뮤니티에서 적극적인 개발을 진행하고 있습니다. LLM 배포가 프로덕션 시스템에 점점 더 중요해지면서, vLLM의 성능 표준으로서의 역할이 계속해서 성장하고 있습니다.

유용한 링크

이 사이트의 관련 기사

외부 자원 및 문서

  • vLLM GitHub 저장소 - 공식 vLLM 저장소로 소스 코드, 포괄적인 문서, 설치 가이드 및 활발한 커뮤니티 토론이 포함되어 있습니다. 최신 기능을 파악하고 문제를 해결하는 데 필수적인 자원입니다.

  • vLLM 문서 - vLLM의 기본 설정부터 고급 설정까지 모든 측면을 다루는 공식 문서입니다. API 참조, 성능 최적화 가이드 및 배포 최선의 실천 방법이 포함되어 있습니다.

  • PagedAttention 논문 - vLLM의 효율성을 가능하게 하는 PagedAttention 알고리즘을 소개한 학술 논문입니다. vLLM의 성능 우위에 대한 기술 혁신을 이해하는 데 필수적인 읽을거리입니다.

  • vLLM 블로그 - vLLM의 공식 블로그로, 릴리스 발표, 성능 벤치마크, 기술 심층 분석 및 프로덕션 배포 사례가 포함되어 있습니다.

  • HuggingFace 모델 허브 - vLLM과 호환되는 오픈소스 LLM의 포괄적인 저장소입니다. 모델 크기, 작업, 라이선스 및 성능 특성을 기준으로 모델을 검색하여 사용 사례에 적합한 모델을 찾을 수 있습니다.

  • Ray Serve 문서 - 확장 가능한, 분산된 vLLM 배포를 구축하기 위한 Ray Serve 프레임워크 문서입니다. Ray는 프로덕션 시스템에 사용할 수 있는 자동 확장, 다중 모델 서빙 및 자원 관리와 같은 고급 기능을 제공합니다.

  • NVIDIA TensorRT-LLM - NVIDIA의 TensorRT-LLM은 NVIDIA GPU에서 고도로 최적화된 추론을 수행합니다. vLLM과 다른 최적화 전략을 사용하는 대안으로, 추론 최적화 풍경을 이해하는 데 유용합니다.

  • OpenAI API 참조 - vLLM API와 호환되는 공식 OpenAI API 문서입니다. OpenAI와 자가 호스팅 vLLM 엔드포인트 간에 교차로 작동하는 애플리케이션을 구축할 때 참조하세요.