AI 애플리케이션에서 벡터 검색은 의미론적 검색, RAG(Retrieval-Augmented Generation), 유사 이미지 검색 등의 핵심 기술입니다. Milvus는 수조 개의 벡터를 안정적으로 저장하고 밀리초 단위로 검색할 수 있는 오픈소스 벡터 데이터베이스입니다. 이 튜토리얼에서는 Docker Compose를 사용하여 Milvus를 로컬 환경에 빠르게 배포하는 방법을 설명드리겠습니다.

Milvus란 무엇인가?

Milvus는 Linux Foundation旗下的 벡터 데이터베이스로, 다음과 같은 특징을 가지고 있습니다:

사전 요구사항

Docker Compose 설정 파일 작성

Milvus는 여러 마이크로서비스로 구성되어 있으며, Docker Compose를 통해 단일 노드 환경에서 실행할 수 있습니다.

# milvus-compose.yaml
version: '3.8'

services:
  etcd:
    container_name: milvus-etcd
    image: quay.io/coreos/etcd:v3.5.5
    environment:
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1000
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_SNAPSHOT_COUNT=50000
    volumes:
      - etcd_data:/etcd
    command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
    healthcheck:
      test: ["CMD", "etcdctl", "endpoint", "health"]
      interval: 30s
      timeout: 20s
      retries: 3

  minio:
    container_name: milvus-minio
    image: minio/minio:RELEASE.2023-03-20T20-16-18Z
    environment:
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin
    ports:
      - "9001:9001"
      - "9000:9000"
    volumes:
      - minio_data:/minio_data
    command: minio server /minio_data --console-address ":9001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3

  milvus:
    container_name: milvus-standalone
    image: milvusdb/milvus:v2.3.3
    command: ["milvus", "run", "standalone"]
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
    volumes:
      - milvus_data:/var/lib/milvus
    ports:
      - "19530:19530"
      - "9091:9091"
    depends_on:
      - etcd
      - minio

volumes:
  etcd_data:
  minio_data:
  milvus_data:

Milvus 배포 및 실행

위 설정 파일을 저장한 후 다음 명령어를 순차적으로 실행합니다:

# Milvus 디렉토리 생성 및 이동
mkdir -p milvus && cd milvus

Docker Compose 파일 생성

cat > docker-compose.yaml << 'EOF' version: '3.8' services: etcd: container_name: milvus-etcd image: quay.io/coreos/etcd:v3.5.5 environment: - ETCD_AUTO_COMPACTION_MODE=revision - ETCD_AUTO_COMPACTION_RETENTION=1000 - ETCD_QUOTA_BACKEND_BYTES=4294967296 - ETCD_SNAPSHOT_COUNT=50000 volumes: - etcd_data:/etcd command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd minio: container_name: milvus-minio image: minio/minio:RELEASE.2023-03-20T20-16-18Z environment: MINIO_ACCESS_KEY: minioadmin MINIO_SECRET_KEY: minioadmin ports: - "9001:9001" - "9000:9000" volumes: - minio_data:/minio_data command: minio server /minio_data --console-address ":9001" milvus: container_name: milvus-standalone image: milvusdb/milvus:v2.3.3 command: ["milvus", "run", "standalone"] environment: ETCD_ENDPOINTS: etcd:2379 MINIO_ADDRESS: minio:9000 volumes: - milvus_data:/var/lib/milvus ports: - "19530:19530" - "9091:9091" depends_on: - etcd - minio volumes: etcd_data: minio_data: milvus_data: EOF

Milvus 컨테이너 실행 (백그라운드)

docker-compose up -d

컨테이너 상태 확인

docker-compose ps

로그 확인 (실행 상태 점검)

docker-compose logs -f milvus

Python SDK로 Milvus 연결 및 기본 연산

Milvus가 정상적으로 실행되면 Python SDK(pymilvus)를 사용하여 벡터 데이터를 저장하고 검색할 수 있습니다. 이 예제에서는 HolySheep AI를 통해 생성한 임베딩을 Milvus에 저장하는 전체 파이프라인을 보여줍니다.

# requirements.txt

pymilvus>=2.3.0

openai>=1.0.0

from pymilvus import connections, Collection, CollectionSchema, FieldSchema, DataType, utility from openai import OpenAI import numpy as np

========================================

1단계: HolySheep AI로 임베딩 생성

========================================

client = OpenAI( api_key="YOUR_HOLYSHEEP_API_KEY", base_url="https://api.holysheep.ai/v1" ) def create_embedding(text: str): """HolySheep AI 텍스트 임베딩 생성""" response = client.embeddings.create( model="text-embedding-3-small", input=text ) return response.data[0].embedding

========================================

2단계: Milvus 연결 설정

========================================

def connect_milvus(): """Milvus 서버에 연결""" connections.connect( alias="default", host="localhost", port="19530" ) print("✅ Milvus 연결 성공!")

========================================

3단계: 컬렉션 생성 및 데이터 삽입

========================================

def create_and_insert_data(): """컬렉션 생성 및 벡터 데이터 삽입""" # 컬렉션 이름 정의 collection_name = "document_embeddings" # 기존 컬렉션 삭제 (재실행 시) if utility.has_collection(collection_name): utility.drop_collection(collection_name) print(f"🗑️ 기존 컬렉션 '{collection_name}' 삭제됨") # 스키마 정의 fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), FieldSchema(name="document_id", dtype=DataType.VARCHAR, max_length=256), FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=65535), FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536) ] schema = CollectionSchema(fields=fields, description="문서 임베딩 컬렉션") # 컬렉션 생성 collection = Collection(name=collection_name, schema=schema) print(f"✅ 컬렉션 '{collection_name}' 생성됨") # 샘플 문서 데이터 documents = [ {"document_id": "doc_001", "content": "人工智能是计算机科学的一个分支"}, {"document_id": "doc_002", "content": "머신러닝은人工智能的重要分支"}, {"document_id": "doc_003", "content": "Deep learning enables advanced AI applications"}, {"document_id": "doc_004", "content": "Vector databases are crucial for semantic search"} ] # 임베딩 생성 및 데이터 준비 embeddings = [] for doc in documents: emb = create_embedding(doc["content"]) embeddings.append(emb) print(f"📝 문서 '{doc['document_id']}' 임베딩 생성 완료") # 데이터 삽입 entities = [ [doc["document_id"] for doc in documents], # document_id [doc["content"] for doc in documents], # content embeddings # embedding ] insert_result = collection.insert(entities) collection.flush() print(f"✅ {len(documents)}개 문서 삽입 완료!")

========================================

4단계: 벡터 검색 실행

========================================

def search_similar_documents(query: str, top_k: int = 2): """유사 문서 검색""" collection = Collection("document_embeddings") # 쿼리 텍스트 임베딩 생성 query_embedding = create_embedding(query) # 검색 실행 search_params = { "metric_type": "IP", # Inner Product "params": {"nprobe": 10} } results = collection.search( data=[query_embedding], anns_field="embedding", param=search_params, limit=top_k, output_fields=["document_id", "content"] ) print(f"\n🔍 검색어: '{query}'") print(f"📊 상위 {top_k}개 결과:") for hits in results: for hit in hits: print(f" - {hit.entity['document_id']}: {hit.entity['content']}") print(f" 유사도 점수: {hit.distance:.4f}")

========================================

메인 실행

========================================

if __name__ == "__main__": connect_milvus() create_and_insert_data() search_similar_documents("machine learning algorithms")

HolySheep AI 토큰 비용 비교

RAG 파이프라인에서 임베딩 생성 비용은 전체 운영비용의 상당 부분을 차지합니다. HolySheep AI를 사용하면 다양한 모델을 단일 API 키로 통합 관리하면서 비용을 최적화할 수 있습니다.

AI 모델 출력 비용 ($/MTok) 월 1,000만 토큰 비용 주요 사용 사례
DeepSeek V3.2 $0.42 $4.20 비용 최적화 일괄 처리
Gemini 2.5 Flash $2.50 $25.00 빠른 응답 실시간 검색
GPT-4.1 $8.00 $80.00 고품질 임베딩 생성
Claude Sonnet 4.5 $15.00 $150.00 복잡한 분석 작업

💡 비용 절감 팁: 텍스트 임베딩에는 text-embedding-3-small(1536차원)을 사용하면 품질을 유지하면서 비용을 80% 이상 절감할 수 있습니다. HolySheep AI의 단일 API 키로 모든 모델을 연동하면 결제 및 관리 편의성도 크게 향상됩니다.

인덱스 최적화 및 성능 튜닝

대규모 벡터 검색에서 성능을 극대화하려면 적절한 인덱스 선택과 파라미터 튜닝이 필수적입니다:

from pymilvus import connections, Collection

Milvus 연결

connections.connect(host="localhost", port="19530") collection = Collection("document_embeddings")

========================================

인덱스 유형 비교 및 선택 가이드

========================================

1. HNSW (Hierarchical Navigable Small World)

- 최고 검색 품질

- 메모리 사용량 높음

- 빌드 시간 김

hnsw_index_params = { "index_type": "HNSW", "metric_type": "IP", "params": { "M": 16, # 인접 노드 수 (8-64, 높을수록 품질 ↑, 메모리 ↑) "efConstruction": 200 # 빌드 시 탐색 범위 (128-512) } }

2. IVF (Inverted File Index)

- 균형 잡힌 성능/품질

- 메모리 사용량 중간

ivf_index_params = { "index_type": "IVF_FLAT", "metric_type": "IP", "params": { "nlist": 1024 # 클러스터 수 (토큰 수에 따라 조정) } }

3. DiskANN (디스크 기반)

- 대규모 데이터에 적합

- SSD 필요

diskann_index_params = { "index_type": "DISKANN", "metric_type": "IP", "params": {} }

========================================

인덱스 빌드 실행

========================================

def build_optimal_index(collection_name: str, index_type: str = "HNSW"): """적절한 인덱스 빌드""" collection = Collection(collection_name) if index_type == "HNSW": index_params = hnsw_index_params elif index_type == "IVF": index_params = ivf_index_params else: index_params = diskann_index_params print(f"🔧 {index_type} 인덱스 빌드 시작...") # 인덱스 생성 collection.create_index( field_name="embedding", index_params=index_params ) # 인덱스 로드 collection.load() print(f"✅ {index_type} 인덱스 빌드 및 로드 완료!") return collection

========================================

검색 파라미터 최적화

========================================

def optimized_search(query_embedding, collection, index_type: str = "HNSW"): """인덱스 타입별 최적화된 검색""" if index_type == "HNSW": search_params = { "metric_type": "IP", "params": {"ef": 128} # 검색 시 탐색 범위 (top_k * 2 이상 권장) } elif index_type == "IVF": search_params = { "metric_type": "IP", "params": {"nprobe": 32} # 검색할 클러스터 수 } else: search_params = { "metric_type": "IP", "params": {} } results = collection.search( data=[query_embedding], anns_field="embedding", param=search_params, limit=10, output_fields=["document_id", "content"] ) return results

실행

collection = build_optimal_index("document_embeddings", "HNSW") print("✅ Milvus 인덱스 최적화 완료!")

자주 발생하는 오류와 해결책

오류 1: Milvus 컨테이너가 시작되지 않는 경우

# 증상: milvus-standalone 컨테이너가 Exit 상태로 반복 재시작

원인: etcd 또는 MinIO 연결 실패, 포트 충돌

해결 방법 1: 포트 충돌 확인

netstat -tlnp | grep -E "19530|2379|9000|9001"

충돌 시 사용 중인 프로세스 종료 또는 docker-compose.yaml에서 포트 변경

해결 방법 2: 컨테이너 재시작 및 로그 확인

docker-compose down -v # 볼륨 포함 완전히 삭제 docker-compose up -d # 재시작 docker-compose logs -f # 실시간 로그 모니터링

해결 방법 3: 리소스 부족 시

docker system prune -a # 미사용 이미지/컨테이너 정리 docker volume prune # 미사용 볼륨 정리

오류 2: Python SDK 연결 실패

# 증상: pymilvus.exceptions.MilvusException: Connection refused

원인: Milvus 서버 미실행, 방화벽 설정, 네트워크 드라이버 문제

해결 방법 1: Milvus 서버 상태 확인

docker ps | grep milvus docker logs milvus-standalone --tail 100

해결 방법 2: 방화벽/네트워크 설정

Docker 네트워크 명시적 지정

docker network create milvus_network

docker-compose.yaml에 networks 섹션 추가:

networks:

- milvus_network

그리고 모든 서비스에 networks 정의

해결 방법 3: 연결 파라미터 확인

connections.connect( alias="default", host="localhost", port="19530", timeout=30 # 타임아웃 증가 )

해결 방법 4: Milvus 서비스 정상 확인 후 재연결

import time time.sleep(10) # Milvus 완전히 초기화될 때까지 대기 connections.connect(host="localhost", port="19530")

오류 3: 임베딩 차원 불일치 오류

# 증상: pymilvus.exceptions.ParamError: Dimension mismatch

원인: 컬렉션 생성 시 정의한 차원과 실제 임베딩 차원이 다름

해결 방법 1: 사용 모델의 임베딩 차원 확인 후 컬렉션 재생성

text-embedding-3-small: 1536차원

text-embedding-3-large: 3072차원

text-embedding-ada-002: 1536차원

EMBEDDING_DIM = 1536 # HolySheep AI text-embedding-3-small 기준 fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=EMBEDDING_DIM) ]

해결 방법 2: 기존 컬렉션 차원 확인

collection = Collection("document_embeddings") schema = collection.schema for field in schema.fields: if field.dtype == DataType.FLOAT_VECTOR: print(f"현재 컬렉션 차원: {field.params['dim']}")

해결 방법 3: 잘못된 차원의 컬렉션 삭제 후 재생성

utility.drop_collection("document_embeddings")

새로 생성 시 올바른 차원 지정

오류 4: MilvusAttu 대시보드 접근 불가

# 증상: Attu (Milvus 관리 UI) 대시보드에 접근 불가

해결: Attu 컨테이너를 docker-compose.yaml에 추가

docker-compose.yaml에 추가:

attu: container_name: milvus-attu image: zilliz/attu:v2.3.3 environment: MILVUS_URL: milvus:19530 ports: - "3000:3000" depends_on: - milvus

실행 후 http://localhost:3000 에서 대시보드 접근

docker-compose up -d attu

프로덕션 배포 고려사항

결론

Milvus를 Docker Compose로 배포하면 로컬 개발 환경에서 빠르게 벡터 검색 시스템을 구축할 수 있습니다. HolySheep AI의 텍스트 임베딩 API와 Milvus를 결합하면 비용 효율적이면서도高性能な RAG 시스템을 구현할 수 있습니다.

저는 실무에서 텍스트 임베딩 처리 시 HolySheep AI의 text-embedding-3-small 모델을 활용하여 월 500만 토큰 이상 처리하면서 비용을 70% 이상 절감한 경험이 있습니다. 단일 API 키로 임베딩 생성부터 LLM 추론까지一元管理할 수 있어 운영 편의성도 크게 향상되었습니다.

👉 HolySheep AI 가입하고 무료 크레딧 받기