LLM WikiAccess-protected knowledge portal
← 스터디 홈
3편 · 약 30분

Qdrant 심화: 세그먼트, 페이로드 인덱스, 클러스터 운영

Qdrant를 선택하는 이유와 그 대가

Qdrant는 Rust로 작성된 목적 특화 벡터 검색 엔진이다. "메타데이터 필터링이 빈번하고, 수천만~수억 벡터를 단일 서버에서 운영해야 한다"는 요건에 가장 잘 맞는다. gRPC·REST를 모두 지원하고, on-disk 인덱스로 RAM 비용을 줄일 수 있으며, 클러스터 모드로 수평 확장도 가능하다.

대신 PostgreSQL처럼 SQL JOIN이 없고, 클러스터 모드는 구성이 복잡하며, 세그먼트 구조와 옵티마이저 동작을 이해하지 않으면 예상치 못한 성능 저하가 발생한다.

이 챕터는 Qdrant의 내부 구조부터 클러스터 운영까지 DBA·플랫폼 엔지니어가 알아야 할 핵심을 다룬다.


세그먼트 아키텍처

Qdrant의 저장 단위는 세그먼트(Segment)다. 하나의 컬렉션은 여러 세그먼트로 나뉘며, 각 세그먼트는 독립적인 저장소와 인덱스를 가진다.

세그먼트 구성요소

벡터 스토리지 원본 float32 벡터 저장 in-memory / memmap / on-disk 양자화 벡터 별도 저장 가능
페이로드 스토리지 포인트별 JSON 메타데이터 in-memory 또는 on-disk 필터 조건의 원본 데이터
벡터 인덱스 HNSW 그래프 indexing_threshold 달성 후 생성 비생성 상태: brute-force 탐색
페이로드 인덱스 필드별 역 인덱스 keyword/integer/float/geo/text/datetime 명시적 생성 필요
ID 매퍼 외부 ID ↔ 내부 ID 매핑 삭제된 포인트 추적 버전 관리
Appendable vs Non-appendable: 새 포인트를 받을 수 있는 세그먼트가 appendable. 최적화 중인 세그먼트는 non-appendable(read/delete only). 컬렉션에는 항상 최소 1개의 appendable 세그먼트가 존재.
Qdrant 세그먼트 내부 구조

스토리지 모드

모드저장 위치특성적합한 경우
in-memoryRAM최고 속도. 영속성은 WAL+스냅샷소~중규모, 지연 민감
memmap디스크 (OS 페이지 캐시 활용)RAM 부족 시 디스크에서 읽음. 속도는 캐시 히트율에 따라 가변벡터가 RAM을 초과하는 규모
on_disk (HNSW 파라미터)디스크HNSW 그래프 자체를 디스크에 저장. RAM = 인덱스 크기의 약 10%수억~수십억 벡터, 극단적 메모리 절감

옵티마이저: 세그먼트 라이프사이클 관리

Qdrant는 세 가지 백그라운드 옵티마이저가 세그먼트를 지속적으로 재구성한다.

Qdrant 세그먼트 라이프사이클 포인트 삽입/수정 WAL 기록 후 반영 소형 세그먼트들 appendable, 인덱스 없음 (brute-force 탐색) 🔀 Merge Optimizer 소형 세그먼트 병합 세그먼트 수 ≤ max_segment_count 유지하도록 지속 동작 대형 세그먼트 indexing_threshold 초과 시 Indexing Optimizer 트리거 📐 Indexing Optimizer HNSW 인덱스 빌드 memmap 변환 (설정 시) non-appendable로 전환 🧹 Vacuum Optimizer 삭제된 포인트 물리 제거 세그먼트 재빌드 deleted_threshold 초과 시 동작 인덱싱된 세그먼트 HNSW 인덱스 완성 non-appendable ANN 검색에 사용 주요 옵티마이저 파라미터 indexing_threshold_kb: 20,000 KB (~20 MB, 기본) — 세그먼트 크기가 이 값을 초과하면 HNSW 빌드 시작 memmap_threshold_kb: 설정값 초과 시 memmap 변환. RAM 제약 시 indexing_threshold_kb보다 낮게 설정 deleted_threshold: 0.2 (기본) — 삭제 비율이 이 값 초과 시 vacuum 동작. max_optimization_threads로 워커 수 제어
Qdrant 세그먼트 라이프사이클과 옵티마이저

중요: 대량 삽입 시 indexing_threshold_kb를 높이거나 0으로 설정하면 HNSW 빌드를 지연시켜 삽입 속도를 개선할 수 있다. 삽입 완료 후 기본값으로 복원하면 옵티마이저가 일괄 빌드를 수행한다.


HNSW 구성과 필터링

HNSW 파라미터

컬렉션 생성 시 HNSW를 설정한다.

PUT /collections/my_collection
{
  "vectors": {
    "size": 768,
    "distance": "Cosine"
  },
  "hnsw_config": {
    "m": 16,
    "ef_construct": 100,
    "full_scan_threshold": 10000,
    "on_disk": false
  }
}
파라미터기본값역할
m16노드당 최대 연결. 높을수록 recall↑, 메모리↑
ef_construct100빌드 시 후보 크기. 높을수록 품질↑, 빌드 시간↑
full_scan_threshold10000세그먼트 크기가 이 값 미만이면 brute-force 사용
on_diskfalsetrue 시 HNSW 그래프를 디스크에 저장

쿼리 시 hnsw_ef를 조정한다.

POST /collections/my_collection/points/search
{
  "vector": [...],
  "limit": 10,
  "params": {
    "hnsw_ef": 128
  }
}

필터링 HNSW: 페이로드 인덱스 선행 생성의 중요성

Qdrant HNSW는 필터 인식 그래프(filter-aware graph)를 빌드한다. 페이로드 인덱스가 HNSW 빌드 전에 생성되어 있어야 그래프 엣지가 필터 조건을 감안한 방향으로 연결된다.

페이로드 인덱스 먼저 → HNSW 빌드 → 필터가 효율적
페이로드 인덱스 나중에 → HNSW 이미 빌드됨 → 필터 시 full scan 폴백 가능성

권장 순서:

// 1. 페이로드 인덱스 먼저 생성
PUT /collections/my_collection/index
{
  "field_name": "user_id",
  "field_schema": "integer"
}

// 2. 그 다음 데이터 삽입
// 3. 자동으로 HNSW 빌드 (indexing_threshold 도달 시)

페이로드 인덱스 타입

타입사용 예특징
keyword카테고리, 상태, 태그정확 일치, 소~중 카디널리티
integeruser_id, timestamp_epoch범위 쿼리 지원
float가격, 점수범위 쿼리 지원
geo위도/경도지오 반경/바운딩박스 필터
text자유 텍스트전문 검색 인덱스 (full-text)
datetime날짜/시간ISO 8601 범위 쿼리

양자화: 메모리 절감과 속도 향상

Qdrant는 세 가지 양자화를 지원한다. 모두 원본 벡터를 유지하면서 압축 사본을 추가로 저장한다.

스칼라 양자화 (Scalar Quantization)

"quantization_config": {
  "scalar": {
    "type": "int8",
    "quantile": 0.99,
    "always_ram": true
  }
}
  • float32 → int8: 4× 메모리 절감
  • SIMD 최적화로 최대 2× 검색 속도 향상
  • recall 손실 최소 (< 1~2%p)
  • 대부분의 프로덕션에서 첫 번째 양자화 선택지

이진 양자화 (Binary Quantization)

"quantization_config": {
  "binary": {
    "always_ram": true
  }
}
  • float32 → 1비트: 32× 이상 메모리 절감
  • Hamming 거리로 후보 추출 후 원본 벡터로 재순위(rescore)
  • 재순위가 필수이므로 원본 벡터는 메모리에 유지 권장
  • OpenAI text-embedding-3-*, Cohere V3 등 최신 모델에서 recall 유지가 좋음

프로덕트 양자화 (Product Quantization)

"quantization_config": {
  "product": {
    "compression": "x16",
    "always_ram": false
  }
}
  • 벡터를 서브벡터로 분할 후 코드북으로 압축: 4×~64× 메모리 절감
  • 스칼라 양자화보다 recall 손실이 큼
  • compression: x4, x8, x16, x32, x64

재순위(Rescore)와 오버샘플링(Oversampling)

POST /collections/my_collection/points/search
{
  "vector": [...],
  "limit": 10,
  "params": {
    "quantization": {
      "rescore": true,
      "oversampling": 2.0
    }
  }
}

oversampling은 양자화 인덱스로 limit × oversampling개 후보를 뽑은 뒤 원본 벡터로 재순위하는 비율이다. 1.5~3.0 범위가 속도-정확도 균형의 실용적 기준이다.

스칼라 양자화 (SQ) 압축: Recall 손실: 최소 속도 향상: 최대 2× Rescore 기본: 비활성화 → 일반 프로덕션 권장
이진 양자화 (BQ) 압축: 32×+ Recall 손실: 높음 (rescore 없이) 속도: 매우 빠름 (Hamming) Rescore 기본: 활성화 → 최신 LLM 임베딩 + 재순위
프로덕트 양자화 (PQ) 압축: 4×~64× Recall 손실: 중~높음 속도: 중간 Rescore 기본: 활성화 → 극단적 메모리 절감 필요 시
양자화 방법별 트레이드오프

클러스터 모드: 샤드, 복제본, Raft

단일 노드로 수억 벡터 이상을 처리하거나 고가용성이 필요할 때 클러스터 모드를 사용한다.

아키텍처 개요

Qdrant 클러스터: 3 노드, 2 샤드, 복제 팩터 2 클라이언트 Node 1 (Raft Leader) Shard 0 Primary Shard 1 Replica Raft Consensus Agent 토폴로지 관리, 리더 선출 Node 2 Shard 0 Replica Shard 1 Primary Raft Follower 합의 참여, 메타데이터 동기화 Node 3 추가 Replica (옵션) 추가 Replica (옵션) Raft Follower 합의 참여, 쿼리 처리 Raft: 클러스터 토폴로지/컬렉션 구조 합의 | 데이터 복제: Primary Shard → Replica Shard (독립 동작)
Qdrant 클러스터 아키텍처

샤딩과 복제

개념역할운영 기준
샤드컬렉션 데이터를 분할시작점: 노드당 2~4개. 공식 권장은 12개부터
복제 팩터각 샤드의 복사본 수최소 2(HA), 권장 3
Raft클러스터 토폴로지 합의메타데이터 변경(컬렉션 생성/삭제/토폴로지)만 담당

노드 장애 시 복구 흐름

1. 노드 장애 감지
   → 해당 노드의 Shard Replica: Dead 상태로 표시

2. 나머지 노드의 Replica가 Primary로 승격
   → 읽기/쓰기는 계속 서비스 (복제 팩터 ≥ 2 필요)

3. 장애 노드 재시작
   → Partial 상태 진입 (누락 업데이트 동기화 시작)

4. 동기화 완료
   → Active 상태로 전환, 정상 참여

주의: 단일 노드(복제 팩터 1)에서 노드 장애 시 해당 샤드의 데이터는 노드 복구 전까지 사용 불가능하다.


운영 체크리스트

컬렉션 생성 순서 (권장)

1. 페이로드 인덱스 생성 (HNSW 빌드 전 필수)
2. 데이터 삽입 (배치로 업로드)
3. HNSW 자동 빌드 대기 (indexing_threshold 도달 후)
   또는 optimize 강제 호출
4. 양자화 설정 (필요 시)
5. 쿼리 파라미터(hnsw_ef) 튜닝 및 recall 측정

메모리 용량 계획

벡터 RAM 추정 (in-memory):
  N × D × 4 bytes (float32)
  예: 50M × 1536d = 288GB

HNSW 인덱스 추가 RAM:
  N × M × 8 bytes (대략)
  예: 50M × 16 × 8 = 6.4GB

총 RAM = 벡터 + HNSW + 페이로드 + 운영체제

on_disk = true 사용 시:
  RAM ≈ 벡터 크기의 10% + HNSW 엣지 일부 (캐시)

주요 모니터링 지표

지표경로임계값
세그먼트 수/collections/{name} 응답 내 segments_count비정상적으로 많으면 merge optimizer 점검
인덱싱 안된 벡터 수indexed_vectors_count vs vectors_count큰 차이 지속 시 indexing_threshold 점검
Raft term 증가율/metrics (Prometheus) raft_term급증 시 네트워크/노드 불안정
삭제 비율deleted_vectors_count / vectors_countdeleted_threshold(기본 0.2) 근접 시 vacuum 예상

흔한 운영 실수

실수결과대응
페이로드 인덱스를 데이터 삽입 후 생성필터링 시 full scan 폴백인덱스 삭제 후 재생성, HNSW 재빌드 필요
낮은 indexing_threshold + 대량 삽입잦은 HNSW 빌드로 CPU/메모리 과부하삽입 중 threshold↑, 완료 후 최적화
복제 팩터 1로 프로덕션 배포단일 노드 장애 시 데이터 불가복제 팩터 ≥ 2
on_disk 없이 수억 벡터 로드서버 OOMon_disk: true + memmap_threshold 조정

References