vLLM을 사용한 예시 모델 배포
GitLab v19.4Offering: GitLab Self-Managed
요약
GPT OSS 120B는 vLLM으로 배포하는 예시 모델이며, GPU 선택부터 프로덕션 모니터링까지 다룹니다. GPT OSS 120B는 NVIDIA H100에서 학습되었으며 H100 이상의 데이터 센터 GPU에서 가장 잘 동작합니다.
GPT OSS 120B는 vLLM으로 배포하는 예시 모델이며, GPU 선택부터 프로덕션 모니터링까지 다룹니다.
GPU 선택#
GPT OSS 120B는 NVIDIA H100에서 학습되었으며 H100 이상의 데이터 센터 GPU에서 가장 잘 동작합니다. 전문가 혼합(mixture-of-experts, MoE) 구조가 토큰마다 네트워크의 일부만 활성화하므로, 이 모델은 단일 H100 80 GB GPU에 들어갑니다.
병렬화 전략 결정#
GPU를 어떻게 연결하는지에 따라 다음 병렬화 전략이 정해집니다.
- GPU가 NVLink(수백 GB/s)로 연결되어 있다면 단일 노드에서 텐서 병렬화를 사용합니다. 텐서 병렬화는 각 레이어를 GPU 사이에 나누므로 높은 대역폭이 필요합니다.
- GPU의 대역폭이 낮고 PCIe(약 64 GB/s)로 동작한다면 파이프라인 병렬화를 사용합니다. 파이프라인 병렬화는 레이어를 GPU 사이에 순차적으로 나눕니다.
텐서 병렬화의 최대 한계에 도달했지만 모델을 더 분산해야 한다면 두 병렬화 전략을 함께 사용할 수 있습니다. 예를 들어 노드 안에서는 텐서 병렬화를, 노드 사이에서는 파이프라인 병렬화를 사용합니다.
VRAM 요구 사항 계획#
필요한 VRAM은 컨텍스트 길이와 예상 동시 처리 수에 따라 달라집니다.
vLLM은 다음 용도로 VRAM을 할당합니다.
| 카테고리 | 크기 | 비고 |
|---|---|---|
| 모델 가중치 | 약 61 GB | 고정 |
| 프레임워크 오버헤드 | 약 2 GB | 고정 |
| KV 캐시 | 나머지 | 동시 처리 수와 컨텍스트 길이에 따라 확장 |
KV 캐시는 각 요청에서 처리한 토큰의 사전 계산 벡터를 저장합니다. 각 토큰은 한 번만 계산되며, 변동이 발생하는 지점이 바로 이 캐시입니다.
예시: 단일 H100 80 GB#
--gpu-memory-utilization 0.95를 사용하면 76 GB의 VRAM을 쓸 수 있습니다.
76 GB usable
├── 61 GB model weights ← fixed
├── 2 GB framework overhead ← fixed
└── 13 GB KV cache ← fills as requests arrive
캐시된 토큰당 약 36 KB 이므로, 13 GB는 전체 어텐션 레이어에 걸쳐 약 370K 토큰의 컨텍스트를 담습니다. 에이전트형 요청 하나가 약 32K 토큰을 사용한다면 동시 요청 약 10 건 을 처리할 수 있습니다.
vLLM을 시작하면 로그에 정확한 수치가 표시됩니다.
Available KV cache memory: N GiB
GPU KV cache size: Y tokens
Maximum concurrency for Y tokens per request: Nx
설치#
환경에 맞는 방법을 선택합니다.
- 설치 스크립트: CUDA 나 GPU 드라이버가 설치되지 않은 새 Ubuntu 또는 Debian 머신입니다.
- vLLM만 설치: CUDA와 드라이버가 이미 있는 경우입니다(GCP의 NVIDIA Deep Learning VM, AWS Deep Learning AMI, 기존 GPU 머신).
- Docker: 호스트 수준 설정을 전부 건너뜁니다.
하드웨어가 다르다면 추가 구성은 GPT OSS - vLLM Recipes를 참고합니다.
옵션 1: 설치 스크립트(처음부터)#
스택을 업데이트할 때는 각 변수에 다음 버전을 사용합니다. 이 버전들은 GPT OSS 120B를 서빙하는 데 필요한 최소 버전입니다. vLLM은 성능 개선, 버그 수정, 하드웨어 지원 확대가 포함된 최신 릴리스를 사용하는 것이 좋습니다.
| 변수 | 버전 |
|---|---|
| CUDA toolkit | 12.9 |
| 최소 드라이버 | 575.x |
| Python | 3.12 |
| vLLM | 0.18.0 |
#!/bin/bash
# vLLM + CUDA installation for gpt-oss-120b
# Target: Ubuntu 22.04 / Debian 12, x86_64
CUDA_VERSION="12-9" # apt package suffix → cuda-toolkit-12-9
MIN_DRIVER_VERSION="575" # minimum driver for CUDA 12.9
PYTHON_VERSION="3.12"
VLLM_VERSION="0.18.0"
VENV_DIR="${HOME}/vllm-env"
set -e
# ===========================================================================
# PART 1 — system prerequisites
# ===========================================================================
echo "--- Part 1: System prerequisites ---"
sudo apt-get update && sudo apt-get upgrade -y
sudo apt-get install -y \
build-essential \
dkms \
linux-headers-$(uname -r) \
wget curl gnupg2 \
software-properties-common \
python${PYTHON_VERSION} \
python${PYTHON_VERSION}-venv \
python${PYTHON_VERSION}-dev \
python3-pip git
# Install uv — recommended by vLLM docs; gives extra index URLs higher
# priority than PyPI, which is required for the gpt-oss fork to resolve correctly.
curl --location --silent --show-error --fail "https://astral.sh/uv/install.sh" | sh
source "${HOME}/.local/bin/env"
# ===========================================================================
# PART 2 — NVIDIA drivers and CUDA toolkit
# Reboot required after this section before continuing to Part 3.
# ===========================================================================
echo "--- Part 2: NVIDIA drivers and CUDA ${CUDA_VERSION//-/.} ---"
# Add NVIDIA's package repository.
# For Debian 12, replace ubuntu2204 with debian12 in the URL.
# Current keyring URL: https://developer.nvidia.com/cuda-downloads
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
# cuda-drivers (no version suffix) is a meta-package — apt resolves
# the latest driver compatible with the pinned toolkit automatically.
sudo apt-get install -y \
cuda-drivers \
cuda-toolkit-${CUDA_VERSION} \
nvidia-gds-${CUDA_VERSION}
echo 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
# Keep GPU initialized between jobs (reduces cold-start latency)
sudo systemctl enable nvidia-persistenced
echo "Rebooting to load NVIDIA kernel modules..."
echo "After reboot, run: bash install.sh --post-reboot"
if [[ "${1:-}" != "--post-reboot" ]]; then
sudo reboot
fi
# ===========================================================================
# PART 3 — Python environment and vLLM
# Start here after reboot, or if using a cloud managed image.
# ===========================================================================
echo "--- Part 3: Verify drivers ---"
nvidia-smi # confirm driver >= ${MIN_DRIVER_VERSION} and GPUs visible
nvcc --version # confirm CUDA ${CUDA_VERSION//-/.}
echo "--- Part 3: Python environment ---"
uv venv "$VENV_DIR" --python ${PYTHON_VERSION} --seed
source "$VENV_DIR/bin/activate"
python --version # should show Python 3.12.x
echo "--- Part 3: PyTorch ---"
# --torch-backend=auto inspects your installed CUDA driver at runtime and
# selects the matching PyTorch index automatically. This replaces hardcoded
# --index-url flags and stays correct across CUDA version updates.
uv pip install torch torchvision torchaudio --torch-backend=auto
echo "--- Part 3: vLLM ---"
uv pip install "vllm==${VLLM_VERSION}" --torch-backend=auto
echo ""
echo "Installation complete."
echo "Activate environment: source ${VENV_DIR}/bin/activate"
echo "Verify vLLM version: python -c \"import vllm; print(vllm.__version__)\""
옵션 2: vLLM만 설치#
CUDA와 드라이버가 이미 설치되어 있다면(클라우드 관리형 이미지, 기존 GPU 머신) 다음 명령으로 vLLM을 설치합니다.
uv venv
source .venv/bin/activate
uv pip install vllm --torch-backend=auto
옵션 3: Docker#
다음 명령으로 GPT OSS 120B Docker 이미지를 설치합니다. vllm/vllm-openai:v0.18.0 이미지에는 CUDA, 드라이버, vLLM 이 포함되어 있습니다.
docker run \
--gpus all \
-p 8000:8000 \
--ipc=host \
vllm/vllm-openai:v0.18.0 \
--model openai/gpt-oss-120b
vLLM 구성#
vLLM 구성 값은 트래픽 패턴에 따라 달라집니다. 아래 권장 설정으로 시작한 다음 이 조정 항목들을 맞춰 갑니다.
| 플래그 | 기본값 | 설명 |
|---|---|---|
--gpu-memory-utilization |
0.90 |
vLLM 이 확보하는 GPU 메모리 비율입니다. KV 캐시를 늘리고 처리량을 높이려면 0.95로 올립니다. 부하 상황에서 OOM 오류가 발생하면 낮춥니다. |
--max-model-len |
모델 최대값(GPT OSS 120B의 경우 128K) | 요청당 최대 컨텍스트 길이를 제한합니다. 이 값을 낮추면 동시 처리 용량이 늘어납니다. |
--max-num-seqs |
256 |
단일 배치의 최대 요청 수입니다. 값이 클수록 GPU 활용도와 처리량이 좋아지지만 요청당 지연 시간이 늘어납니다. 실제 동시 처리 수는 사용 가능한 KV 캐시로 여전히 제한됩니다. |
--max-num-batched-tokens |
None | 반복당 처리하는 전체 토큰 수입니다. --max-num-seqs와 함께 동작하며, vLLM은 둘 중 먼저 도달하는 한계까지 배치를 구성합니다. |
--tensor-parallel-size |
None | 레이어를 N 개의 GPU에 수평으로 나눕니다. 높은 대역폭이 필요하며 NVLink로 연결된 단일 노드 안에서 사용합니다. |
--pipeline-parallel-size |
None | 레이어를 N 개의 GPU에 순차적으로 나눕니다. 낮은 대역폭도 견디므로 PCIe로 연결된 노드 사이에 적합합니다. |
권장 설정#
다음 표는 하드웨어별 권장 설정입니다. 사용하는 하드웨어와 예상 트래픽 패턴에 맞는 행을 고른 다음, 해당 구성을 사용합니다.
근사 동시 요청 수 칼럼은 표에 적힌 컨텍스트 길이에서 KV 캐시로 제한되는 대략적인 동시 처리 수이며, --max-num-seqs 값이 아닙니다.
| 하드웨어 | 최대 컨텍스트 | 근사 동시 요청 수 | 최적 용도 |
|---|---|---|---|
| Single H100 80 GB | 32K | 10 | 개발·테스트, 저트래픽 서빙 |
| 2× H100 80 GB | 64K | 34 | 중간 규모 프로덕션 부하 |
| 4× H100 80 GB | 128K | 51 | 전체 컨텍스트 창, 높은 처리량 |
| 2× A100 40 GB | 32K | 3 | 최소 구성의 A100 설정 |
| 4× A100 40 GB | 32K | 69 | 더 높은 A100 처리량 |
| 2× L40S / RTX A6000 Ada 48 GB | 32K | 19 | 비용 효율적인 Ada Lovelace 옵션 |
Single H100 80 GB#
이 설정에서 --gpu-memory-utilization을 기본값 0.90보다 높은 0.95로 올리는 것은 단일 H100의 알려진 CUDA OOM 문제를 우회하기 위해서입니다.
vllm serve openai/gpt-oss-120b \
--gpu-memory-utilization 0.95 \
--max-model-len 32768 \
--max-num-seqs 16 \
--max-num-batched-tokens 4096
2× H100 80 GB#
이 설정에서는 합쳐진 KV 캐시 풀이 더 크므로 컨텍스트 창을 넓히고 동시 요청을 더 많이 처리할 수 있습니다.
vllm serve openai/gpt-oss-120b \
--tensor-parallel-size 2 \
--max-model-len 65536 \
--max-num-seqs 32 \
--max-num-batched-tokens 8192
4× H100 80 GB#
이 설정은 128K 컨텍스트 창 전체를 제공합니다.
vllm serve openai/gpt-oss-120b \
--tensor-parallel-size 4 \
--gpu-memory-utilization 0.95 \
--max-model-len 131072 \
--max-num-seqs 64 \
--max-num-batched-tokens 16384
2× A100 40 GB#
이 설정에서 단일 A100 40 GB는 61 GB 모델 가중치를 담지 못합니다. GPU 두 개가 최소 구성입니다.
vllm serve openai/gpt-oss-120b \
--tensor-parallel-size 2 \
--max-model-len 32768 \
--max-num-seqs 24 \
--max-num-batched-tokens 4096
4× A100 40 GB#
vllm serve openai/gpt-oss-120b \
--tensor-parallel-size 4 \
--max-model-len 32768 \
--max-num-seqs 128 \
--max-num-batched-tokens 16384
2× L40S 48GB 또는 RTX A6000 Ada 48 GB#
두 설정 모두 48 GB의 Ada Lovelace를 사용합니다.
vllm serve openai/gpt-oss-120b \
--tensor-parallel-size 2 \
--max-model-len 32768 \
--max-num-seqs 16 \
--max-num-batched-tokens 4096
NVIDIA Blackwell 및 Hopper 추가 최적화는 GPT OSS - vLLM Recipes: Recipe for NVIDIA Blackwell & Hopper Hardware를 참고합니다.
서버 확인#
vLLM을 시작한 다음에는 아래 요청으로 정상적으로 서빙되는지 확인합니다.
curl "http://localhost:8000/v1/chat/completions" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-oss-120b",
"messages": [{"role": "user", "content": "Hello"}],
"max_tokens": 64
}'
모델의 완성 결과가 담긴 JSON 응답이 표시됩니다. 서버가 아직 준비되지 않았다면 연결 거부 오류를 받습니다. vLLM은 처음 시작할 때 모델 가중치를 불러올 시간이 필요하며, 저장소 속도에 따라 몇 분이 걸릴 수 있습니다.
모니터링#
vLLM은 Prometheus 호환 /metrics 엔드포인트를 제공합니다. 전체 목록은 Production Metrics - vLLM을 참고합니다.
vLLM을 모니터링할 때는 사용자 대면 지연 시간과 용량 압박 지표를 확인합니다.
| 메트릭 | 설명 |
|---|---|
| 사용자 대면 지연 시간 | |
time_to_first_token |
사용자가 응답성으로 느끼는 시간입니다. |
time_per_output_token_seconds |
스트리밍이 얼마나 부드럽게 느껴지는지를 나타냅니다. |
| 용량 압박 | |
kv_cache_usage_perc |
사용 중인 KV 풀의 비율입니다. 주요 메모리 압박 신호입니다. 0.85를 넘는 값이 지속되면 용량에 가까워지고 있다는 뜻입니다. |
num_requests_waiting |
KV 캐시가 가득 차서 대기 중인 요청 수입니다. 대기열이 계속 늘어나면 용량을 초과한 것입니다. GPU를 늘리거나, --max-model-len을 줄이거나, --max-num-seqs를 낮춥니다. |
num_requests_running |
실제 동시 처리 수입니다. |
문제 해결#
클라이언트 타임아웃 또는 num_requests_waiting의 지속 증가#
들어오는 요청이 KV 캐시 용량을 초과한 경우입니다. vLLM은 캐시 공간이 확보될 때까지 새 요청을 대기열에 넣고, 대기열은 줄어들지 않습니다.
이 문제를 해결하는 방법은 다음과 같습니다.
kv_cache_usage_perc를 확인합니다. 0.85를 넘는 값이 지속되면 메모리에 병목이 있다는 뜻입니다.--max-model-len을 줄여 요청당 KV 할당량을 낮춥니다. 그러면 동시 요청을 더 받을 여유가 생깁니다.--max-num-seqs를 줄여 동시에 캐시를 두고 경쟁하는 요청 수를 제한합니다.- 단일 노드 조정을 모두 시도했다면 수평으로 확장합니다. GPU 나 노드를 추가하고 여러 vLLM 인스턴스에 부하를 분산합니다.
CUDA OOM 오류로 인한 서버 충돌#
부하가 높을 때 서버의 GPU 메모리가 부족한 경우입니다.
이 문제를 해결하려면 다음 순서로 조정합니다.
--max-num-seqs를 줄여 동시 배치 크기를 제한합니다.--max-model-len을 줄여 요청당 KV 할당량을 낮춥니다.- 시작 시점에 OOM 이 발생하면
--gpu-memory-utilization을 낮춥니다.
예상보다 느린 토큰 생성#
time_per_output_token_seconds가 높고 전체 토큰/초가 낮은 경우입니다. GPU가 반복마다 처리하는 작업량이 부족한 상태입니다.
이 문제를 해결하는 방법은 다음과 같습니다.
--max-num-batched-tokens를 늘려 vLLM 이 반복마다 더 많은 토큰을 처리하도록 합니다.--max-num-seqs를 늘려 더 많은 요청이 함께 배치되도록 합니다. 그러면 GPU 활용도가 좋아집니다.