vLLM·TGI·Ollama 로컬/온프렘 서빙 배포 완전 정리: “내 서비스엔 뭐가 맞나?”를 성능/운영 관점에서 결정하기
LLM 서빙을 “돌아가게” 만드는 건 쉽습니다. 문제는 동시성(concurrency)이 올라갈 때 GPU가 놀지 않게 유지하면서, KV cache 메모리 폭발을 제어하고, 배포/업그레이드/관측(Observability)까지 포함한 운영 난이도를 감당하는 겁니다.
들어가며
LLM 서빙을 “돌아가게” 만드는 건 쉽습니다. 문제는 동시성(concurrency)이 올라갈 때 GPU가 놀지 않게 유지하면서, KV cache 메모리 폭발을 제어하고, 배포/업그레이드/관측(Observability)까지 포함한 운영 난이도를 감당하는 겁니다. 2026년 8월 기준 로컬/온프렘에서 많이 쓰는 선택지는 대략 3갈래입니다: vLLM(고성능 GPU 서빙), Hugging Face TGI(모델 허브/생태계 친화), Ollama(로컬 UX 최강).1
언제 쓰면 좋은가(요약):
- vLLM: “한 대의 GPU/몇 대의 GPU로 최대 처리량을 뽑아야 하는” 프로덕션 API(동시 요청 많음).2
- TGI: Hugging Face 모델/툴체인 중심 + 샤딩/런처 옵션이 명확한 운영을 선호(조직 표준이 HF일 때 특히).3
- Ollama: 개발/내부 도구/개인 PC/간단한 단일 노드 배포에서 “설치-실행-모델관리” 시간을 최소화. OpenAI 호환 API도 제공.4
언제 쓰면 안 좋은가:
- vLLM: 단일 사용자/낮은 QPS에서 “첫 토큰까지의 체감(TTFT)”만 중요하면 오히려 오버헤드가 아까울 수 있음(특히 메모리 타이트한 GPU).
- Ollama: 동시성이 커지면(혹은 모델을 크게/여럿) “서빙 엔진”로서 한계가 빨리 옴—편의성의 대가를 처리량/튜닝 여지에서 치르는 편.5
- TGI: 워크로드에 따라 vLLM 대비 동시성 처리량에서 손해를 볼 수 있음(반대로 특정 상호작용/낮은 동시성에서는 tail latency가 더 유리하다는 보고도 있음).6
🔧 핵심 개념
1) KV cache가 “서빙 비용”의 본체다
대부분의 트랜스포머 디코딩 서빙은 가중치(weight) 메모리 + KV cache 메모리 + 활성화/버퍼의 합으로 GPU 메모리가 결정됩니다. 특히 동시 요청이 늘면 KV cache가 선형으로 커지기 쉬워서, 메모리 관리 전략이 곧 처리량/비용입니다.
2) vLLM: PagedAttention + continuous batching의 조합
vLLM의 핵심은 PagedAttention: 요청별 KV cache를 고정 길이 연속 메모리로 잡지 않고, OS의 페이징처럼 블록 단위로 할당/회수해 “메모리 단편화/낭비”를 줄입니다. 그 위에 continuous batching(연속 배칭) 으로 요청을 계속 합쳐 GPU를 높은 점유율로 유지합니다.2
이 설계가 “동시성 높은 API”에서 강한 이유는, 요청들이 서로 다른 길이로 생성해도 KV cache를 효율적으로 재사용/관리하며 배칭을 깨지 않기 때문입니다.
또 하나 실무 포인트: vLLM의 vllm serve는 OpenAI-compatible API 서버를 제공하지만, --api-key가 보호하는 경로가 제한적이어서 “리버스 프록시/네트워크 레벨 보안”이 필수입니다.1
3) TGI: 라우터 + 모델 서버(샤딩) 구조가 명확
TGI는 요청을 받는 레이어(라우터) 와 모델 실행 서버(파이썬, gRPC 기반) 가 분리된 구조로 문서화되어 있고, 모델 서버에서 tensor parallel sharding을 통해 멀티 GPU로 확장합니다. 또한 paged attention, flash attention, speculation 등 최적화 옵션들을 “서빙 제품” 관점에서 제공하려는 색이 강합니다.7
TGI에서 실무적으로 가장 자주 만지는 건 배칭/프리필 상한 같은 런처 파라미터(예: MAX_BATCH_PREFILL_TOKENS)입니다. 이 값은 긴 프롬프트/다중 요청에서 VRAM과 TTFT를 좌우합니다.7
4) Ollama: “배포/모델 UX 레이어”로 이해하는 게 편하다
Ollama는 로컬에서 모델을 다운로드/관리하고 실행하는 UX가 강점이고, Docker 배포도 간단합니다.4
또한 OpenAI API 일부 호환 레이어를 제공해 기존 앱을 빠르게 붙일 수 있습니다.8
다만 동시성/대규모 처리량을 극한으로 뽑는 “서빙 엔진” 관점에서는 vLLM/TGI 대비 튜닝 여지가 제한될 수 있어, 내부 도구/개발 환경 또는 “단일 노드로 가볍게”가 주 포지션이 됩니다.
💻 실전 코드
아래는 같은 애플리케이션 코드를 거의 안 바꾸고 vLLM/TGI/Ollama를 스위칭할 수 있게, “OpenAI-compatible endpoint”를 전제로 한 현실적인 구성을 보여줍니다.
시나리오:
- 단일 노드(온프렘)에서 GPU 1~2장으로 Instruct 모델 서빙
- 외부에는 Nginx로 TLS/인증/레이트리밋을 걸고
- 내부 앱(예: FastAPI/Batch worker)은 OpenAI SDK로 호출
1) vLLM: Docker로 OpenAI-compatible API 서빙
1
2
3
4
5
6
7
8
9
10
11
12
13
# (1) vLLM 서버 실행 (단일 노드)
# 중요: PyTorch 공유메모리/TP에서 shm 이슈가 나서 --shm-size 또는 ipc=host가 필요할 수 있음.
# vLLM docker 배포 문서 참고.[^9]
docker run --rm --gpus all \
--shm-size=8g \
-p 8000:8000 \
-e VLLM_API_KEY="local-dev-token" \
vllm/vllm-openai:latest \
vllm serve meta-llama/Llama-3.2-3B-Instruct \
--host 0.0.0.0 \
--port 8000 \
--gpu-memory-utilization 0.92
테스트 호출(스트리밍):
1
2
3
4
5
6
7
8
9
10
11
curl http://localhost:8000/v1/chat/completions \
-H "Authorization: Bearer local-dev-token" \
-H "Content-Type: application/json" \
-d '{
"model":"meta-llama/Llama-3.2-3B-Instruct",
"stream": true,
"messages":[
{"role":"system","content":"You are a senior backend engineer."},
{"role":"user","content":"우리 서비스에서 Redis 캐시 미스율이 급증했을 때 점검 순서를 8단계로 써줘."}
]
}'
운영 포인트:
--gpu-memory-utilization은 “OOM vs 처리량”의 가장 큰 레버입니다. 너무 높이면 스파이크에서 바로 죽고, 너무 낮으면 처리량이 안 나옵니다.9--api-key는 vLLM 서버를 “완전히” 보호하는 수단이 아니니, 반드시 프록시/방화벽으로 감싸는 전제로 보세요.10
2) TGI: 공식 이미지 기반 실행 + 샤딩(멀티 GPU) 기본 틀
1
2
3
4
5
6
7
8
9
# (2) TGI 실행 (예: GPU 2장으로 tensor parallel sharding)
# 실제 옵션은 모델/환경에 따라 달라지며, 런처 인자/아키텍처 문서를 같이 보는 것이 안전합니다.[^3]
docker run --rm --gpus all \
-p 8080:80 \
-e MAX_BATCH_PREFILL_TOKENS=4096 \
ghcr.io/huggingface/text-generation-inference:latest \
--model-id meta-llama/Llama-3.2-3B-Instruct \
--num-shard 2
체크해야 하는 것:
- 긴 프롬프트가 많은 서비스(예: RAG)면
MAX_BATCH_PREFILL_TOKENS가 VRAM/TTFT에 직격입니다.7 - TGI는 내부적으로 컴포넌트 분리(라우터↔모델서버) 구조라, 병목이 “토크나이저/라우터/샤딩 통신” 중 어디인지 관측 포인트를 나누기 좋습니다.7
3) Ollama: Docker + OpenAI compatibility로 앱 붙이기
1
2
3
4
5
6
# (3) Ollama 서버 (NVIDIA GPU + 모델 영속 볼륨)
docker run -d --gpus=all \
-v ollama:/root/.ollama \
-p 11434:11434 \
--name ollama \
ollama/ollama
Ollama는 OpenAI 호환 API를 제공하므로, “기존 OpenAI 클라이언트 코드”를 재사용하는 전략이 가능합니다.8
추가로 Compose에서 GPU를 붙이는 방식은 Docker 문서의 GPU 지원 가이드를 그대로 따르면 됩니다.11
⚡ 실전 팁 & 함정
Best Practice (바로 효과 나는 것 3가지)
1) 워크로드를 “동시성 vs 단일 응답”으로 분류하고 엔진을 고르기
- 동시 요청이 많고 비용/처리량이 핵심이면 vLLM이 유리한 경향(특히 PagedAttention 기반 메모리 효율).2
- 반대로 “챗봇 1~2명” 수준이면 Ollama/경량 엔진이 체감상 더 만족스러울 수 있습니다(오버헤드/메모리 여유).5
2) 프론트(인증/TLS/레이트리밋)는 Nginx/Envoy로 고정
vLLM의 --api-key는 범위가 제한되고 “서버를 완전히 잠그는 장치”로 보면 위험합니다. 외부 노출은 프록시에서 끝내세요.10
3) 프리필/컨텍스트 비용을 모니터링 지표로 승격
“토큰/초”만 보면 운영에서 터집니다. 최소한 아래를 로그/메트릭으로 남기세요:
- prompt tokens, output tokens, TTFT, decode tok/s
- OOM 재시도 횟수, 큐 대기시간, 배치 크기 변화 TGI는 프리필 상한 같은 런처 파라미터가 이런 지표와 강하게 연결됩니다.7
흔한 함정/안티패턴
GPU 메모리를 0.99까지 태우고 “평균” 벤치만 보고 배포
실제 트래픽은 분산이 있어서, “가끔 긴 프롬프트”가 들어오는 순간 OOM으로 장애가 납니다. vLLM의--gpu-memory-utilization은 여유를 두고, 긴 프롬프트가 많은 서비스면 프롬프트 길이 상한/요약 전략을 같이 설계해야 합니다.9OpenAI 호환이면 완전히 동일하다고 가정
엔진마다 지원 파라미터/스트리밍/에러 형태가 미묘하게 다릅니다. “우리 앱이 쓰는 기능(예: tool calling, JSON schema, logprobs)”을 체크리스트로 만들고 PoC에서 계약 테스트(contract test)를 돌리세요. (vLLM/Ollama 모두 ‘호환’임을 강조하지만 범위가 다를 수 있음)1
비용/성능/안정성 트레이드오프(결정용 요약)
- vLLM: 처리량/동시성 최적화에 강함(비용 효율↑). 대신 보안/프록시/관측까지 “프로덕션 엔지니어링”이 전제.2
- TGI: HF 생태계와 운영 옵션이 명시적(팀 운영 표준화에 유리). 워크로드에 따라 vLLM 대비 처리량이 덜 나올 수 있으니 실제 트래픽으로 측정 필수.6
- Ollama: 로컬/내부 도구에서 시간 절약이 압도적. 대규모 동시성/최대 처리량이 목표라면 “편의성의 비용”을 받아들이는 선택.4
🚀 마무리
핵심은 “기술 우열”이 아니라 내 트래픽 형태와 운영 역량에 맞는 서빙 레이어를 고르는 것입니다.
- 동시 요청이 많고 GPU 비용이 민감하면: vLLM을 1순위로 PoC(특히 PagedAttention/continuous batching의 이점).2
- Hugging Face 중심(모델 허브/툴체인/샤딩 운영 표준)이라면: TGI를 기준선으로 두고, 프리필/배칭 파라미터 튜닝을 운영 체계에 포함.3
- “팀이 지금 당장 쓰는 내부 LLM”이 필요하면: Ollama로 빠르게 가치 검증 후, 트래픽이 커질 때 vLLM/TGI로 승격하는 로드맵이 현실적입니다.4
다음 학습 추천(실무 순서): 1) vLLM OpenAI-compatible server/vllm serve 옵션과 보안 주의사항 정독10
2) TGI Architecture + launcher 파라미터(프리필/배칭/샤딩)로 “내 워크로드에서 병목이 어디인지” 찾기7
3) Ollama Docker/OpenAI compatibility로 기존 앱을 연결하고, “언제 vLLM/TGI로 넘어갈지” 기준(QPS, 동시성, 비용)을 수치로 정하기4
https://docs.vllm.ai/en/latest/serving/online_serving/openai_compatible_server/ ↩︎ ↩︎2 ↩︎3
https://huggingface.co/docs/text-generation-inference/index ↩︎ ↩︎2
https://huggingface.co/docs/text-generation-inference/en/architecture ↩︎ ↩︎2 ↩︎3 ↩︎4 ↩︎5 ↩︎6
https://www.mintlify.com/vllm-project/vllm/api/cli/serve ↩︎ ↩︎2