vLLM 서버를 띄우다가 CUDA out of memory가 발생하면 무조건 더 작은 모델부터 찾기 쉽습니다. 하지만 실제 원인은 모델 가중치, KV Cache, CUDA Graph, 동시 요청이 서로 다릅니다. 원인을 구분하지 않고 옵션을 바꾸면 서버는 실행되더라도 처리량이 급격히 떨어지거나, 트래픽이 들어오는 순간 다시 종료될 수 있습니다.
이 글에서는 오류가 발생한 시점부터 확인한 뒤 max_model_len, max_num_seqs, gpu_memory_utilization, enforce_eager, 양자화, 텐서 병렬을 어떤 순서로 적용해야 하는지 정리합니다.
결론부터 말하면
처음에는 컨텍스트 길이와 동시 시퀀스를 줄여 안정적인 기준점을 만들고, 그다음 CUDA Graph와 KV Cache 예산을 조정하세요. 그래도 모델 가중치가 들어가지 않을 때 양자화·CPU 오프로딩·텐서 병렬을 검토하는 순서가 안전합니다.
1. vLLM OOM은 발생 시점부터 구분해야 한다
vLLM의 GPU 메모리는 대략 모델 가중치, KV Cache, 실행 중 활성값과 작업 공간, CUDA Graph가 나눠 사용합니다. 따라서 같은 OOM 문구라도 해결 방법은 달라집니다.
발생 시점·메시지가능성 높은 원인가장 먼저 할 일
| 모델 가중치를 읽는 중 OOM | 가중치 자체가 VRAM보다 큼 | 양자화 모델 또는 텐서 병렬 검토 |
| No available memory for the cache blocks | KV Cache에 할당할 공간 부족 | 다른 프로세스 종료 후 max_model_len 축소 |
| 모델 최대 길이가 KV Cache 용량보다 크다는 오류 | 컨텍스트 길이에 비해 KV Cache 예산 부족 | max_model_len 축소 또는 여유 VRAM 범위에서 메모리 예산 확대 |
| CUDA Graph 캡처 중 OOM | 그래프 캡처용 추가 메모리 부족 | max_num_seqs 축소, 임시로 enforce_eager 적용 |
| 서버는 켜지지만 동시 요청에서 OOM | 배치·동시성·긴 프롬프트의 피크 메모리 | max_num_seqs와 입력 길이 제한 |
아직 모델 선택과 기본 서버 구성이 끝나지 않았다면 먼저 vLLM·GGUF·FastAPI로 사내 AI 서버 만들기와 로컬 LLM 서버 구축 가이드를 참고하세요. GPU 구매 전이라면 로컬 LLM 서버 비용과 GPU 사양 비교도 함께 보면 시행착오를 줄일 수 있습니다.
2. 설정을 바꾸기 전 3분 진단
옵션을 바꾸기 전에 GPU를 다른 프로세스가 사용 중인지 확인합니다. 이미 점유된 VRAM을 무시한 채 gpu_memory_utilization만 올리면 오히려 일반적인 CUDA OOM이 발생할 수 있습니다.
# GPU 메모리와 실행 중인 프로세스 확인
nvidia-smi
# Linux에서 1초마다 확인
watch -n 1 nvidia-smi
# 현재 vLLM 버전과 지원 옵션 확인
python -c "import vllm; print(vllm.__version__)"
vllm serve --help
다음 네 가지를 기록해 두면 원인 판단이 빨라집니다.
- 모델명과 파라미터 규모, 원본 또는 양자화 형식
- GPU 모델·개수·총 VRAM, 시작 전 여유 VRAM
- max_model_len, max_num_seqs, 메모리 관련 실행 옵션
- 서버 시작 중인지, 첫 요청인지, 동시 요청 중인지
vLLM은 변화가 빠른 프로젝트입니다. 버전별 기본값이나 지원 옵션이 다를 수 있으므로 인터넷의 명령어를 그대로 복사하기보다 현재 설치된 버전의 vllm serve --help를 기준으로 확인하는 것이 좋습니다.
3. 가장 안전한 기준 설정부터 시작한다
먼저 컨텍스트와 동시성을 보수적으로 제한하고 CUDA Graph를 끈 상태에서 서버가 기동되는지 확인합니다. 아래 명령어의 모델명은 실제 사용하는 Hugging Face 모델 ID로 바꾸세요.
MODEL="사용할-모델-ID"
vllm serve "$MODEL" \
--max-model-len 4096 \
--max-num-seqs 8 \
--gpu-memory-utilization 0.85 \
--enforce-eager
이 설정이 모든 GPU의 정답이라는 뜻은 아닙니다. 서버가 안정적으로 기동되는 기준점을 만드는 예시입니다. 기동과 짧은 부하 테스트가 성공하면 다음 순서로 성능을 회복합니다.
- enforce_eager를 제거하고 다시 테스트합니다.
- max_num_seqs를 8 → 16 → 32처럼 한 단계씩 올립니다.
- 업무에 필요한 범위에서 max_model_len을 늘립니다.
- 각 단계마다 최대 길이 요청과 동시 요청을 함께 테스트합니다.
4. 1순위: max_model_len을 실제 사용 길이에 맞춘다
max_model_len은 모델이 지원하는 최대 길이를 그대로 제공해야 한다는 의미가 아닙니다. 챗봇이 실제로 4K 토큰만 사용한다면 32K 또는 128K로 열어 두는 것은 불필요한 KV Cache 부담이 될 수 있습니다.
vllm serve "$MODEL" \
--max-model-len 4096
vLLM 공식 메모리 절약 문서도 컨텍스트 길이와 최대 배치 크기를 줄이는 방법을 권장합니다. 다만 숫자를 지나치게 낮추면 긴 문서나 RAG 컨텍스트가 잘리므로, 애플리케이션 로그에서 입력 토큰의 p95와 최대값을 먼저 확인하는 편이 좋습니다.
실무 팁: RAG에서 검색 문서를 무조건 많이 넣기보다 검색 결과 수, 청크 길이, 중복 문서를 먼저 줄이세요. VRAM뿐 아니라 첫 토큰 응답 시간과 API 비용도 함께 개선됩니다.
RAG 운영비와 자원 사용을 같이 줄이고 싶다면 RAG 비용 최적화 — GPU·CPU 자원 절감 방법도 참고하세요.
5. 2순위: max_num_seqs로 동시 처리 피크를 제한한다
max_num_seqs는 한 번의 스케줄러 반복에서 처리하는 최대 시퀀스 수를 제한합니다. 값을 높이면 처리량을 키울 여지가 생기지만, 긴 요청이 동시에 몰릴 때 메모리 피크도 커질 수 있습니다.
vllm serve "$MODEL" \
--max-model-len 4096 \
--max-num-seqs 8
서버 시작은 성공하지만 부하 테스트에서만 OOM이 난다면 이 값을 먼저 낮추세요. 요청 큐, 애플리케이션의 동시성 제한, 타임아웃도 함께 설정해야 갑작스러운 트래픽이 GPU까지 그대로 밀려들지 않습니다.
6. gpu_memory_utilization은 오류 종류에 따라 방향이 다르다
gpu_memory_utilization은 현재 vLLM 인스턴스가 모델 실행에 사용할 GPU 메모리 비율입니다. 값이 높을수록 KV Cache에 활용할 공간을 늘릴 수 있지만, 같은 GPU의 다른 프로세스나 런타임 여유 공간과 충돌할 수 있습니다.
상황조정 방향주의점
| KV Cache 블록이 없다는 시작 오류 | GPU가 실제로 비어 있다면 조금 올려 테스트 | 먼저 다른 GPU 프로세스를 종료 |
| CUDA Graph 또는 실행 중 일반 CUDA OOM | 컨텍스트·동시성을 줄이고 여유 공간 확보 | 비율만 낮추면 KV Cache 부족이 심해질 수 있음 |
| 한 GPU에서 vLLM 인스턴스 여러 개 운영 | 인스턴스별 비율 합계를 보수적으로 배분 | 드라이버와 기타 프로세스 여유분 필요 |
# 예: GPU가 실제로 비어 있고 KV Cache 공간만 부족할 때 단계적으로 확인
vllm serve "$MODEL" \
--max-model-len 4096 \
--max-num-seqs 8 \
--gpu-memory-utilization 0.90
0.99로 무조건 올리는 설정은 권장하지 않습니다. 모델과 GPU가 같아도 드라이버, vLLM 버전, 다른 프로세스, 요청 패턴에 따라 필요한 여유분이 달라집니다.
7. CUDA Graph 캡처에서 터지면 enforce_eager를 진단용으로 쓴다
vLLM은 성능을 높이기 위해 CUDA Graph를 사용하며, 그래프 캡처에도 추가 GPU 메모리가 필요합니다. 공식 문서에서는 캡처 크기를 줄이거나 enforce_eager=True로 그래프 캡처를 완전히 끌 수 있다고 설명합니다.
vllm serve "$MODEL" \
--max-model-len 4096 \
--max-num-seqs 8 \
--enforce-eager
enforce_eager를 적용했을 때만 정상 기동된다면 CUDA Graph 메모리가 원인일 가능성이 높습니다. 운영에서는 처리량과 지연 시간을 비교한 뒤 유지 여부를 정하세요. 가능하다면 그래프를 전부 끄기보다 사용하는 vLLM 버전이 지원하는 캡처 크기 설정을 조정하는 방법도 검토할 수 있습니다.
8. 가중치가 들어가지 않으면 양자화·오프로딩·텐서 병렬
방법 A. 양자화 모델 사용
양자화는 일부 정밀도를 낮추는 대신 모델 가중치의 메모리 사용량을 줄입니다. AWQ, GPTQ, FP8, bitsandbytes, GGUF 등 여러 형식이 있지만 GPU 세대와 백엔드에 따라 지원 범위가 다릅니다. 모델 카드와 vLLM의 최신 호환성 표를 확인하고 선택하세요.
# 예시: 체크포인트가 해당 형식으로 준비된 경우
vllm serve "양자화된-모델-ID" \
--quantization awq \
--max-model-len 4096
양자화 모델은 단순히 용량만 확인하지 말고 응답 품질, 첫 토큰 지연, 처리량을 원본 모델과 함께 측정해야 합니다.
방법 B. CPU 오프로딩
cpu_offload_gb는 GPU에 모두 들어가지 않는 모델 가중치 일부를 CPU 메모리로 옮겨 사용할 수 있게 합니다. 단, 모델의 순전파마다 CPU와 GPU 사이의 데이터 전송이 발생하므로 빠른 인터커넥트와 충분한 시스템 RAM이 필요하고, 응답 성능이 낮아질 수 있습니다.
vllm serve "$MODEL" \
--cpu-offload-gb 8 \
--max-model-len 4096
방법 C. 여러 GPU에 텐서 병렬 적용
GPU가 두 장 이상이라면 tensor_parallel_size로 모델을 분할할 수 있습니다. vLLM 초기화 전에 임의로 CUDA 장치를 설정하기보다 공식 문서가 안내하는 CUDA_VISIBLE_DEVICES로 사용할 GPU를 지정하는 편이 안전합니다.
CUDA_VISIBLE_DEVICES=0,1 vllm serve "$MODEL" \
--tensor-parallel-size 2 \
--max-model-len 8192 \
--max-num-seqs 16 \
--gpu-memory-utilization 0.90
텐서 병렬은 모델을 여러 GPU로 나누지만 통신 비용이 생깁니다. GPU 간 연결 방식과 실제 처리량을 측정한 뒤 단일 GPU 양자화 구성과 비교하는 것이 좋습니다.
9. 자주 하는 잘못된 해결 방법
- gpu_memory_utilization을 무조건 0.99로 올린다: KV Cache는 늘 수 있지만 다른 프로세스와 런타임 여유 공간이 사라질 수 있습니다.
- 모델이 지원하는 최대 컨텍스트를 그대로 연다: 실제 서비스가 사용하지 않는 길이라면 메모리만 낭비할 수 있습니다.
- swap_space만 늘리면 모든 OOM이 해결된다고 생각한다: 모델 가중치가 GPU에 들어가지 않는 문제와 KV Cache·CUDA Graph 문제는 별도로 진단해야 합니다.
- 단일 짧은 요청만 성공하면 운영 가능하다고 판단한다: 최대 입력 길이와 예상 동시성을 조합한 부하 테스트가 필요합니다.
- 양자화 형식의 하드웨어 호환성을 확인하지 않는다: GPU 세대에 따라 지원 여부와 성능이 달라질 수 있습니다.
10. 운영 투입 전 체크리스트
- 서버 시작 전후의 VRAM 사용량을 기록했는가?
- 짧은 요청, 최대 길이 요청, 동시 요청을 각각 테스트했는가?
- 입력 토큰 길이의 p50·p95·최대값을 확인했는가?
- 처리량뿐 아니라 첫 토큰 지연과 p95 응답 시간을 비교했는가?
- OOM 발생 시 요청을 제한하거나 재시작할 운영 정책이 있는가?
- 모델·vLLM·CUDA·드라이버 버전을 변경 이력에 남겼는가?
vLLM과 Ollama 중 어떤 서빙 도구가 맞는지 아직 결정하지 않았다면 vLLM vs Ollama 비교에서 운영 목적별 차이를 먼저 확인해 보세요.
FAQ
Q1. gpu_memory_utilization을 낮추면 OOM이 해결되나요?
오류 종류에 따라 다릅니다. 다른 프로세스나 CUDA Graph와 충돌하는 일반 CUDA OOM에는 여유 공간 확보가 도움이 될 수 있습니다. 반대로 KV Cache 블록을 만들 공간이 없다는 오류에서는 값을 낮추면 상황이 더 나빠질 수 있습니다. 먼저 다른 프로세스, 컨텍스트 길이, 동시성을 확인하세요.
Q2. max_model_len은 어느 정도가 적당한가요?
모델의 최대 지원 길이가 아니라 실제 서비스 입력과 출력의 합을 기준으로 정합니다. 운영 로그의 p95를 감당하면서 비정상적으로 긴 요청은 애플리케이션에서 제한하는 방식이 효율적입니다.
Q3. enforce_eager를 계속 사용해도 되나요?
기능상 사용할 수 있지만 CUDA Graph 최적화를 끄므로 성능 차이가 생길 수 있습니다. OOM 원인을 확인하는 진단용 기준으로 먼저 사용하고, 이후 실제 트래픽과 유사한 부하에서 지연 시간과 처리량을 비교해 유지 여부를 결정하세요.
Q4. 24GB GPU에서 어떤 모델까지 실행할 수 있나요?
파라미터 수만으로 단정할 수 없습니다. 가중치 정밀도, 양자화 방식, 컨텍스트 길이, KV Cache dtype, 동시 요청 수가 모두 영향을 줍니다. 같은 모델도 설정에 따라 필요한 VRAM이 크게 달라지므로 작은 컨텍스트와 동시성에서 시작해 측정해야 합니다.
마무리: 한 번에 하나씩 바꿔야 원인을 찾을 수 있다
vLLM CUDA OOM 해결의 핵심은 옵션을 여러 개 동시에 바꾸는 것이 아니라, 발생 시점 분류 → 기준 설정 기동 → 컨텍스트 길이 → 동시 시퀀스 → CUDA Graph → 메모리 예산 → 양자화·오프로딩·텐서 병렬 순서로 한 단계씩 검증하는 것입니다.
운영에 필요한 최대 입력 길이와 동시성을 먼저 정의하면 불필요하게 큰 GPU를 구매하거나, 반대로 부하가 몰릴 때 서버가 멈추는 문제를 줄일 수 있습니다. 설정을 변경할 때마다 버전·명령어·부하 조건·VRAM·지연 시간·처리량을 표로 남겨 두세요. 다음 업그레이드 때 가장 유용한 운영 데이터가 됩니다.
공식 참고 문서
이 글은 2026년 7월 18일 기준 공식 문서를 바탕으로 작성했습니다. vLLM은 버전별 옵션과 기본값이 달라질 수 있으므로 실제 운영 환경에서는 설치된 버전의 도움말과 릴리스 문서를 함께 확인하세요.
'AI·LLM 엔지니어링' 카테고리의 다른 글
| LLM 양자화 완전정리 — FP16·INT8·INT4, GGUF·AWQ·GPTQ 선택법 (0) | 2026.07.26 |
|---|---|
| vLLM 속도 튜닝 가이드 (2026) — TTFT·ITL·처리량을 개선하는 실전 순서 (0) | 2026.07.24 |
| vLLM vs Ollama 완벽 비교 - 로컬 LLM 서빙, 무엇을 선택해야 할까? (2026) (0) | 2026.07.16 |
| Claude Code, Cursor, Codex 실제 개발 생산성 비교: 어떤 AI 코딩 도구가 맞을까? (0) | 2026.07.15 |
| OpenAI API 비용 줄이는 실무 방법 7가지: 모델 선택·캐싱·Batch까지 (0) | 2026.07.15 |