Qdrant 심화: 세그먼트, 페이로드 인덱스, 클러스터 운영
Qdrant를 선택하는 이유와 그 대가
Qdrant는 Rust로 작성된 목적 특화 벡터 검색 엔진이다. "메타데이터 필터링이 빈번하고, 수천만~수억 벡터를 단일 서버에서 운영해야 한다"는 요건에 가장 잘 맞는다. gRPC·REST를 모두 지원하고, on-disk 인덱스로 RAM 비용을 줄일 수 있으며, 클러스터 모드로 수평 확장도 가능하다.
대신 PostgreSQL처럼 SQL JOIN이 없고, 클러스터 모드는 구성이 복잡하며, 세그먼트 구조와 옵티마이저 동작을 이해하지 않으면 예상치 못한 성능 저하가 발생한다.
이 챕터는 Qdrant의 내부 구조부터 클러스터 운영까지 DBA·플랫폼 엔지니어가 알아야 할 핵심을 다룬다.
세그먼트 아키텍처
Qdrant의 저장 단위는 세그먼트(Segment)다. 하나의 컬렉션은 여러 세그먼트로 나뉘며, 각 세그먼트는 독립적인 저장소와 인덱스를 가진다.
세그먼트 구성요소
스토리지 모드
| 모드 | 저장 위치 | 특성 | 적합한 경우 |
|---|---|---|---|
in-memory | RAM | 최고 속도. 영속성은 WAL+스냅샷 | 소~중규모, 지연 민감 |
memmap | 디스크 (OS 페이지 캐시 활용) | RAM 부족 시 디스크에서 읽음. 속도는 캐시 히트율에 따라 가변 | 벡터가 RAM을 초과하는 규모 |
on_disk (HNSW 파라미터) | 디스크 | HNSW 그래프 자체를 디스크에 저장. RAM = 인덱스 크기의 약 10% | 수억~수십억 벡터, 극단적 메모리 절감 |
옵티마이저: 세그먼트 라이프사이클 관리
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
}
}| 파라미터 | 기본값 | 역할 |
|---|---|---|
m | 16 | 노드당 최대 연결. 높을수록 recall↑, 메모리↑ |
ef_construct | 100 | 빌드 시 후보 크기. 높을수록 품질↑, 빌드 시간↑ |
full_scan_threshold | 10000 | 세그먼트 크기가 이 값 미만이면 brute-force 사용 |
on_disk | false | true 시 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 | 카테고리, 상태, 태그 | 정확 일치, 소~중 카디널리티 |
integer | user_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 범위가 속도-정확도 균형의 실용적 기준이다.
클러스터 모드: 샤드, 복제본, Raft
단일 노드로 수억 벡터 이상을 처리하거나 고가용성이 필요할 때 클러스터 모드를 사용한다.
아키텍처 개요
샤딩과 복제
| 개념 | 역할 | 운영 기준 |
|---|---|---|
| 샤드 | 컬렉션 데이터를 분할 | 시작점: 노드당 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_count | deleted_threshold(기본 0.2) 근접 시 vacuum 예상 |
흔한 운영 실수
| 실수 | 결과 | 대응 |
|---|---|---|
| 페이로드 인덱스를 데이터 삽입 후 생성 | 필터링 시 full scan 폴백 | 인덱스 삭제 후 재생성, HNSW 재빌드 필요 |
낮은 indexing_threshold + 대량 삽입 | 잦은 HNSW 빌드로 CPU/메모리 과부하 | 삽입 중 threshold↑, 완료 후 최적화 |
| 복제 팩터 1로 프로덕션 배포 | 단일 노드 장애 시 데이터 불가 | 복제 팩터 ≥ 2 |
| on_disk 없이 수억 벡터 로드 | 서버 OOM | on_disk: true + memmap_threshold 조정 |
References
- Qdrant Documentation: Storage Concepts
- Qdrant Documentation: Indexing
- Qdrant Optimizer Architecture
- Qdrant Distributed Deployment
- Qdrant Capacity Planning Guide
- Binary Quantization — Vector Search 40x Faster (Qdrant Blog)
- Qdrant Quantization Documentation
- Qdrant Vector Search Resource Optimization
- Building a Distributed Qdrant Cluster (Pramod Wickramatilake, Medium)
- Qdrant Monitoring: Complete Guide to Metrics, Alerts, and Best Practices (CubeAPM)