Milvus 벡터 데이터베이스 아키텍처 완전 분석 문서 #
📋 목차 #
개요 #
Milvus의 정의와 위치 #
- Milvus는 현대 AI 애플리케이션의 핵심 인프라로 자리잡은 오픈소스 벡터 데이터베이스
- 전통적인 관계형 데이터베이스가 구조화된 데이터를 처리하는 것과 달리, Milvus는 비정형 데이터(이미지, 텍스트, 오디오, 비디오 등)를 고차원 벡터로 변환하여 저장하고 검색하는 데 특화됨
기술적 기반 #
Milvus는 아래와 같은 검증된 벡터 검색 라이브러리들을 통합하여 구축됨
- Faiss (Facebook AI Similarity Search): Meta에서 개발한 고성능 벡터 유사도 검색 라이브러리로, GPU 가속을 지원하며 대규모 벡터 데이터셋에서 뛰어남
- HNSW (Hierarchical Navigable Small World): 그래프 기반의 근사 최근접 이웃 검색 알고리즘으로, 높은 정확도 & 빠른 검색 속도
- DiskANN: MS에서 개발한 디스크 기반 벡터 검색 엔진으로, 메모리 제약 없이 대용량 데이터셋 처리 가능
- SCANN (Scalable Nearest Neighbors): Google에서 개발한 벡터 검색 라이브러리로, 양자화 기법을 통해 메모리 사용량을 최적화
핵심 가치 #
대규모 처리 능력 #
- 수십억 개의 벡터 처리 가능
- 페타바이트 규모의 데이터 저장 및 검색
- 선형 확장성을 통한 무제한 용량 증설
실시간 성능 #
- 밀리초 단위의 검색 응답 시간
- 동시 처리: 수천 개의 동시 쿼리 지원
- 스트리밍 데이터 실시간 처리
클라우드 네이티브 설계 #
- Kubernetes 완전 지원: 컨테이너 오케스트레이션 환경에서 최적화
- 마이크로서비스 아키텍처: 각 구성 요소의 독립적 확장 및 관리
- 멀티 클라우드 지원: AWS, Azure, GCP 등 주요 클라우드 플랫폼 지원
아키텍처 설계 원칙 #
1. 데이터 Plane과 컨트롤 Plane 분리 #
┌─────────────────────────────────────────────────────────────┐
│ MILVUS ARCHITECTURE │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────────┐ │
│ │ Control Plane │ │ Data Plane │ │
│ │ │ │ │ │
│ │ ┌─────────────┐│ │ ┌─────────────────┐ │ │
│ │ │Coordinator ││ │ │ Streaming Node │ │ │
│ │ │ ││ │ │ │ │ │
│ │ │- Scheduling ││ │ │ - Real-time │ │ │
│ │ │- Metadata ││ │ │ Processing │ │ │
│ │ │- Topology ││ │ │ - Data Ingestion│ │ │
│ │ └─────────────┘│ │ └─────────────────┘ │ │
│ │ │ │ │ │
│ │ ┌─────────────┐│ │ ┌─────────────────┐ │ │
│ │ │Meta Storage ││ │ │ Query Node │ │ │
│ │ │ ││ │ │ │ │ │
│ │ │- etcd ││ │ │ - Historical │ │ │
│ │ │- Consistency││ │ │ Data Query │ │ │
│ │ │- ACID ││ │ │ - Index Search │ │ │
│ │ └─────────────┘│ │ └─────────────────┘ │ │
│ └─────────────────┘ │ │ │
│ │ ┌─────────────────┐ │ │
│ │ │ Data Node │ │ │
│ │ │ │ │ │
│ │ │ - Compaction │ │ │
│ │ │ - Index Build │ │ │
│ │ │ - Optimization │ │ │
│ │ └─────────────────┘ │ │
│ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
이러한 분리 구조는 다음과 같은 장점을 제공
- 독립적 확장성: 컨트롤 Plane과 데이터 Plane이 서로 다른 리소스 요구사항을 가지므로, 각각 독립적으로 확장할 수 있음. e.g, 메타데이터 관리 부하가 증가하면 컨트롤 Plane만 확장하고, 쿼리 처리량이 증가하면 데이터 Plane만 확장 가능
- 장애 격리: 한 Plane의 장애가 다른 Plane에 직접적인 영향을 주지 않음. 데이터 Plane의 일부 노드에 장애가 발생해도 컨트롤 Plane은 정상 동작하며, 장애 복구를 조율할 수 있음
- 운영 효율성: 각 Plane별로 최적화된 운영 전략을 적용할 수 있음. 컨트롤 Plane은 고가용성과 일관성에 중점을 두고, 데이터 Plane은 처리량과 응답 시간에 중점을 둘 수 있음
2. 공유 스토리지 아키텍처 (Shared-Storage Architecture) #
┌───────────────────────────────────────────────────────────────┐
│ SHARED STORAGE ARCHITECTURE │
├───────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │
│ │Compute Node │ │Compute Node │ │Compute Node │ │ ... │ │
│ │ #1 │ │ #2 │ │ #3 │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │- Stateless │ │- Stateless │ │- Stateless │ │ │ │
│ │- Scalable │ │- Scalable │ │- Scalable │ │ │ │
│ │- Ephemeral │ │- Ephemeral │ │- Ephemeral │ │ │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └─────┬─────┘ │
│ │ │ │ │ │
│ └───────────────┼───────────────┼──────────────┘ │
│ │ │ │
│ └───────┬───────┘ │
│ │ │
│ ┌──────────────────────────────▼────────────────────────────┐ │
│ │ SHARED STORAGE LAYER │ │
│ ├───────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │ │
│ │ │ Object Storage │ │ Meta Storage │ │ WAL Storage │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ - Vector Data │ │ - Schema Info │ │ - Log Files │ │ │
│ │ │ - Index Files │ │ - Topology │ │ - Checkpts │ │ │
│ │ │ - Snapshots │ │ - Metadata │ │ - Recovery │ │ │
│ │ │ │ │ │ │ Data │ │ │
│ │ │ (S3/MinIO/Blob) │ │ (etcd) │ │(Woodpecker) │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
핵심 특징:
- 완전한 스토리지-컴퓨팅 분리: 컴퓨팅 노드는 어떠한 영구 데이터도 저장하지 않음. 모든 데이터는 공유 스토리지 레이어에 저장되며, 컴퓨팅 노드는 필요에 따라 데이터를 로드해 처리함
- Woodpecker WAL의 혁신: 전통적인 디스크 기반 WAL과 달리, Woodpecker는 Zero-disk 설계를 채택해 object storage에 직접 log 기록. 로컬 디스크 관리의 복잡성 제거 및 무제한 확장성 제공함
- 탄력적 확장: 컴퓨팅 노드가 상태 비저장이므로, 워크로드에 따라 동적으로 노드를 추가하거나 제거할 수 있음. K8s 환경에서 HPA(Horizontal Pod Autoscaler)를 통해 자동 확장 가능
3. 스트림 처리와 배치 처리 분리 #
┌─────────────────────────────────────────────────────────────────┐
│ STREAM vs BATCH PROCESSING SEPARATION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │
│ │ STREAM PROCESSING │ │ BATCH PROCESSING │ │
│ │ │ │ │ │
│ │ ┌─────────────────────────┐ │ │ ┌─────────────────────────┐ │ │
│ │ │ Streaming Node │ │ │ │ Query Node │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ ┌─────────────────────┐ │ │ │ │ ┌─────────────────────┐ │ │ │
│ │ │ │ Real-time Ingestion │ │ │ │ │ │ Historical Query │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ - Insert/Update │ │ │ │ │ │ - Vector Search │ │ │ │
│ │ │ │ - Delete Operations │ │ │ │ │ │ - Scalar Filtering │ │ │ │
│ │ │ │ - Growing Data │ │ │ │ │ │ - Hybrid Queries │ │ │ │
│ │ │ └─────────────────────┘ │ │ │ │ └─────────────────────┘ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ ┌─────────────────────┐ │ │ │ │ ┌─────────────────────┐ │ │ │
│ │ │ │ Real-time Query │ │ │ │ │ │ Index Management │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ - Growing Data │ │ │ │ │ │ - HNSW/IVF/FLAT │ │ │ │
│ │ │ │ - Low Latency │ │ │ │ │ │ - Optimization │ │ │ │
│ │ │ │ - Consistency │ │ │ │ │ │ - Caching │ │ │ │
│ │ │ └─────────────────────┘ │ │ │ │ └─────────────────────┘ │ │ │
│ │ └─────────────────────────┘ │ │ └─────────────────────────┘ │ │
│ └─────────────────────────────┘ │ │ │
│ │ ┌─────────────────────────┐ │ │
│ │ │ Data Node │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────┐ │ │ │
│ │ │ │ Offline Processing │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ - Compaction │ │ │ │
│ │ │ │ - Index Building │ │ │ │
│ │ │ │ - Optimization │ │ │ │
│ │ │ └─────────────────────┘ │ │ │
│ │ └─────────────────────────┘ │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
이러한 분리는 다음과 같은 장점을 제공:
- 최적화된 성능: 각 처리 유형에 특화된 최적화 가능. 스트림 처리는 낮은 지연시간에, 배치 처리는 높은 처리량에 최적화됨
- 리소스 효율성: 실시간 처리와 배치 처리가 서로 다른 리소스 패턴을 가지므로, 각각에 적합한 하드웨어와 설정을 사용할 수 있음음
- 확장성: 실시간 워크로드와 배치 워크로드를 독립적으로 확장할 수 있어, 비용 효율적인 운영 가능
시스템 레이어 구조 #
Access Layer (접근 계층) - 시스템의 관문 #
Access Layer는 Milvus 시스템의 최전선에서 모든 클라이언트 요청을 처리하는 핵심 계층
Proxy 구성 요소의 역할과 책임 #
상태 비저장 설계의 중요성 Proxy는 완전히 상태 비저장(Stateless)으로 설계됨
- 어떤 세션 정보나 캐시 데이터도 로컬에 저장하지 않음
- 요청 간의 의존성이 없어 완전한 수평 확장 가능
- 장애 발생 시 즉시 다른 Proxy로 트래픽 전환 가능
- 롤링 업데이트나 배포 시 무중단 서비스 가능
로드 밸런싱 전략 Milvus는 다양한 로드 밸런싱 솔루션 지원:
- Nginx: HTTP/HTTPS 트래픽에 대한 고성능 로드 밸런싱, SSL 터미네이션, 요청 라우팅
- Kubernetes Ingress: 클라우드 네이티브 환경에서의 자동 로드 밸런싱, 서비스 디스커버리
- NodePort: 간단한 포트 기반 접근, 개발 및 테스트 환경에 적합
- LVS (Linux Virtual Server): 커널 레벨의 고성능 로드 밸런싱, 대용량 트래픽 처리
요청 검증 프로세스 모든 클라이언트 요청은 다음 단계를 거쳐 검증:
- API 스키마 검증: 요청 형식이 정의된 API 스펙과 일치하는지 확인
- 파라미터 유효성 검사: 벡터 차원, 검색 파라미터, 필터 조건 등의 유효성 검증
- 권한 확인: 사용자 인증 및 리소스 접근 권한 검사
- 리소스 제한 검사: 요청 크기, 동시 연결 수, 처리량 제한 확인
결과 집계 및 후처리 Milvus의 MPP(Massively Parallel Processing) 아키텍처로 인해 하나의 쿼리가 여러 노드에서 병렬 처리됨. Proxy는 이러한 분산 처리 결과를 다음과 같이 집계:
- 중간 결과 수집: 각 워커 노드에서 반환된 부분 결과를 수집
- 병합 및 정렬: 유사도 점수 기준으로 결과를 병합하고 정렬
- Top-K 선택: 최종 사용자가 요청한 개수만큼 상위 결과 선택
- 메타데이터 보강: 필요한 경우 추가 메타데이터 정보 첨부
Coordinator Service - 시스템의 두뇌 #
Coordinator는 Milvus 클러스터 전체의 두뇌 역할을 수행하며, 언제나 단일 인스턴스만 활성화되어 전체 시스템의 일관성 보장
Leader Election과 고가용성 #
Coordinator는 etcd를 통한 리더 선출 메커니즘을 사용
- 분산 락: etcd의 분산 락을 통해 단일 Coordinator만 활성화
- 하트비트: 주기적인 하트비트를 통한 생존 확인
- 자동 장애조치: 리더 장애 시 자동으로 새로운 리더 선출
- 상태 복구: 새로운 리더는 etcd에서 이전 상태를 복구하여 연속성 보장
DDL/DCL/TSO 관리의 세부 사항 #
데이터 정의 언어(DDL) 관리
- 컬렉션 생성: 스키마 검증, 메타데이터 저장, 초기 파티션 설정
- 인덱스 관리: 인덱스 타입 선택, 파라미터 최적화, 빌드 작업 스케줄링
- 파티션 관리: 파티션 생성, 삭제, 병합 작업 조율
- 스키마 진화: 필드 추가/삭제, 데이터 타입 변경 등의 스키마 변경 관리
데이터 제어 언어(DCL) 관리
- 사용자 인증: 사용자 생성, 비밀번호 관리, 세션 관리
- 권한 관리: 역할 기반 접근 제어(RBAC), 리소스별 권한 설정
- 감사 로그: 모든 DDL/DCL 작업에 대한 감사 추적
타임스탬프 오라클(TSO) 서비스 TSO는 분산 환경에서 전역 순서를 보장하는 핵심 서비스
- 단조 증가: 시스템 전체에서 단조 증가하는 타임스탬프 생성
- 고정밀도: 마이크로초 단위의 정밀한 타임스탬프
- 배치 할당: 성능 최적화를 위한 타임스탬프 배치 할당
- 시계 동기화: NTP를 통한 노드 간 시계 동기화
스트리밍 서비스 관리 #
WAL과 Streaming Node 바인딩
- 토픽 관리: Kafka/Pulsar 토픽 생성 및 파티션 관리
- 컨슈머 그룹: 각 Streaming Node에 대한 컨슈머 그룹 할당
- 오프셋 관리: 메시지 처리 진행 상황 추적 및 관리
- 리밸런싱: 노드 추가/제거 시 파티션 재분배
서비스 디스커버리
- 노드 등록: 새로운 Streaming Node의 자동 등록
- 헬스 모니터링: 주기적인 헬스 체크 및 상태 업데이트
- 로드 밸런싱: 워크로드에 따른 동적 로드 분산
- 장애조치: 노드 장애 시 자동 트래픽 재라우팅
쿼리 관리 시스템 #
토폴로지 관리 Query Node의 동적 토폴로지 관리:
- 노드 상태 추적: 각 Query Node의 리소스 사용량, 처리 능력, 응답 시간 모니터링
- 세그먼트 할당: 데이터 세그먼트를 최적의 Query Node에 할당
- 로드 밸런싱: 쿼리 부하를 균등하게 분산
- 동적 확장: 워크로드 변화에 따른 자동 스케일링
서빙 쿼리 뷰 관리 쿼리 라우팅을 위한 메타데이터 뷰 관리
- 세그먼트 맵핑: 각 세그먼트가 어느 노드에 로드되어 있는지 추적
- 인덱스 상태: 각 세그먼트의 인덱스 빌드 상태 및 타입 정보
- 캐시 정보: 자주 액세스되는 데이터의 캐시 위치 정보
- 라우팅 최적화: 네트워크 지연시간을 고려한 최적 라우팅 경로 계산
히스토리컬 데이터 관리 #
오프라인 작업 스케줄링 Data Node에서 수행되는 배치 작업들을 효율적으로 스케줄링:
- 컴팩션 작업: 작은 세그먼트들을 병합하여 스토리지 효율성 향상
- 인덱스 빌딩: 새로운 데이터에 대한 인덱스 구축 작업
- 가비지 컬렉션: 삭제된 데이터의 물리적 제거
- 데이터 마이그레이션: 스토리지 티어 간 데이터 이동
리소스 관리
- 우선순위 기반 스케줄링: 작업 중요도에 따른 우선순위 할당
- 리소스 할당: CPU, 메모리, 디스크 I/O 리소스의 효율적 분배
- 의존성 관리: 작업 간 의존성을 고려한 실행 순서 결정
- 진행 상황 추적: 장시간 실행되는 작업의 진행 상황 모니터링
핵심 구성 요소 상세 분석 #
Worker Nodes - 시스템의 실행 엔진 #
Worker Node들은 Coordinator의 지시를 받아 실제 데이터 처리 작업을 수행하는 실행 엔진. 각 노드는 상태 비저장으로 설계되어 Kubernetes 환경에서 완벽한 확장성과 장애 복구 능력 제공
1. Streaming Node - 실시간 데이터 처리의 핵심 #
Streaming Node는 “샤드 레벨의 미니 브레인"으로 불리며, 실시간 데이터 처리와 일관성 보장의 핵심 역할 담당.
샤드 레벨 일관성 보장 메커니즘
Streaming Node는 각 데이터 샤드에 대해 강력한 일관성 보장:
- WAL 기반 순서 보장: 모든 쓰기 작업이 WAL에 순차적으로 기록되어 작업 순서 보장
- 체크포인트 메커니즘: 주기적으로 데이터 상태의 스냅샷을 생성하여 장애 복구 지점 제공
- 트랜잭션 격리: 동시 실행되는 작업들 간의 격리를 통해 데이터 일관성 보장
- 충돌 감지 및 해결: 동일 데이터에 대한 동시 수정 시 충돌을 감지하고 해결 전략 적용
- 실시간 쿼리 처리 능력
Streaming Node는 성장 중인 데이터(Growing Data)에 대한 실시간 쿼리 처리:
- 인메모리 인덱싱: 새로 삽입된 데이터에 대해 메모리 기반의 임시 인덱스를 구축하여 즉시 검색 가능하
- 증분 인덱스 업데이트: 새로운 벡터가 추가될 때마다 기존 인덱스를 점진적으로 업데이트
- 하이브리드 검색: 성장 중인 데이터와 히스토리컬 데이터를 동시에 검색하여 완전한 결과를 제공
- 지연시간 최적화: 밀리초 단위의 응답 시간을 위한 다양한 최적화 기법 적용
쿼리 플랜 생성 및 최적화
각 쿼리에 대해 최적의 실행 계획을 수립:
- 비용 기반 최적화: 인덱스 타입, 데이터 분포, 하드웨어 특성을 고려한 최적 실행 계획 선택
- 병렬 처리 계획: 멀티코어 환경에서 최대 성능을 위한 병렬 실행 전략 수립
- 캐시 활용 전략: 메모리 계층 구조를 고려한 데이터 접근 패턴 최적화
- 동적 계획 조정: 실행 중 성능 메트릭을 기반으로 계획을 동적으로 조정
데이터 변환 프로세스
성장 중인 데이터를 봉인된(Sealed) 데이터로 변환하는 핵심 프로세스:
- 임계값 모니터링: 세그먼트 크기, 시간 경과, 메모리 사용량 등 다양한 임계값을 모니터링
- 변환 트리거: 설정된 조건 달성 시 자동으로 변환 프로세스 시작
- 데이터 압축: 스토리지 효율성을 위한 고급 압축 알고리즘 적용
- 인덱스 최적화: 장기 저장에 최적화된 인덱스 구조로 변환
- 메타데이터 동기화: 변환 완료 후 모든 관련 메타데이터 업데이트
2. Query Node - 히스토리컬 데이터 검색 전문가 #
Query Node는 봉인된 히스토리컬 데이터에 대한 고성능 검색을 전담하는 특화된 노드
세그먼트 로딩 및 관리 전략
효율적인 메모리 관리와 성능 최적화를 위한 정교한 로딩 전략:
- 지연 로딩(Lazy Loading): 실제 쿼리 요청이 있을 때만 세그먼트를 메모리에 로드하여 메모리 효율성 극대화
- LRU 캐시 정책: 가장 오래 사용되지 않은 세그먼트를 우선적으로 메모리에서 제거
- 프리로딩: 접근 패턴 분석을 통해 자주 사용될 세그먼트를 미리 로드
- 메모리 풀 관리: 세그먼트별 메모리 할당을 효율적으로 관리하는 전용 메모리 풀 운영
- 압축 해제 최적화: 스토리지에서 로드된 압축 데이터의 빠른 압축 해제
다양한 인덱스 타입 지원
각기 다른 특성과 용도를 가진 다양한 벡터 인덱스를 지원합니다:
HNSW (Hierarchical Navigable Small World):
- 그래프 기반 인덱스로 높은 검색 정확도와 빠른 속도 제공
- 메모리 사용량이 많지만 최고 수준의 성능 보장
- 실시간 업데이트가 어려워 주로 정적 데이터에 사용
IVF (Inverted File):
- 클러스터링 기반 인덱스로 메모리 효율성과 성능의 균형
- IVF_FLAT: 정확한 거리 계산으로 높은 정확도
- IVF_PQ: 제품 양자화를 통한 메모리 사용량 최적화
FLAT:
- 브루트포스 검색으로 100% 정확도 보장
- 작은 데이터셋이나 최고 정확도가 필요한 경우 사용
- 선형 시간 복잡도로 대용량 데이터에는 부적합
ANNOY (Approximate Nearest Neighbors Oh Yeah):
- 트리 기반 인덱스로 빠른 검색과 작은 메모리 사용량
- 인덱스 빌드 후 수정 불가능한 정적 특성
하이브리드 쿼리 실행 엔진
벡터 유사도 검색과 스칼라 필터링을 결합한 복합 쿼리 처리:
- 필터 우선 전략: 스칼라 조건을 먼저 적용하여 검색 범위를 축소한 후 벡터 검색 수행
- 벡터 우선 전략: 벡터 유사도 검색을 먼저 수행한 후 스칼라 필터 적용
- 동적 전략 선택: 쿼리 특성과 데이터 분포를 분석하여 최적 전략 자동 선택
- 병렬 실행: 여러 세그먼트에 대한 검색을 병렬로 수행하여 처리 시간 단축
결과 집계 및 최적화
분산된 검색 결과를 효율적으로 집계하고 최적화:
- Top-K 병합: 각 세그먼트에서 반환된 Top-K 결과를 전역 Top-K로 병합
- 점수 정규화: 서로 다른 세그먼트 간 점수 스케일 차이를 정규화
- 중복 제거: 동일한 엔티티가 여러 세그먼트에 존재할 경우 중복 제거
- 메타데이터 보강: 필요한 경우 추가 속성 정보를 결과에 포함
3. Data Node - 데이터 최적화의 전문가 #
Data Node는 히스토리컬 데이터의 장기 저장과 최적화를 담당하는 배치 처리 전문 노드입니다.
컴팩션 엔진의 고도화
스토리지 효율성과 쿼리 성능을 동시에 향상시키는 정교한 컴팩션 전략:
- 크기 기반 컴팩션: 작은 세그먼트들을 병합하여 I/O 오버헤드 감소
- 시간 기반 컴팩션: 특정 시간 범위의 데이터를 하나의 세그먼트로 통합
- 접근 패턴 기반: 함께 자주 액세스되는 데이터를 동일 세그먼트에 배치
- 압축률 최적화: 데이터 특성에 따른 최적 압축 알고리즘 선택
- 인덱스 재구성: 컴팩션 과정에서 인덱스 구조도 함께 최적화
병렬 인덱스 빌딩 시스템
대용량 데이터에 대한 효율적인 인덱스 구축:
- 데이터 파티셔닝: 대용량 데이터를 여러 파티션으로 분할하여 병렬 처리
- 워커 프로세스 관리: 사용 가능한 CPU 코어 수에 따른 최적 워커 수 결정
- 메모리 관리: 각 워커별 메모리 할당량 조절로 OOM 방지
- 진행 상황 추적: 장시간 실행되는 인덱스 빌드 작업의 진행률 모니터링
- 장애 복구: 일부 워커 장애 시 해당 파티션만 재처리하는 부분 복구
리소스 관리 및 최적화
시스템 리소스의 효율적 활용을 위한 고급 관리 기능:
- CPU 스케줄링: 컴팩션과 인덱스 빌딩 작업의 CPU 사용량 조절
- 메모리 풀링: 대용량 작업을 위한 전용 메모리 풀 운영
- 디스크 I/O 최적화: 순차 읽기/쓰기 최대화를 통한 디스크 성능 향상
- 네트워크 대역폭 관리: 오브젝트 스토리지와의 데이터 전송 최적화
- 작업 큐 관리: 우선순위 기반 작업 스케줄링
스토리지 시스템 심화 분석 #
1. Meta Storage (etcd) - 시스템 상태의 신뢰할 수 있는 저장소 #
etcd는 Milvus의 모든 메타데이터를 저장하는 분산 키-값 저장소로, 시스템의 두뇌 역할을 수행
저장되는 메타데이터의 종류와 구조
컬렉션 메타데이터:
- 스키마 정보: 필드 정의, 데이터 타입, 제약 조건
- 인덱스 설정: 인덱스 타입, 파라미터, 빌드 상태
- 파티션 정보: 파티션 키, 범위, 상태
- 접근 권한: 사용자별, 역할별 접근 권한 설정
세그먼트 메타데이터:
- 물리적 위치: 오브젝트 스토리지에서의 파일 경로
- 크기 정보: 행 수, 바이트 크기, 압축률
- 상태 정보: Growing, Sealed, Compacted 등의 생명주기 상태
- 인덱스 정보: 구축된 인덱스 타입과 파일 위치
토폴로지 메타데이터:
- 노드 상태: 각 워커 노드의 생존 상태, 리소스 사용량
- 세그먼트 할당: 어떤 세그먼트가 어느 노드에 할당되었는지
- 로드 밸런싱: 노드별 워크로드 분산 정보
일관성 보장 메커니즘
ACID 트랜잭션 지원:
- 원자성(Atomicity): 복수의 메타데이터 변경을 하나의 트랜잭션으로 처리
- 일관성(Consistency): 모든 노드에서 동일한 메타데이터 뷰 보장
- 격리성(Isolation): 동시 실행되는 트랜잭션 간 격리
- 지속성(Durability): 커밋된 변경사항의 영구 저장 보장
분산 합의 알고리즘:
- Raft 프로토콜을 통한 리더 선출과 로그 복제
- 과반수 합의를 통한 강한 일관성 보장
- 네트워크 분할 시에도 데이터 일관성 유지
서비스 등록 및 디스커버리
동적 서비스 등록:
- 새로운 노드가 클러스터에 참여할 때 자동 등록
- 노드별 메타데이터: IP 주소, 포트, 제공 서비스, 버전 정보
- TTL(Time To Live) 기반 자동 만료로 좀비 노드 방지
헬스 체크 시스템:
- 주기적 하트비트를 통한 노드 생존 확인
- 응답 시간 기반 노드 성능 평가
- 장애 감지 시 자동 서비스 목록에서 제외
2. Object Storage - 대용량 데이터의 안전한 보관소 #
Object Storage는 Milvus의 모든 영구 데이터를 저장하는 확장 가능한 저장소입니다.
지원하는 스토리지 백엔드
MinIO (기본 구현):
- S3 호환 API를 제공하는 오픈소스 오브젝트 스토리지
- 온프레미스 환경에서 완전한 제어권 제공
- 고성능 분산 스토리지 클러스터 구성 가능
- 암호화, 압축, 버전 관리 등 엔터프라이즈 기능 지원
Amazon S3:
- 업계 표준 클라우드 오브젝트 스토리지
- 11 9’s(99.999999999%)의 내구성 보장
- 다양한 스토리지 클래스: Standard, IA, Glacier 등
- 글로벌 CDN과 연계한 빠른 데이터 접근
Azure Blob Storage:
- Microsoft 클라우드의 오브젝트 스토리지 서비스
- Hot, Cool, Archive 티어를 통한 비용 최적화
- Azure 생태계와의 완벽한 통합
- 지역별 복제를 통한 재해 복구
데이터 조직 및 계층화 전략
계층적 디렉토리 구조:
/milvus-data/
├── collections/
│ ├── collection-001/
│ │ ├── partitions/
│ │ │ ├── partition-2024-01/
│ │ │ │ ├── segments/
│ │ │ │ │ ├── segment-12345/
│ │ │ │ │ │ ├── vectors.bin
│ │ │ │ │ │ ├── scalars.bin
│ │ │ │ │ │ ├── indexes/
│ │ │ │ │ │ │ ├── hnsw.idx
│ │ │ │ │ │ │ └── ivf.idx
│ │ │ │ │ │ └── metadata.json
스토리지 티어링:
- Hot Tier: 자주 액세스되는 최신 데이터, 고성능 SSD 스토리지
- Warm Tier: 가끔 액세스되는 데이터, 표준 스토리지
- Cold Tier: 장기 보관 데이터, 저비용 아카이브 스토리지
- 자동 티어링: 접근 패턴 분석을 통한 자동 데이터 이동
압축 및 최적화 전략
데이터 타입별 최적화:
- 벡터 데이터: ZSTD 압축으로 높은 압축률과 빠른 압축 해제
- 인덱스 파일: LZ4 압축으로 빠른 로딩 시간 보장
- 메타데이터: GZIP 압축으로 최대 압축률 달성
- 스칼라 데이터: 데이터 타입에 따른 특화된 압축 알고리즘
중복 제거 및 델타 압축:
- 블록 레벨 중복 제거로 스토리지 효율성 향상
- 델타 압축을 통한 증분 데이터 저장
- 참조 기반 압축으로 유사한 벡터 데이터 최적화
3. WAL Storage (Woodpecker) - 혁신적인 제로 디스크 WAL #
Woodpecker는 전통적인 디스크 기반 WAL의 한계를 극복한 혁신적인 클라우드 네이티브 WAL 솔루션입니다.
제로 디스크 설계의 혁신성
전통적 WAL의 한계:
- 로컬 디스크 의존성으로 인한 확장성 제약
- 디스크 장애 시 데이터 손실 위험
- 복잡한 디스크 관리 및 유지보수
- 노드별 디스크 용량 제한
Woodpecker의 해결책:
- 오브젝트 스토리지 직접 쓰기로 무제한 확장성
- 클라우드 스토리지의 높은 내구성 활용
- 디스크 관리 복잡성 완전 제거
- 탄력적 스토리지 용량 활용
성능 최적화 메커니즘
배치 처리:
- 여러 로그 엔트리를 배치로 묶어 네트워크 오버헤드 감소
- 동적 배치 크기 조절로 지연시간과 처리량 균형
- 압축을 통한 네트워크 대역폭 효율성 향상
비동기 처리:
- 논블로킹 I/O를 통한 높은 동시성 지원
- 백그라운드 플러시로 애플리케이션 성능 영향 최소화
- 파이프라인 처리를 통한 지연시간 숨김
일관성 및 내구성 보장
순서 보장:
- 글로벌 시퀀스 번호를 통한 엄격한 순서 보장
- 파티션별 순차 쓰기로 인과 관계 유지
- 체크포인트를 통한 일관된 복구 지점 제공
장애 복구:
- 자동 재시도 메커니즘으로 일시적 장애 대응
- 체크포인트 기반 빠른 복구
- 부분 실패 시 증분 복구 지원
데이터 플로우 및 처리 과정 #
검색 요청 상세 플로우 #
검색 요청은 Milvus에서 가장 복잡하고 중요한 처리 과정 중 하나입니다. 다음은 단일 검색 요청이 시스템을 통과하는 전체 여정입니다.
1단계: 클라이언트 요청 접수
- 클라이언트가 SDK 또는 RESTful API를 통해 검색 요청 전송
- 요청에는 쿼리 벡터, 검색 파라미터(top_k, nprobe 등), 필터 조건 포함
- 로드 밸런서가 사용 가능한 Proxy 인스턴스 중 하나를 선택
2단계: Proxy에서의 요청 처리
- 요청 검증: API 스키마, 파라미터 유효성, 권한 확인
- 컬렉션 메타데이터 조회: 스키마 정보, 파티션 구조, 인덱스 정보
- 라우팅 캐시 확인: 세그먼트별 노드 할당 정보 조회
- 캐시 미스 시 Coordinator에서 최신 토폴로지 정보 획득
3단계: 쿼리 계획 수립
- 검색 대상 파티션 결정 (파티션 키 기반 필터링)
- 관련 세그먼트 식별 및 담당 노드 매핑
- 병렬 처리 계획 수립: Streaming Node와 Query Node 간 작업 분배
- 리소스 할당: 각 노드별 처리 용량 고려한 워크로드 분산
4단계: 분산 실행
- Streaming Node에서 성장 중인 데이터 검색
- Query Node에서 히스토리컬 데이터 병렬 검색
- 각 노드는 할당된 세그먼트에 대해 독립적으로 Top-K 검색 수행
- 스칼라 필터가 있는 경우 하이브리드 쿼리 실행
5단계: 결과 집계 및 반환
- 각 노드에서 반환된 부분 결과를 Proxy에서 수집
- 글로벌 Top-K 병합: 유사도 점수 기준 정렬
- 중복 제거 및 최종 결과 선택
- 메타데이터 보강 후 클라이언트에 응답 반환
데이터 삽입 상세 플로우 #
데이터 삽입은 실시간 처리와 장기 저장을 모두 고려해야 하는 복잡한 프로세스입니다.
1단계: 삽입 요청 접수 및 검증
- 클라이언트에서 벡터 데이터와 스칼라 필드를 포함한 삽입 요청 전송
- Proxy에서 데이터 스키마 검증: 필드 타입, 벡터 차원, 필수 필드 확인
- 중복 키 검사 및 데이터 무결성 검증
- 배치 크기 및 처리량 제한 확인
2단계: 라우팅 및 샤드 할당
- 파티션 키 기반 대상 파티션 결정
- 해시 기반 샤드 할당으로 데이터 분산
- 해당 샤드를 담당하는 Streaming Node 식별
- 로드 밸런싱을 통한 핫스팟 방지
3단계: Streaming Node에서의 실시간 처리
- WAL Storage에 삽입 작업 로깅으로 내구성 보장
- 인메모리 버퍼에 데이터 저장 및 임시 인덱스 구축
- 실시간 쿼리를 위한 검색 가능 상태로 전환
- 트랜잭션 커밋 및 클라이언트에 성공 응답
4단계: 배치 처리 및 최적화
- 세그먼트 크기 임계값 도달 시 봉인(Sealing) 프로세스 시작
- Data Node에서 압축 및 인덱스 빌딩 작업 수행
- Object Storage에 최적화된 형태로 영구 저장
- 메타데이터 업데이트 및 Query Node에 로딩 지시
5단계: 인덱스 구축 및 서비스 준비
- 백그라운드에서 고성능 인덱스(HNSW, IVF 등) 구축
- 인덱스 검증 및 품질 확인
- Query Node에 새로운 세그먼트 로딩
- 서빙 토폴로지 업데이트로 검색 서비스 준비 완료
성능 최적화 전략 #
벡터 인덱스 최적화 #
인덱스 타입별 최적화 전략
HNSW 최적화:
- M 파라미터 조정: 연결성과 메모리 사용량의 균형점 찾기
- efConstruction 최적화: 구축 시간과 인덱스 품질의 트레이드오프
- 계층별 최적화: 상위 계층은 연결성 중심, 하위 계층은 정확도 중심
- 동적 프루닝: 불필요한 연결 제거로 메모리 효율성 향상
IVF 계열 최적화:
- 클러스터 수 최적화: 데이터 분포와 쿼리 패턴에 맞는 최적 클러스터 수 결정
- 양자화 파라미터 조정: PQ의 서브벡터 수와 센트로이드 수 최적화
- 불균형 클러스터 처리: 클러스터 크기 불균형 시 재클러스터링
- 적응적 nprobe: 쿼리별 최적 탐색 클러스터 수 동적 결정
메모리 관리 최적화 #
계층적 캐싱 전략
L1 캐시 (CPU 캐시):
- 벡터 연산 최적화를 위한 SIMD 명령어 활용
- 캐시 라인 정렬을 통한 메모리 접근 패턴 최적화
- 프리페칭을 통한 캐시 미스 최소화
L2 캐시 (메모리):
- 자주 접근되는 인덱스 구조의 메모리 상주
- LRU 기반 세그먼트 캐싱으로 메모리 효율성 극대화
- 메모리 풀링을 통한 할당/해제 오버헤드 감소
L3 캐시 (SSD):
- NVMe SSD를 활용한 고속 로컬 캐시
- 압축된 인덱스의 SSD 캐싱으로 네트워크 I/O 감소
- 예측적 프리로딩으로 캐시 히트율 향상
네트워크 최적화 #
데이터 전송 최적화:
- 압축을 통한 네트워크 대역폭 효율성 향상
- 배치 처리로 네트워크 라운드트립 최소화
- 연결 풀링으로 연결 설정 오버헤드 감소