- 패키지 정리 실제 효과: 7.3MB 메모리 절약 - 전체 최적화 과정 요약 (987.9MB → 112.7MB) - 예상 대비 실제 결과 비교표 - 최적화 우선순위 교훈 추가
319 lines
9.1 KiB
Markdown
319 lines
9.1 KiB
Markdown
# skill-embedding 서비스 구축 및 배포
|
|
|
|
**날짜**: 2025-08-05
|
|
**작업자**: happybell80 & Claude
|
|
**관련 서버**: 51124 (skill-embedding 서비스)
|
|
|
|
## 오전 10시 30분
|
|
|
|
### 임베딩 서비스 분리 결정
|
|
|
|
**배경**:
|
|
- rb10508_micro가 987.9MB 메모리 사용 (ONNX 임베딩 모델 포함)
|
|
- 각 로빙마다 동일한 임베딩 모델 중복 로드
|
|
- 향후 로빙 추가 시 메모리 부담 가중
|
|
|
|
**해결 방안**:
|
|
- 중앙 임베딩 서비스 구축 (skill-embedding)
|
|
- 모든 로빙이 HTTP API로 임베딩 요청
|
|
- 메모리 절약: 로빙당 ~500MB 절감 예상
|
|
|
|
## 오전 10시 45분
|
|
|
|
### 서비스 설계 및 개발
|
|
|
|
**주요 결정사항**:
|
|
1. **포트 번호**: 8600 → 8015 (스킬 서비스 포트 범위)
|
|
2. **서비스 이름**: embedding_service → skill-embedding
|
|
3. **접근 방식**: 내부 전용 (nginx 프록시 불필요)
|
|
|
|
**구현 내용**:
|
|
```python
|
|
# FastAPI 엔드포인트
|
|
POST /embed - 텍스트 → 임베딩 변환
|
|
GET /health - 헬스체크
|
|
```
|
|
|
|
**기술 스택**:
|
|
- FastAPI + Uvicorn
|
|
- ONNX Runtime
|
|
- multilingual-MiniLM-L12-v2 모델
|
|
- 384차원 임베딩
|
|
|
|
## 오전 11시 00분
|
|
|
|
### 51124 서버 사전 준비
|
|
|
|
**서버팀 작업**:
|
|
```bash
|
|
# 디렉토리 생성
|
|
mkdir -p /home/admin/ivada_project/skill-embedding/logs
|
|
chmod 777 logs
|
|
|
|
# ONNX 모델 권한 설정
|
|
chown -R 999:999 /home/admin/ivada_project/onnx_models
|
|
|
|
# 환경변수 설정
|
|
cat > .env << EOF
|
|
PORT=8015
|
|
SERVICE_NAME=skill-embedding
|
|
LOG_LEVEL=INFO
|
|
MODEL_PATH=/models/onnx/multilingual-MiniLM-L12-v2
|
|
EOF
|
|
|
|
# Docker 공간 정리 (16.16GB 확보)
|
|
docker system prune -a -f
|
|
```
|
|
|
|
## 오전 11시 15분
|
|
|
|
### 배포 및 검증
|
|
|
|
**Gitea Actions 배포**:
|
|
- SSH 키 기반 51124 서버 배포
|
|
- Docker Compose로 컨테이너 실행
|
|
- 헬스체크 통과
|
|
|
|
**검증 결과**:
|
|
```bash
|
|
# 컨테이너 상태
|
|
CONTAINER ID IMAGE STATUS PORTS NAMES
|
|
abc123def skill-embedding Up 25 seconds 8015/tcp skill-embedding
|
|
|
|
# 메모리 사용량
|
|
skill-embedding: 874.4MB (예상 범위 내)
|
|
|
|
# API 테스트
|
|
curl http://localhost:8015/health
|
|
{"status":"healthy","service":"skill-embedding","model":"multilingual-MiniLM-L12-v2","uptime":25.31}
|
|
|
|
# 임베딩 테스트
|
|
curl -X POST http://localhost:8015/embed \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"texts":["테스트"]}'
|
|
# 384차원 벡터 정상 반환
|
|
```
|
|
|
|
## 오전 11시 20분
|
|
|
|
### ChromaDB 통합 준비
|
|
|
|
**HTTPEmbeddingFunction 구현**:
|
|
```python
|
|
class HTTPEmbeddingFunction(EmbeddingFunction):
|
|
def __init__(self, embedding_service_url="http://localhost:8015"):
|
|
self.url = f"{embedding_service_url}/embed"
|
|
|
|
def __call__(self, texts):
|
|
response = requests.post(self.url, json={"texts": texts})
|
|
return response.json()["embeddings"]
|
|
```
|
|
|
|
**적용 대상**:
|
|
- rb10508_micro: 988.1MB → ~400MB (예상)
|
|
- rb8001: 추후 적용
|
|
- rb10408: 추후 적용
|
|
|
|
## 교훈
|
|
|
|
1. **서비스 분리의 이점**
|
|
- 중복 제거로 메모리 효율성 향상
|
|
- 중앙 관리로 유지보수 용이
|
|
- 확장성 확보 (새 로빙 추가 시 임베딩 서비스 재사용)
|
|
|
|
2. **내부 서비스 설계**
|
|
- nginx 프록시 불필요한 내부 API는 복잡도 감소
|
|
- localhost 통신으로 충분한 성능
|
|
- 보안상 외부 노출 불필요
|
|
|
|
3. **사전 준비의 중요성**
|
|
- 서버팀과 긴밀한 협업으로 원활한 배포
|
|
- 권한 설정 (logs 777, ONNX 모델 999:999) 필수
|
|
- Docker 공간 확보로 빌드 실패 방지
|
|
|
|
4. **단계적 적용 전략**
|
|
- 새 서비스 먼저 안정화
|
|
- 하나의 로빙(rb10508_micro)에 시범 적용
|
|
- 성공 후 다른 로빙들에 확산
|
|
|
|
5. **모니터링 지표**
|
|
- 메모리 사용량: 874.4MB (ONNX 모델 포함)
|
|
- 응답 시간: 단일 텍스트 ~50ms
|
|
- 헬스체크: 30초 간격
|
|
|
|
## 현재 상태
|
|
|
|
**skill-embedding 서비스**:
|
|
- ✅ 정상 가동 중 (포트 8015)
|
|
- ✅ 메모리 사용량 안정적 (874.4MB)
|
|
- ✅ API 응답 정상
|
|
- ✅ 384차원 임베딩 생성 확인
|
|
|
|
**다음 작업**:
|
|
- rb10508_micro의 memory.py 수정
|
|
- ONNXEmbeddingFunction → HTTPEmbeddingFunction 교체
|
|
- 메모리 절감 효과 측정
|
|
|
|
## 오후 1시 40분
|
|
|
|
### rb10508_micro HTTP 임베딩 전환 대성공
|
|
|
|
**목표**: rb10508_micro의 ONNX 임베딩을 HTTP 방식으로 전환
|
|
|
|
**구현 방식**:
|
|
```python
|
|
# memory.py에 간단한 HTTPEmbeddingFunction 추가
|
|
class HTTPEmbeddingFunction(EmbeddingFunction):
|
|
def __init__(self):
|
|
self.url = f"{os.getenv('SKILL_EMBEDDING_URL', 'http://localhost:8015')}/embed"
|
|
|
|
def __call__(self, input: List[str]) -> List[List[float]]:
|
|
if not input:
|
|
return []
|
|
response = requests.post(self.url, json={"texts": input}, timeout=30)
|
|
response.raise_for_status()
|
|
return response.json()["embeddings"]
|
|
```
|
|
|
|
**변경사항**:
|
|
1. memory.py: HTTPEmbeddingFunction 직접 구현 (파일 복사 없이)
|
|
2. requirements.txt: onnxruntime, transformers 제거
|
|
3. docker-compose.yml: ONNX 볼륨 제거, SKILL_EMBEDDING_URL 추가
|
|
|
|
**배포 결과 - 극적인 메모리 절감**:
|
|
```
|
|
배포 전: 988.1 MiB
|
|
배포 후: 118.4 MiB
|
|
절약량: 870 MiB (88% 감소!)
|
|
```
|
|
|
|
**성능 검증**:
|
|
- 헬스체크: 정상 (Up 50초, healthy)
|
|
- API 응답: 정상 작동
|
|
- HTTP 임베딩: 7ms 처리 시간
|
|
- skill-embedding 연동: 완벽
|
|
|
|
## 교훈 (추가)
|
|
|
|
6. **예상보다 좋은 결과**
|
|
- 목표 400MB → 실제 118MB (예상의 30%)
|
|
- ONNX 제거만으로 870MB 절감
|
|
- PyTorch 의존성이 생각보다 무거웠음
|
|
|
|
7. **간단한 구현의 힘**
|
|
- 파일 복사 대신 직접 구현 (12줄)
|
|
- 불필요한 추상화 제거
|
|
- 예외처리는 서비스 레벨에서 충분
|
|
|
|
8. **HTTP 임베딩의 장점**
|
|
- 극적인 메모리 절감 (88%)
|
|
- 7ms 레이턴시는 무시할 수준
|
|
- 중앙 관리로 업데이트 용이
|
|
|
|
9. **아키텍처 검증**
|
|
- 임베딩 서비스 분리 전략 성공
|
|
- 다른 로빙들도 같은 방식 적용 가능
|
|
- 100개 로빙 = 87GB 메모리 절약 가능
|
|
|
|
## 오후 2시 16분
|
|
|
|
### rb10508_micro ChromaDB 경로 표준화
|
|
|
|
**문제상황**:
|
|
- rb10508_micro가 `./chroma_db_micro` 사용 (비표준)
|
|
- 다른 모든 로빙은 `./chroma_db` 표준 경로 사용
|
|
- 백업 크론잡과 인프라 관리의 일관성 필요
|
|
|
|
**해결과정**:
|
|
|
|
1. **서버팀 사전 작업** (51124 서버)
|
|
```bash
|
|
# 컨테이너 중지
|
|
docker stop rb10508_micro
|
|
|
|
# 데이터 마이그레이션
|
|
mv chroma_db_micro/* chroma_db/
|
|
|
|
# 권한 설정
|
|
chown -R 999:999 chroma_db/
|
|
```
|
|
|
|
2. **로컬 개발자 작업**
|
|
- docker-compose.yml 수정: `./chroma_db_micro` → `./chroma_db`
|
|
- git commit & push로 배포
|
|
|
|
3. **검증 결과**
|
|
- ChromaDB 데이터: 17MB → 172KB (압축 후)
|
|
- 기존 기억 완전 보존 ("User: 넌 누구야?" 검색 가능)
|
|
- HTTP 임베딩 정상 작동 (11ms 응답)
|
|
- 메모리 사용량 유지 (120.4MB)
|
|
|
|
**교훈**:
|
|
|
|
10. **표준화의 중요성**
|
|
- 모든 로빙이 동일한 디렉토리 구조 사용
|
|
- 백업, 모니터링, 마이그레이션 자동화 가능
|
|
- 인프라 복잡도 감소
|
|
|
|
11. **안전한 마이그레이션**
|
|
- 서버팀과 협업으로 데이터 손실 방지
|
|
- 컨테이너 중지 → 데이터 이동 → 권한 설정 순서
|
|
- 배포 후 기능 검증 필수
|
|
|
|
## 오후 2시 47분
|
|
|
|
### rb10508_micro 최종 최적화 - 패키지 정리
|
|
|
|
**목표**: 미사용 패키지 제거로 추가 메모리 절약
|
|
|
|
**제거 대상 패키지**:
|
|
1. pytest, pytest-asyncio (테스트 도구)
|
|
2. neo4j (그래프 DB 미사용)
|
|
3. Pillow (이미지 처리 미사용)
|
|
4. passlib[bcrypt] (JWT로 충분)
|
|
5. email-validator (이메일 검증 미구현)
|
|
6. PyMuPDF (이전에 제거)
|
|
|
|
**실제 최적화 결과**:
|
|
```
|
|
메모리: 120MB → 112.7MB (7.3MB 절약)
|
|
이미지: 1.09GB → 1.06GB (30MB 절약)
|
|
```
|
|
|
|
**예상 vs 실제 비교**:
|
|
| 항목 | 예상 | 실제 | 차이 |
|
|
|------|------|------|------|
|
|
| 메모리 절약 | 40MB | 7.3MB | -32.7MB |
|
|
| 이미지 절약 | 40MB | 30MB | -10MB |
|
|
|
|
**전체 최적화 과정 요약**:
|
|
```
|
|
1. 초기상태: 987.9MB RAM, 6.19GB 이미지
|
|
2. HTTP전환: 120.0MB RAM, 1.14GB 이미지 (88% 메모리 감소) ← 핵심!
|
|
3. PyMuPDF제거: 변화 없음, 이미지 55MB 감소
|
|
4. 패키지정리: 112.7MB RAM, 1.06GB 이미지 (7MB 추가 절약)
|
|
```
|
|
|
|
**총 최적화 효과**:
|
|
- 메모리: 987.9MB → 112.7MB (88.6% 감소)
|
|
- 이미지: 6.19GB → 1.06GB (82.9% 감소)
|
|
- 목표 200MB 대비: 56% 달성
|
|
|
|
**교훈**:
|
|
|
|
12. **예상과 실제의 차이**
|
|
- 패키지 크기와 실제 메모리 사용량은 다름
|
|
- 대부분의 절약은 HTTP 임베딩 전환에서 발생
|
|
- 추가 최적화는 수익 감소 효과
|
|
|
|
13. **효율적인 최적화 우선순위**
|
|
- 1순위: 임베딩 모델 제거 (870MB 절약)
|
|
- 2순위: 이미지 크기 최적화 (5GB 절약)
|
|
- 3순위: 미사용 패키지 정리 (7MB 절약)
|
|
|
|
14. **벤치마크 비교**
|
|
- rb10408_test: 55.7MB (최소 기능)
|
|
- rb10508_micro: 112.7MB (풀 기능)
|
|
- 2배 차이는 추가 기능 대비 효율적
|
|
|
|
**결론**: rb10508_micro 최적화 완료! HTTP 임베딩 전환이 핵심이었으며, 112.7MB로 목표 초과 달성. 추가 최적화는 비용 대비 효과가 낮음. |