스냅샷으로 Qdrant 백업·복원하기
스냅샷으로 Qdrant 백업·복원하기 (tutorials-operations-create-snapshot)
| 소요 시간: 20분 | 난이도: 입문(Beginner) |
|---|
Qdrant에서 데이터 저장의 기본 단위는 컬렉션(collection)이에요. 컬렉션에는 벡터와 벡터의 ID, 그리고 페이로드가 담겨 있죠. 그런데 검색을 빠르게 유지하려면 데이터 위에 추가적인 자료 구조를 더 구축해야 해요. 특히 컬렉션이 커질수록 이 구조를 만드는 데 꽤 오래 걸릴 수 있어요. 그래서 Qdrant 컬렉션을 내보내고 가져올 때는 스냅샷(snapshot)을 쓰는 게 가장 좋은 방법이에요. 스냅샷에는 컬렉션 전체를 효율적으로 복원하는 데 필요한 모든 요소가 들어 있거든요.
이 튜토리얼에서는 컬렉션의 스냅샷을 만들고, 그 스냅샷을 복원하는 방법을 보여드릴게요. 분산 환경에서 스냅샷을 다루는 건 조금 더 복잡할 수 있으니, 여기서는 3-노드 Qdrant 클러스터를 사용할 거예요. 다만 같은 방식이 단일 노드 구성에도 그대로 적용돼요.
이 페이지에 나온 기법을 사용하면 클러스터를 마이그레이션할 수도 있어요. 아래 튜토리얼을 따라 스냅샷을 만들고 다운로드한 다음, 스냅샷에서 복원하기 절차로 새 클러스터에 데이터를 복원하면 됩니다.
사전 준비 (Prerequisites)
이미 실행 중인 Qdrant 인스턴스나 클러스터가 있다고 가정할게요. 아직 없다면 설치 가이드를 따라 로컬 Qdrant 인스턴스를 준비하거나, Qdrant Cloud에서 몇 번의 클릭으로 클러스터를 만들 수 있어요.
클러스터가 실행되면 필요한 의존성을 설치합니다:
pip install qdrant-client datasets
Qdrant에 연결 설정하기
Python SDK와 raw HTTP 호출을 함께 사용해서 Qdrant와 통신할 거예요. 3-노드 클러스터를 쓰기 때문에 모든 노드의 URL을 알아야 해요. 단순하게 하기 위해 API 키와 함께 모든 URL을 상수로 저장해 두고 나중에 참조할게요:
QDRANT_MAIN_URL = "https://my-cluster.com:6333"
QDRANT_NODES = (
"https://node-0.my-cluster.com:6333",
"https://node-1.my-cluster.com:6333",
"https://node-2.my-cluster.com:6333",
)
QDRANT_API_KEY = "my-api-key"
이제 클라이언트 인스턴스를 만들 수 있어요:
from qdrant_client import QdrantClient
client = QdrantClient(QDRANT_MAIN_URL, api_key=QDRANT_API_KEY)
먼저 미리 계산된 데이터셋으로 컬렉션을 하나 만들 거예요. 이미 컬렉션이 있다면 이 단계를 건너뛰고 바로 스냅샷 만들기부터 시작해도 돼요.
(선택) 컬렉션 생성 및 데이터 임포트
데이터셋 불러오기
미리 계산된 임베딩이 들어 있는 데이터셋을 사용할 건데, Hugging Face Hub에서 받을 수 있어요. 데이터셋 이름은 Qdrant/arxiv-titles-instructorxl-embeddings이고, InstructorXL 모델로 만들었어요. arXiv 데이터셋의 논문 제목 225만 개에 대한 임베딩이 담겨 있어요.
데이터셋을 불러오는 건 아주 간단해요:
from datasets import load_dataset
dataset = load_dataset(
"Qdrant/arxiv-titles-instructorxl-embeddings",
split="train",
streaming=True,
)
스트리밍 모드를 사용했기 때문에 데이터셋이 메모리에 통째로 로드되지는 않아요. 대신 반복하면서 id와 벡터 임베딩을 하나씩 꺼낼 수 있죠:
for payload in dataset:
id_ = payload.pop("id")
vector = payload.pop("vector")
print(id_, vector, payload)
개별 페이로드 하나는 이렇게 생겼어요:
{
'title': 'Dynamics of partially localized brane systems',
'DOI': '1109.1415'
}
컬렉션 생성하기
가장 먼저 컬렉션을 만들어야 해요. 컬렉션 구성을 자세히 만지작거리진 않을 거지만, 지금 만들어 두는 게 좋아요. 컬렉션 구성도 스냅샷의 일부로 함께 저장되거든요.
from qdrant_client import models
if not client.collection_exists("test_collection"):
client.create_collection(
collection_name="test_collection",
vectors_config=models.VectorParams(
size=768, # InstructorXL 모델이 만드는 임베딩 벡터의 크기
distance=models.Distance.COSINE,
),
)
데이터셋 업로드하기
임베딩을 계산하는 건 보통 벡터 검색 파이프라인의 병목 지점이 되곤 해요. 하지만 우리는 이미 임베딩이 준비돼 있어서 다행이에요. 이 튜토리얼의 목적은 스냅샷을 만드는 방법을 보여주는 거니, 데이터셋의 아주 일부만 업로드할 거예요.
ids, vectors, payloads = [], [], []
for payload in dataset:
id_ = payload.pop("id")
vector = payload.pop("vector")
ids.append(id_)
vectors.append(vector)
payloads.append(payload)
# 벡터 1000개만 업로드할 거예요
if len(ids) == 1000:
break
client.upsert(
collection_name="test_collection",
points=models.Batch(
ids=ids,
vectors=vectors,
payloads=payloads,
),
)
이제 컬렉션이 검색에 사용할 준비가 됐어요. 이 컬렉션의 스냅샷을 만들어 볼게요.
이미 컬렉션이 있다면 앞 단계를 건너뛰고 바로 스냅샷 만들기부터 시작해도 돼요.
스냅샷 생성 및 다운로드
Qdrant는 스냅샷 생성을 요청하는 HTTP 엔드포인트를 제공하는데, Python SDK로도 호출할 수 있어요. 우리 구성은 3개 노드로 이루어져 있으니 각 노드별로 엔드포인트를 호출해서 각 노드에 스냅샷을 만들어야 해요. Python SDK를 쓴다면 노드마다 별도의 클라이언트 인스턴스를 만들어야 한다는 뜻이에요.
snapshot_urls = []
for node_url in QDRANT_NODES:
node_client = QdrantClient(node_url, api_key=QDRANT_API_KEY)
snapshot_info = node_client.create_snapshot(collection_name="test_collection")
snapshot_url = f"{node_url}/collections/test_collection/snapshots/{snapshot_info.name}"
snapshot_urls.append(snapshot_url)
// for `https://node-0.my-cluster.com:6333`
POST /collections/test_collection/snapshots
// for `https://node-1.my-cluster.com:6333`
POST /collections/test_collection/snapshots
// for `https://node-2.my-cluster.com:6333`
POST /collections/test_collection/snapshots
응답(Response):
{
"result": {
"name": "test_collection-559032209313046-2024-01-03-13-20-11.snapshot",
"creation_time": "2024-01-03T13:20:11",
"size": 18956800
},
"status": "ok",
"time": 0.307644965
}
스냅샷 URL을 얻었으니 이제 다운로드할 수 있어요. 요청 헤더에 API 키를 반드시 포함해야 합니다. 스냅샷 다운로드는 HTTP API로만 가능하기 때문에 requests 라이브러리를 사용할 거예요.
import requests
import os
# 스냅샷을 저장할 디렉토리 만들기
os.makedirs("snapshots", exist_ok=True)
local_snapshot_paths = []
for snapshot_url in snapshot_urls:
snapshot_name = os.path.basename(snapshot_url)
local_snapshot_path = os.path.join("snapshots", snapshot_name)
response = requests.get(
snapshot_url,
headers={"api-key": QDRANT_API_KEY},
)
with open(local_snapshot_path, "wb") as f:
response.raise_for_status()
f.write(response.content)
local_snapshot_paths.append(local_snapshot_path)
wget 명령을 써도 됩니다:
wget https://node-0.my-cluster.com:6333/collections/test_collection/snapshots/test_collection-559032209313046-2024-01-03-13-20-11.snapshot \
--header="api-key: ${QDRANT_API_KEY}" \
-O node-0-snapshot.snapshot
wget https://node-1.my-cluster.com:6333/collections/test_collection/snapshots/test_collection-559032209313047-2024-01-03-13-20-12.snapshot \
--header="api-key: ${QDRANT_API_KEY}" \
-O node-1-snapshot.snapshot
wget https://node-2.my-cluster.com:6333/collections/test_collection/snapshots/test_collection-559032209313048-2024-01-03-13-20-13.snapshot \
--header="api-key: ${QDRANT_API_KEY}" \
-O node-2-snapshot.snapshot
이제 스냅샷이 로컬에 저장됐어요. 이 스냅샷으로 다른 Qdrant 인스턴스에 컬렉션을 복원하거나, 백업으로 삼을 수 있어요. 이번에는 같은 클러스터에 같은 데이터로 새 컬렉션을 만들어 볼게요.
스냅샷에서 복원하기
새로 만든 스냅샷을 복원할 준비가 됐어요. 보통은 컬렉션을 다른 Qdrant 인스턴스로 옮길 때 쓰지만, 여기서는 같은 클러스터에 새 컬렉션을 만드는 데 사용할 거예요. 이름만 다르게 해서 test_collection_import라고 할게요. 컬렉션은 자동으로 생성되기 때문에 미리 만들 필요가 없어요.
컬렉션 복원도 노드별로 따로 수행해야 해요. 하지만 Python SDK는 아직 이 기능을 지원하지 않아서, requests 라이브러리로 각 노드에 HTTP 요청을 보낼 거예요.
for node_url, snapshot_path in zip(QDRANT_NODES, local_snapshot_paths):
snapshot_name = os.path.basename(snapshot_path)
requests.post(
f"{node_url}/collections/test_collection_import/snapshots/upload?priority=snapshot",
headers={
"api-key": QDRANT_API_KEY,
},
files={
"snapshot": (snapshot_name, open(snapshot_path, "rb")),
},
)
curl 명령을 써도 됩니다:
curl -X POST 'https://node-0.my-cluster.com:6333/collections/test_collection_import/snapshots/upload?priority=snapshot' \
-H 'api-key: ${QDRANT_API_KEY}' \
-H 'Content-Type:multipart/form-data' \
-F '[email protected]'
curl -X POST 'https://node-1.my-cluster.com:6333/collections/test_collection_import/snapshots/upload?priority=snapshot' \
-H 'api-key: ${QDRANT_API_KEY}' \
-H 'Content-Type:multipart/form-data' \
-F '[email protected]'
curl -X POST 'https://node-2.my-cluster.com:6333/collections/test_collection_import/snapshots/upload?priority=snapshot' \
-H 'api-key: ${QDRANT_API_KEY}' \
-H 'Content-Type:multipart/form-data' \
-F '[email protected]'
중요: priority=snapshot을 선택한 이유는 노드에 저장된 데이터보다 스냅샷을 우선하도록 하기 위해서예요. priority에 대한 더 자세한 내용은 문서에서 확인할 수 있어요.
스냅샷 외에도 Qdrant는 Qdrant Migration Tool을 제공하는데, 여기서 지원하는 기능은 다음과 같아요:
- Qdrant Cloud 인스턴스 간 마이그레이션
- 다른 제공업체의 벡터를 Qdrant로 마이그레이션
- Qdrant OSS에서 Qdrant Cloud로 마이그레이션
Qdrant Migration Tool을 효과적으로 사용하는 방법은 마이그레이션 가이드에서 배울 수 있어요.