🎯 프로젝트 개요
개인 프로젝트로 원격 GPU 서버를 활용해 LLM 챗봇 서비스를 구축했습니다. 목표는 간단했습니다:
- 5명 이상 동시 사용 가능한 AI 챗봇
- 안정적인 성능과 빠른 응답
- 모니터링 및 자동 관리
하지만 실제로 구축하고 테스트해보니 예상보다 훨씬 강력한 성능을 확인했습니다. 최종적으로 50명 동시 접속도 무리 없이 처리하는 시스템이 완성되었습니다.
🏗️ 시스템 구성
하드웨어
원격 서버
- GPU: NVIDIA GB10
- RAM: 119.6GB
- CPU: 20-core ARM64 (aarch64)
- OS: NVIDIA DGX Spark 7.4.0 (Linux 6.14.0)
Main 서버 (yeonghoon-kim)
- GPU: 미사용 (원격 서버 활용)
- 역할: Open WebUI 호스팅, 모니터링
소프트웨어 스택
┌─────────────────────────────────────────┐
│ Main 서버 (Open WebUI) │
│ - 웹 인터페이스 │
│ - 사용자 인증 │
│ - 채팅 이력 관리 │
└─────────────────────────────────────────┘
↓ HTTP/WebSocket
┌─────────────────────────────────────────┐
│ 원격 LLM 서버 (Ollama) │
│ - Nginx 로드밸런서 │
│ - Ollama 인스턴스 (GPU 가속) │
│ - 12개 LLM 모델 호스팅 │
└─────────────────────────────────────────┘
↓ Prometheus
┌─────────────────────────────────────────┐
│ 모니터링 (Grafana + Prometheus) │
│ - GPU 사용률, 메모리, 온도 │
│ - 시스템 리소스 │
└─────────────────────────────────────────┘
🚀 구축 과정
1단계: Ollama 배포
원격 서버에 Docker를 사용해 Ollama를 배포했습니다:
| |
주요 설정:
OLLAMA_NUM_PARALLEL=5: 동시 요청 5개 처리OLLAMA_KEEP_ALIVE=5m: 미사용 모델 5분 후 자동 언로드- GPU 전체 활용
2단계: Nginx 로드밸런서
처음엔 2개의 Ollama 인스턴스로 시작했지만, 메모리 중복 로드 문제가 발견되었습니다:
ollama-1: codellama:34b (33.8GB)
ollama-2: codellama:34b (33.8GB) ← 중복!
----------------------------------
합계: 67.6GB (메모리 낭비)
해결: ollama-2를 중지하고 ollama-1만 운영
- 메모리 사용량 50% 절감
- 성능 저하 없음 (단일 인스턴스로도 50명 처리 가능)
3단계: Open WebUI 연동
Main 서버에서 Open WebUI를 배포:
| |
도메인: 내부 도메인 (비공개)
- Caddy를 통한 HTTPS 지원
- IP 제한 (내부 네트워크만 접근)
4단계: GPU 모니터링
Prometheus + Grafana로 실시간 모니터링:
수집 메트릭:
- GPU 사용률
- GPU 메모리 (nvidia-smi 파싱)
- GPU 온도
- 시스템 리소스 (CPU, 메모리, 디스크)
Grafana 대시보드:
- Row 1: GPU 사용률
- Row 2: GPU 메모리 (used/total)
- Row 3: GPU 온도
🧪 성능 테스트
동시 접속 테스트
테스트 방법:
- 간단한 프롬프트 (“Say hello in 5 words”)
- curl을 사용한 동시 요청
- 성공/실패 및 응답 시간 측정
경량 모델 (neural-chat:7b, 3.8GB)
| 동시 사용자 | 성공률 | 평균 응답 시간 |
|---|---|---|
| 5명 | 100% | 5-15초 (첫 로드) |
| 10명 | 100% | 0.4-3.6초 |
| 20명 | 100% | 0.4-3.9초 |
| 50명 | 100% | 0.4-5초 |
발견:
- 모델이 로드되면 초고속 (0.4초)
- 메모리 공유로 효율적 처리
- 50명 동시 접속도 타임아웃 없음
대형 모델 (codellama:34b, 17.7GB)
| 동시 사용자 | 성공률 | 평균 응답 시간 |
|---|---|---|
| 10명 | 100% | 10-14초 (첫 로드) |
| 20명 | 100% | 2-9초 |
| 50명 | 100% | 2-28초 |
발견:
- 대형 모델도 50명 처리 가능
- 첫 로드 후 성능 대폭 향상
- 메모리 관리로 안정적 처리
모델 순차 로드 테스트
목적: GPU 메모리 한계 및 Ollama 자동 관리 확인
테스트 방법:
- 모든 모델 언로드 (Ollama 재시작)
- 12개 모델 5초 간격 순차 로드
- 각 모델 로드 후 GPU 메모리 측정
결과:
| 모델 | 크기 | 로드 시간 | GPU 메모리 | 상태 |
|---|---|---|---|---|
| neural-chat:7b | 3.8GB | 6.0초 | 6.7 GB | ✅ |
| mistral:latest | 4.1GB | 8.0초 | 31.7 GB | ✅ |
| mistral-openorca:latest | 3.8GB | 8.3초 | 56.4 GB | ✅ |
| deepseek-r1:7b | 4.4GB | 14.4초 | 40.7 GB | ✅ |
| gemma2:9b | 5.1GB | 8.3초 | 60.0 GB | ✅ |
| codellama:13b | 6.9GB | 14.9초 | 90.7 GB 🔥 | ✅ |
| orca2:13b | 6.9GB | 8.7초 | 42.7 GB | ✅ |
| gemma3:12b | 7.6GB | 13.3초 | 95.5 GB 🔥🔥 | ✅ (최대치) |
| deepseek-r1:14b | 8.4GB | 61.3초 | - | ❌ 메모리 부족 |
| gpt-oss:20b | 12.8GB | 9.4초 | 30.1 GB | ✅ |
| qwen3:30b | 17.3GB | 2.2초 | - | ❌ 모델 파일 손상 |
| codellama:34b | 17.7GB | 21.4초 | 63.9 GB | ✅ |
주요 발견:
- GPU 메모리 최대치: ~95.5GB (gemma3:12b 로드 시)
- Ollama 자동 메모리 관리 작동
- 90.7GB → 42.7GB (이전 모델 자동 언로드)
- 95.5GB → 30.1GB (자동 언로드)
- 성공률: 10/12 (83%)
- deepseek-r1:14b: GPU 메모리 부족 (하드웨어 한계)
- qwen3:30b: 모델 파일 손상
💡 최적화 포인트
1. 단일 인스턴스 운영
Before:
ollama-1 (33.8GB) + ollama-2 (33.8GB) = 67.6GB
After:
ollama-1 (33.8GB) = 33.8GB (50% 절감)
효과:
- 메모리 효율 2배 증가
- 단일 인스턴스로도 50명 처리 가능
2. RAG 비활성화
Open WebUI의 RAG 기능을 비활성화하여:
- HuggingFace 의존성 제거
- ‘NoneType’ 에러 방지
- 시작 시간 단축
3. 자동 메모리 관리
Ollama의 OLLAMA_KEEP_ALIVE=5m 설정:
- 미사용 모델 5분 후 자동 언로드
- GPU 메모리 자동 최적화
- 수동 관리 불필요
📊 운영 가이드
권장 모델 선택
일반 사용 (7B-9B):
- neural-chat:7b (코딩)
- mistral:latest (범용)
- gemma2:9b (안정)
전문 작업 (13B):
- codellama:13b (코딩 전문)
- orca2:13b (추론 강화)
대형 작업 (20B-34B):
- gpt-oss:20b (창의적 작업)
- codellama:34b (대규모 코딩)
피하기:
- deepseek-r1:14b (메모리 부족)
- qwen3:30b (불안정)
동시 접속 가이드
| 시간대 | 예상 사용자 | 권장 모델 | 메모리 사용 |
|---|---|---|---|
| 일반 | 10-20명 | 7B-13B | ~30-40GB |
| 피크 | 30-50명 | 7B-9B | ~40-60GB |
| 대형 작업 | 5-10명 | 34B | ~60-70GB |
모니터링 알림 설정
권장 임계값:
- GPU 메모리 > 90%: 경고
- GPU 온도 > 80°C: 경고
- GPU 온도 > 85°C: 위험
🎯 결론
원격 GPU 서버를 활용한 LLM 챗봇 서비스를 성공적으로 구축했습니다:
✅ 달성한 목표:
- 50명 동시 접속 처리 (목표의 10배)
- 경량 모델 0.4초 응답 (초고속)
- 자동 메모리 관리 (안정적)
- 실시간 모니터링 (Grafana)
✅ 핵심 교훈:
- 단일 인스턴스도 충분히 강력
- Ollama 자동 관리가 우수
- 모델 크기와 메모리 trade-off 중요
🚀 다음 단계:
- Grafana 알림 설정
- 사용자 가이드 작성
- 더 많은 모델 테스트
기술 스택:
- Ollama (LLM 서버)
- Open WebUI (웹 인터페이스)
- Nginx (로드밸런서)
- Prometheus + Grafana (모니터링)
- Docker Compose (배포)