Quick start: Dựng Milvus Standalone và Attu GUI trong 5 phút
Khi kho dữ liệu RAG vượt mốc 5-10 triệu vector, các thư viện in-memory như FAISS hay Chroma bắt đầu ngốn RAM và khó mở rộng theo cụm. Milvus giải quyết triệt để vấn đề này nhờ kiến trúc phân tán. Bạn có thể dựng nhanh toàn bộ môi trường bằng Docker Compose.
Tạo file docker-compose.yml gom đủ 4 thành phần: Milvus server, MinIO (lưu file index), Etcd (lưu metadata) và Attu (giao diện web):
version: '3.5'
services:
etcd:
container_name: milvus-etcd
image: quay.io/coreos/etcd:v3.5.5
environment:
- ETCD_AUTO_COMPACTION_MODE=revision
- ETCD_AUTO_COMPACTION_RETENTION=1000
- ETCD_QUOTA_BACKEND_BYTES=4294967296
- ETCD_SNAPSHOT_COUNT=50000
volumes:
- ./volumes/etcd:/etcd
command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls=http://0.0.0.0:2379 --data-dir=/etcd
minio:
container_name: milvus-minio
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
environment:
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
volumes:
- ./volumes/minio:/minio_data
command: minio server /minio_data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
standalone:
container_name: milvus-standalone
image: milvusdb/milvus:v2.3.4
command: ["milvus", "run", "standalone"]
environment:
ETCD_ENDPOINTS: etcd:2379
MINIO_ADDRESS: minio:9000
volumes:
- ./volumes/milvus:/var/lib/milvus
ports:
- "19530:19530"
- "9091:9091"
depends_on:
- "etcd"
- "minio"
attu:
container_name: milvus-attu
image: zilliz/attu:v2.3.4
ports:
- "8000:3000"
environment:
MILVUS_URL: milvus-standalone:19530
depends_on:
- "standalone"
Khởi động toàn bộ stack bằng một lệnh duy nhất:
docker compose up -d
Đợi khoảng 30 giây cho các service ổn định, sau đó mở trình duyệt tại http://localhost:8000. Điền host milvus-standalone:19530 để đăng nhập dashboard Attu.
Kiến trúc Milvus và vai trò của Attu
1. Cơ chế vận hành của Milvus
Milvus tách biệt hoàn toàn giữa tầng tính toán (Compute) và tầng lưu trữ (Storage). Nhờ thiết kế này, bạn có thể scale-out Query Node độc lập khi traffic tìm kiếm tăng vọt:
- Etcd: Lưu metadata của collection, schema, thông tin partition và trạng thái cluster.
- MinIO / S3: Lưu vector thô, file log và các file index. Node compute gặp sự cố khởi động lại cũng không lo mất dữ liệu.
- Query Node & Data Node: Query Node nạp index vào RAM để phục vụ tìm kiếm mili-giây. Data Node gom dữ liệu ghi (insert) thành các immutable segment.
2. Attu giúp ích gì cho vận hành?
Attu là GUI chính thức do Zilliz phát triển. Giao diện này giúp bạn bớt phải viết script thủ công mỗi khi cần kiểm tra dữ liệu:
- Tạo, sửa, xóa Collection và Partition trực quan.
- Kiểm tra trạng thái nạp bộ nhớ (Loaded/Unloaded) của từng collection.
- Test nhanh câu lệnh Vector Search và lọc Scalar metadata trực tiếp trên web.
- Theo dõi số lượng entity và kích thước segment theo thời gian thực.
Thao tác dữ liệu với PyMilvus và tối ưu Index
Hai yếu tố quyết định hiệu năng RAG là: thiết kế schema linh hoạt với Dynamic Field và chọn đúng thuật toán index.
1. Khởi tạo Collection cho hệ thống RAG
Dưới đây là script Python tạo collection chứa document chunk và vector 1536 chiều (chuẩn OpenAI text-embedding-3-small):
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection
# Kết nối tới Milvus
connections.connect("default", host="localhost", port="19530")
collection_name = "rag_enterprise_docs"
# Khai báo Schema
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="doc_id", dtype=DataType.VARCHAR, max_length=64),
FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=4096),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536)
]
# Bật enable_dynamic_field để thoải mái lưu thêm metadata JSON tùy ý
schema = CollectionSchema(fields, description="RAG Knowledge Store", enable_dynamic_field=True)
collection = Collection(name=collection_name, schema=schema)
print(f"Collection {collection_name} đã sẵn sàng!")
2. Chọn Index: HNSW hay IVF_FLAT?
Nếu không đánh index, Milvus phải quét toàn bộ bảng (Flat search). Với 1 triệu vector, query sẽ trễ hàng trăm mili-giây. Lựa chọn thực tế:
- HNSW: Tốc độ tìm kiếm cực nhanh (thường < 5ms trên 1 triệu vector), Recall đạt 98-99%. Điểm trừ: tốn RAM để dựng đồ thị.
- IVF_FLAT: Gom vector vào các cụm centroid. Index này tốn ít RAM hơn HNSW, thích hợp cho máy chủ cấu hình vừa phải.
Tạo index HNSW với metric khoảng cách Cosine:
index_params = {
"metric_type": "COSINE",
"index_type": "HNSW",
"params": {"M": 16, "efConstruction": 200}
}
collection.create_index(field_name="embedding", index_params=index_params)
# Nạp collection vào RAM sau khi build index
collection.load()
print("Index HNSW build xong, collection đã được load vào RAM.")
3. Hybrid Search: Lọc Metadata kết hợp Vector Similarity
Trong thực tế, bạn thường cần tìm chunk liên quan nhưng phải thuộc về một tài liệu hoặc phòng ban cụ thể. Dùng biểu thức expr để lọc:
query_vector = [0.015] * 1536
search_params = {"metric_type": "COSINE", "params": {"ef": 64}}
results = collection.search(
data=[query_vector],
anns_field="embedding",
param=search_params,
limit=3,
expr='doc_id == "finance_q1_2026"', # Lọc metadata trước khi tính tương đồng
output_fields=["doc_id", "content"]
)
for hits in results:
for hit in hits:
print(f"Score: {hit.distance:.4f} | Content: {hit.entity.get('content')}")
Kinh nghiệm thực chiến khi vận hành Milvus
- Nhớ gọi
collection.load(): Milvus chỉ query được trên các segment đã nạp vào RAM. Nếu query trả về rỗng, mở Attu kiểm tra xem collection đã chuyển sang trạng thái Loaded hay chưa. - Ước tính dung lượng RAM cho HNSW: Dùng công thức:
Số vector * Số chiều * 4 bytes * 1.5. Ví dụ: 5 triệu vector 1536 chiều cần khoảng5,000,000 * 1536 * 4 * 1.5 ≈ 46 GB RAM. Hãy chuẩn bị máy chủ tối thiểu 64GB RAM. - Giới hạn số lượng Partition: Chỉ nên giữ dưới 64 partition cho mỗi collection. Quá nhiều partition nhỏ sẽ làm phân mảnh bộ nhớ của Query Node. Muốn lọc dữ liệu chi tiết, hãy dùng Dynamic Metadata và biểu thức
expr. - Bật Etcd Compact định kỳ: Không dọn dẹp snapshot sẽ khiến file Etcd phình to vượt quota 2GB/4GB, dẫn đến treo cluster. Luôn giữ biến môi trường
ETCD_AUTO_COMPACTION_RETENTION=1000. - Monitor qua Prometheus: Milvus mở sẵn endpoint metrics ở port
9091/metrics. Bạn nên kéo về Grafana để theo dõi QPS, Query Latency và số lượng unindexed segment.

