LLM WikiAccess-protected knowledge portal
← 스터디 홈
59편 · 약 14분

Milvus 3.0: 데이터를 복사하지 않고 레이크에서 직접 벡터 검색하는 Vector Lakebase 아키텍처

왜 지금 봐야 하나

2026년 7월 16일 Zilliz는 Milvus 3.0 GA를 발표하면서 "Vector Lakebase"라는 신조어를 꺼냈다. 이 단어가 중요한 이유는 마케팅 때문이 아니라 데이터 이동 문제에 대한 설계 응답이기 때문이다.

기존 Milvus 2.x에서 데이터 레이크(S3/GCS/ADLS)의 데이터를 벡터 검색에 활용하려면 추출 → Milvus 로드 → 인덱스 빌드 과정을 거쳐야 했다. 이 과정은 세 가지 문제를 낳는다.

  1. 비용: 동일 데이터가 레이크와 벡터 DB에 각각 복제되어 저장 비용이 두 배가 된다.
  2. 복잡성: 소스 데이터가 바뀔 때마다 ETL 파이프라인이 재실행돼야 한다.
  3. 위험: 로딩 과정에서 데이터가 외부로 이동하므로 프라이버시 경계가 흐려진다.

Milvus 3.0의 External Collection은 이 세 문제를 한꺼번에 겨냥한다. 데이터를 Milvus로 가져오는 대신, Milvus가 데이터가 있는 곳에서 직접 인덱스를 만든다. 데이터는 이동하지 않는다.


아키텍처 전환: Vector Database에서 Vector Lakebase로

Milvus 2.x — 데이터 이동 필요
데이터 레이크
S3 / GCS / ADLS
(Parquet, Iceberg)
ETL 복사
Milvus 로컬 스토리지
데이터 중복 저장
벡터 인덱스
Milvus 3.0 — 제자리 인덱싱 (Zero-Copy)
데이터 레이크
S3 / GCS / ADLS
(Iceberg / Parquet / Lance / Vortex)
인덱스만 참조
External Collection
벡터·전문검색·스칼라 인덱스
데이터 원본 불변
Milvus 2.x vs 3.0 아키텍처 비교

변화의 핵심

항목Milvus 2.xMilvus 3.0
데이터 위치Milvus 내부 스토리지원래 레이크 (불변)
인덱스 위치Milvus 내부Milvus가 레이크 옆에 생성
데이터 복사필요없음
소스 갱신 반영ETL 재실행증분 동기화
지원 형식자체 세그먼트Iceberg / Parquet / Lance / Vortex
스토리지 엔진이전 방식Loon (신규)

External Collection

External Collection은 Milvus 3.0의 핵심 기능이다. 데이터를 Milvus 컬렉션으로 "정의"하되 실제 데이터는 레이크에 그대로 둔다.

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

# 외부 Iceberg 테이블을 Milvus 컬렉션으로 등록
client.create_collection_from_lake(
    collection_name="product_embeddings",
    # 데이터 소스: S3의 Iceberg 테이블
    data_source={
        "type": "iceberg",
        "uri": "s3://my-bucket/warehouse/products",
        "catalog": "glue",  # AWS Glue 카탈로그
    },
    # 필드 매핑: 레이크 스키마 → Milvus 컬렉션 필드
    field_mapping=[
        {"source_field": "product_id", "dest_field": "id", "is_primary": True},
        {"source_field": "name_embedding", "dest_field": "vector", "dim": 768},
        {"source_field": "name", "dest_field": "name"},
        {"source_field": "category", "dest_field": "category"},
    ],
    index_params=[
        {"field_name": "vector", "index_type": "HNSW", "metric_type": "COSINE"},
    ],
)

등록 후에는 일반 Milvus 컬렉션과 동일하게 검색할 수 있다.

results = client.search(
    collection_name="product_embeddings",
    data=[query_embedding],
    anns_field="vector",
    search_params={"metric_type": "COSINE", "params": {"ef": 128}},
    limit=10,
    output_fields=["name", "category"],
)

지원 포맷:

  • Apache Iceberg: Glue / Hive 카탈로그 기반 테이블
  • Apache Parquet: S3/GCS/ADLS에 저장된 파케이 파일
  • Lance: 벡터 전용 컬럼형 포맷 (LanceDB 에서 온 개념)
  • Vortex: Milvus 3.0에서 새로 도입한 기본 저장 포맷 (Arrow 호환)

새 스토리지 엔진: Loon

Milvus 3.0은 Loon이라는 새 스토리지 엔진을 도입했다. 기존 스토리지 엔진이 세그먼트 파일을 직접 관리했다면, Loon은 매니페스트(manifest) 기반으로 스토리지를 관리한다.

Loon의 설계 목표:

  • 오브젝트 스토리지에서의 포인트 접근 최적화: S3 같은 오브젝트 스토리지는 순차 읽기에는 효율적이지만 임의 접근(random access)에는 비용이 높다. Loon은 읽기 증폭(read amplification)을 줄이는 매니페스트 구조로 이를 해결한다.
  • 기본 저장 포맷: Vortex: Apache Arrow 호환 컬럼형 포맷으로, 벡터 데이터의 접근 패턴에 최적화됐다.
Loon Storage Engine
Manifest Layer
파일 위치·버전·변경 이력
Vortex Files
Arrow 호환 컬럼형 포맷
벡터 + 스칼라 혼합 저장
Index Files
HNSW / Scalar / 전문검색
오브젝트 스토리지
S3 / GCS / Azure Blob
매니페스트가 변경 이력을 추적하므로 랜덤 읽기 없이 필요한 청크만 접근
Loon 스토리지 엔진 구조

Snapshot: 프로덕션을 멈추지 않는 포인트인타임 뷰

Snapshot은 컬렉션의 특정 시점 읽기 전용 뷰다. 프로덕션 컬렉션이 실시간으로 업데이트되는 동안, 평가·검증·오프라인 분석 작업을 별도 Snapshot에서 실행할 수 있다.

# 현재 상태의 스냅샷 생성
snapshot = client.create_snapshot(
    collection_name="product_embeddings",
    snapshot_name="eval-2026-07-29",
)

# 스냅샷을 대상으로 검색 (프로덕션 컬렉션과 독립적)
eval_results = client.search(
    collection_name="product_embeddings",
    snapshot_name="eval-2026-07-29",
    data=[query_embedding],
    anns_field="vector",
    limit=5,
)

Snapshot의 실제 활용 패턴:

  • RAG 파이프라인 평가: 새 임베딩 모델을 검증할 때 기존 스냅샷과 결과를 비교한다.
  • A/B 테스트: 다른 인덱스 파라미터를 동일 데이터에 적용한 두 스냅샷을 비교한다.
  • 감사 및 재현: 특정 시점의 검색 결과를 재현해야 할 때 사용한다.

네이티브 하이브리드 검색

Milvus 2.x에서도 하이브리드 검색이 가능했지만, 전문 검색(full-text search)을 위해 Elasticsearch 클러스터를 따로 운영해야 하는 경우가 많았다. Milvus 3.0은 벡터 검색과 전문 검색을 단일 엔진에서 처리한다.

from pymilvus import AnnSearchRequest, RRFRanker

# 벡터 검색 요청
vector_req = AnnSearchRequest(
    data=[query_embedding],
    anns_field="vector",
    param={"metric_type": "COSINE", "params": {"ef": 128}},
    limit=20,
)

# 전문 검색 요청
text_req = AnnSearchRequest(
    data=["노트북 배터리 교체"],
    anns_field="title_bm25",
    param={"metric_type": "BM25"},
    limit=20,
)

# Reciprocal Rank Fusion으로 결과 통합
results = client.hybrid_search(
    collection_name="products",
    reqs=[vector_req, text_req],
    ranker=RRFRanker(k=60),
    limit=10,
    output_fields=["title", "category"],
)

단일 엔진에서 하이브리드 검색이 가능해지면서 Elasticsearch/OpenSearch를 벡터 파이프라인에서 제거할 수 있는 경우가 생긴다. 단, 복잡한 전문 검색(언어별 형태소 분석, 커스텀 Analyzer)이 필요한 경우에는 전문 검색 엔진이 더 적합할 수 있다.


배포 방식

Milvus 3.0은 K8s와 Docker 배포를 공식 지원한다.

# Helm 차트로 K8s 배포 (간략화)
helm install milvus milvus/milvus \
  --set cluster.enabled=true \
  --set minio.enabled=false \
  --set externalS3.enabled=true \
  --set externalS3.host=s3.amazonaws.com \
  --set externalS3.bucketName=my-milvus-bucket

지원 오브젝트 스토리지:

  • Amazon S3 (S3 호환 포함: MinIO, Ceph)
  • Google Cloud Storage
  • Azure Blob Storage

SDK 지원:

  • Python (pymilvus ≥ 3.0)
  • Go
  • Node.js

운영 체크리스트

External Collection 도입 전 확인

  • [ ] 데이터 포맷 확인: Iceberg / Parquet / Lance / Vortex 중 하나인가?
  • [ ] 카탈로그 연결: Iceberg의 경우 AWS Glue 또는 Hive Metastore 접근 권한이 있는가?
  • [ ] 인덱스 빌드 시간: 초기 인덱스 빌드는 데이터 크기에 비례한다. 첫 배포 전 소요 시간을 측정한다.
  • [ ] 증분 동기화 주기: 소스 데이터가 변경될 때 인덱스 동기화 지연이 허용 범위인가?

Snapshot 운영

  • [ ] Snapshot은 읽기 전용이다. 스냅샷을 대상으로 쓰기 연산을 시도하면 오류가 발생한다.
  • [ ] 오래된 Snapshot은 오브젝트 스토리지 비용을 증가시킨다. 보존 정책을 설정한다.

Loon + Vortex 스토리지

  • [ ] Vortex는 Arrow 호환이지만 범용 Parquet 리더로 직접 읽을 수 없다. Milvus API를 통해서만 접근한다.
  • [ ] Loon의 매니페스트 파일은 오브젝트 스토리지 버킷에 저장된다. 버킷 권한과 버전 관리 정책을 확인한다.

하이브리드 검색

  • [ ] BM25 인덱스는 컬렉션 생성 시 analyzer_params로 언어별 토크나이저를 지정해야 한다. 기본값은 영어 기준이다.
  • [ ] RRF 랭커의 k 파라미터(기본 60)는 벡터 검색과 전문 검색 결과의 통합 비율에 영향을 준다. 워크로드에 맞게 조정한다.

Milvus 2.x에서 3.0으로 마이그레이션

주요 변경점:

  • API는 하위 호환되지만 일부 컬렉션 설정 파라미터가 변경됐다.
  • 기존 Milvus 2.x 세그먼트는 3.0에서 읽을 수 있다. (Loon이 이전 형식을 임포트)
  • Python SDK는 pymilvus >= 3.0이 필요하다.
# 버전 확인
python -c "import pymilvus; print(pymilvus.__version__)"

# 3.0 호환 SDK 설치
pip install "pymilvus>=3.0"

Open question

  • External Collection의 증분 동기화가 어떤 방식으로 트리거되는지(폴링/이벤트 기반/수동) 공식 문서에 명확하지 않다. 소스 데이터 변경 속도가 높은 환경에서는 직접 측정이 필요하다.
  • Vortex 포맷의 압축 방식과 오브젝트 스토리지 비용 특성이 기존 Parquet 대비 어떻게 다른지 벤치마크가 아직 공개되지 않았다.
  • BM25 전문 검색의 한국어·일본어·중국어 지원 수준이 Elasticsearch/OpenSearch 수준인지 확인이 필요하다.

References