벡터 데이터베이스는 AI 시대의 핵심 인프라로 자리 잡았습니다. 십억 개 이상의 임베딩 벡터를 실시간으로 검색해야 하는 시나리오에서, 단일 노드 배포는 한계에 직면합니다. 이 튜토리얼에서는 Milvus 분산 배포 아키텍처를 구성하고, HolySheep AI 게이트웨이와 결합하여 비용 효율적인 AI 검색 파이프라인을 구축하는 방법을 상세히 설명합니다.

왜 분산 배포가 필요한가?

단일 Milvus 인스턴스는 일반적으로 수천만 개 벡터까지만 안정적으로 서비스할 수 있습니다. 그러나:

이런 요구사항을 충족하려면 분산 아키텍처가 필수적입니다.

Milvus 분산 배포 아키텍처

핵심 컴포넌트 구조

# Milvus 분산 배포 docker-compose.yml
version: '3.8'

services:
  # 코디네이터 노드 (탐색 및 데이터 조작 조율)
  rootcoord:
    image: milvusdb/milvus:v2.3.3
    command: ["milvus", "run", "rootcoord"]
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
    depends_on:
      - etcd
      - minio

  # 데이터 코디네이터 (세그먼트 관리)
  datacoord:
    image: milvusdb/milvus:v2.3.3
    command: ["milvus", "run", "datacoord"]
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
    depends_on:
      - etcd
      - minio

  # 쿼리 노드 클러스터 (병렬 검색 수행)
  querynode-1:
    image: milvusdb/milvus:v2.3.3
    command: ["milvus", "run", "querynode"]
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
      QUERYNODE_ID: 1
    deploy:
      replicas: 3
    depends_on:
      - rootcoord

  querynode-2:
    image: milvusdb/milvus:v2.3.3
    command: ["milvus", "run", "querynode"]
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
      QUERYNODE_ID: 2
    depends_on:
      - rootcoord

  # 데이터 노드 클러스터 (임베딩 데이터 수집)
  datanode-1:
    image: milvusdb/milvus:v2.3.3
    command: ["milvus", "run", "datanode"]
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
      DATANODE_ID: 1
    depends_on:
      - rootcoord

  # 인덱스 노드 클러스터 (병렬 인덱스 빌딩)
  indexnode-1:
    image: milvusdb/milvus:v2.3.3
    command: ["milvus", "run", "indexnode"]
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
      INDEXNODE_ID: 1
    depends_on:
      - rootcoord

  # etcd 클러스터 (메타데이터 관리)
  etcd:
    image: quay.io/coreos/etcd:v3.5.5
    environment:
      ETCD_AUTO_COMPACTION_MODE: revision
      ETCD_AUTO_COMPACTION_RETENTION: 1000
    command: ["etcd", "-advertise-client-urls=http://127.0.0.1:2379", 
              "-listen-client-urls=http://0.0.0.0:2379", "--data-dir=/etcd"]

  # 객체 스토리지 (벡터 데이터 영구 저장)
  minio:
    image: minio/minio:RELEASE.2023-09-04
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    command: ["minio", "server", "/minio_data"]
    volumes:
      - minio_data:/minio_data

  # Prometheus 모니터링
  prometheus:
    image: prom/prometheus:v2.45.0
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

volumes:
  minio_data:

Python 클라이언트 연결 예제

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

분산 Milvus 클러스터 연결

connections.connect( alias="distributed_cluster", user="root", password="milvus", host="milvus-cluster-lb.example.com", # 로드밸런서 엔드포인트 port="19530", server_pem_path="./client.pem", # TLS 인증서 server_name="milvus-cluster" )

십억 레벨 처리를 위한 컬렉션 스키마

dim = 1536 # OpenAI 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=dim), FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=65535), FieldSchema(name="category", dtype=DataType.VARCHAR, max_length=100), FieldSchema(name="timestamp", dtype=DataType.INT64) ] schema = CollectionSchema(fields=fields, description="Billion-scale vector collection") collection = Collection(name="billion_vectors", schema=schema)

분산 인덱싱 설정 (검색 성능 최적화)

index_params = { "metric_type": "IP", # 내적 유사도 "index_type": "HNSW", # 계층 탐색 가능 근접 그래프 "params": {"M": 16, "efConstruction": 256} } collection.create_index( field_name="embedding", index_params=index_params, timeout=3600 # 십억 레벨 인덱싱에는 시간이 오래 걸림 )

검색 파라미터 최적화

search_params = { "metric_type": "IP", "params": {"ef": 128} # 검색 정확도 vs 속도 트레이드오프 }

십억 레벨 검색 수행

query_vector = np.random.rand(1, dim).astype(np.float32).tolist() results = collection.search( data=query_vector, anns_field="embedding", param=search_params, limit=10, expr="category == 'tech'", partition_names=["partition_2024_q1", "partition_2024_q2"], consistency_level="Eventually" # 최종 일관성 (빠른 검색) ) print(f"검색 결과