DOCS/300_architecture/370_임베딩_서비스_분리_아키텍처.md
happybell80 3f3449da0c docs: 2단계 완료 - 누락 문서 채우기 및 용어 통일
- 510번: 스타트업 밸류에이션 → 실제 로빙 MVP 개발기로 교체
- 370번: 임베딩 서비스 분리 아키텍처 문서 보완
- 550번: 수익모델과 비즈니스 전략 완전 재작성
- 650번 용어집: 로빙/존재형 에이전트/AI 에이전트 용어 정의 명확화
2025-08-06 13:04:32 +09:00

4.8 KiB

370. 임베딩 서비스 분리 아키텍처

개요

각 로빙이 독립적으로 ONNX 임베딩 모델을 로드하던 구조에서 중앙 임베딩 서비스를 공유하는 구조로 전환하여, 메모리 사용량을 극적으로 감소시키고 확장성을 확보했습니다.

"모든 로빙이 하나의 임베딩 서비스를 공유하면, 메모리는 절약되고 성능은 유지된다."

문제점

  • 각 로빙마다 동일한 임베딩 모델(449MB) 중복 로드
  • rb10508_micro: 987.9MB 메모리 사용
  • 로빙 추가 시 선형적 메모리 증가

해결책: 중앙 임베딩 서비스

아키텍처

이전:                              이후:
┌─────────────┐                   ┌─────────────┐
│  rb10508    │                   │  rb10508    │
│ ONNX Model  │                   │   (118MB)   │──┐
│  (988MB)    │                   └─────────────┘  │
└─────────────┘                                     │
                                                    ▼
┌─────────────┐                   ┌─────────────┐  ┌─────────────────┐
│   rb8001    │                   │   rb8001    │  │ skill-embedding │
│ ONNX Model  │         →         │   (200MB)   │──│   (874.4MB)     │
│  (416MB)    │                   └─────────────┘  │  - ONNX Model   │
└─────────────┘                                     │  - Port 8015    │
                                                    ▼  └─────────────────┘
┌─────────────┐                   ┌─────────────┐
│  rb10408    │                   │  rb10408    │
│ ONNX Model  │                   │   (30MB)    │──┘
│   (55MB)    │                   └─────────────┘
└─────────────┘

기술 스택

  • FastAPI + Uvicorn: 고성능 비동기 웹 서버
  • ONNX Runtime: 최적화된 임베딩 생성
  • multilingual-MiniLM-L12-v2: 다국어 지원 임베딩 모델

API 설계

# POST /embed
{
    "texts": ["안녕하세요", "오늘 날씨가 좋네요"]
}

# Response
{
    "embeddings": [
        [0.1, 0.2, ...],  # 384차원 벡터
        [0.3, 0.4, ...]
    ]
}

# GET /health
{
    "status": "healthy",
    "service": "skill-embedding",
    "model": "multilingual-MiniLM-L12-v2",
    "uptime": 3600.5
}

구현 가이드

1. 로빙 측 변경사항

# 기존: ONNX 직접 로드
from onnx_embedder import ONNXEmbedder
embedder = ONNXEmbedder("/models/onnx/...")

# 변경: HTTP 임베딩 함수
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]]:
        response = requests.post(self.url, json={"texts": input}, timeout=30)
        return response.json()["embeddings"]

2. ChromaDB 통합

# memory.py
self.episodic = self.client.get_or_create_collection(
    name=f"{self.robing_id}_episodic",
    embedding_function=HTTPEmbeddingFunction()  # HTTP 방식으로 변경
)

3. Docker 구성 변경

# 불필요한 볼륨 제거
# - /opt/models:/models:ro  # 더 이상 필요 없음

# 환경변수 추가
environment:
  - SKILL_EMBEDDING_URL=http://localhost:8015

성능 분석

메모리 절감

  • rb10508_micro: 988MB → 118MB (-870MB, 88% 감소)
  • 예상 절감 (100개 로빙): 87GB 메모리 절약

레이턴시

  • HTTP 오버헤드: +7ms (무시할 수준)
  • 전체 응답시간: 1-3초 중 0.2% 미만

확장성

  • 단일 임베딩 서비스로 수백 개 로빙 지원
  • 수평 확장 가능 (로드밸런서 적용 시)

모니터링

# 주요 메트릭
- 임베딩 생성 요청 
- 평균 응답 시간
- 메모리 사용량
- 에러율

# 헬스체크
curl http://localhost:8015/health

다음 단계

  1. 캐싱 레이어 추가: Redis로 자주 사용되는 임베딩 캐싱
  2. 배치 처리 최적화: 대량 텍스트 임베딩 성능 개선
  3. 모델 업데이트: L12 → L6 모델로 추가 경량화 검토
  4. 다른 로빙 적용: rb8001, rb10408에 순차 적용

교훈

  • 중복 제거의 힘: 동일한 기능을 서비스로 분리하면 극적인 효율성 향상
  • 간단한 구현: 12줄의 HTTPEmbeddingFunction으로 870MB 절약
  • 점진적 적용: 하나의 로빙에서 성공 후 확산

"임베딩은 공유하되, 기억은 분리하라"