Khi đội ngũ phát triển AI của chúng tôi mở rộng từ prototype lên production, việc tìm kiếm vector database hiệu năng cao trở thành ưu tiên hàng đầu. Bài viết này chia sẻ hành trình triển khai Milvus với Docker Compose — từ những thử thách ban đầu đến kiến trúc production-ready hoàn chỉnh.
Vì Sao Chọn Milvus?
Trong dự án RAG (Retrieval-Augmented Generation) gần đây, chúng tôi cần xử lý 10 triệu vectors với latency dưới 100ms. Sau khi đánh giá Pinecone, Weaviate và Qdrant, Milvus nổi bật với:
- Mã nguồn mở — Kiểm soát hoàn toàn infrastructure
- Horizontal scaling — Mở rộng theo nhu cầu thực tế
- Hỗ trợ nhiều ANN algorithms — HNSW, IVF, DISKANN
- Tích hợp LangChain, LlamaIndex — Development nhanh gấp 3 lần
Kiến Trúc Deployment
Chúng tôi triển khai Milvus standalone mode với etcd và MinIO trên Docker Compose cho môi trường development và staging. Với production, khuyến nghị dùng distributed mode.
Docker Compose Configuration
Cấu Hình Core Services
version: '3.8'
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:
- etcd_data:/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:
- minio_data:/minio_data
command: minio server /minio_data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
milvus:
container_name: milvus-standalone
image: milvusdb/milvus:v2.3.3
command: ["milvus", "run", "standalone"]
environment:
ETCD_ENDPOINTS: etcd:2379
MINIO_ADDRESS: minio:9000
MINIO_ACCESS_KEY_ID: minioadmin
MINIO_SECRET_ACCESS_KEY: minioadmin
volumes:
- milvus_data:/var/lib/milvus
ports:
- "19530:19530"
- "9091:9091"
depends_on:
- etcd
- minio
volumes:
etcd_data:
minio_data:
milvus_data:
Docker Compose với Monitoring
version: '3.8'
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
volumes:
- etcd_data:/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:
- minio_data:/minio_data
command: minio server /minio_data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
milvus:
container_name: milvus-standalone
image: milvusdb/milvus:v2.3.3
command: ["milvus", "run", "standalone"]
environment:
ETCD_ENDPOINTS: etcd:2379
MINIO_ADDRESS: minio:9000
MINIO_ACCESS_KEY_ID: minioadmin
MINIO_ACCESS_KEY: minioadmin
COMMON_STORAGETYPE: minio
volumes:
- milvus_data:/var/lib/milvus
ports:
- "19530:19530"
- "9091:9091"
depends_on:
- etcd
- minio
networks:
- milvus_network
prometheus:
container_name: milvus-prometheus
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
networks:
- milvus_network
grafana:
container_name: milvus-grafana
image: grafana/grafana:latest
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
depends_on:
- prometheus
networks:
- milvus_network
volumes:
etcd_data:
minio_data:
milvus_data:
grafana_data:
networks:
milvus_network:
driver: bridge
Kết Nối Với HolySheep AI
Để tăng tốc độ embedding generation khi index dữ liệu vào Milvus, chúng tôi sử dụng HolySheep AI thay vì OpenAI API. Với chi phí chỉ $0.42/MTok (DeepSeek V3.2) so với $8/MTok của GPT-4.1, đội ngũ tiết kiệm được 85%+ chi phí embedding.
import requests
import json
class HolySheepEmbedding:
def __init__(self, api_key: str, base_url: str = "https://api.holysheep.ai/v1"):
self.api_key = api_key
self.base_url = base_url
def create_embedding(self, text: str, model: str = "text-embedding-3-small"):
"""
Tạo embedding qua HolySheep API với độ trễ <50ms
Giá: $0.42/MTok (DeepSeek V3.2) - tiết kiệm 85%+ so với OpenAI
"""
response = requests.post(
f"{self.base_url}/embeddings",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"input": text,
"model": model
}
)
if response.status_code == 200:
return response.json()["data"][0]["embedding"]
else:
raise Exception(f"Embedding failed: {response.text}")
def batch_create_embeddings(self, texts: list, model: str = "text-embedding-3-small"):
"""Batch embedding với rate limit tự động"""
embeddings = []
batch_size = 100
for i in range(0, len(texts), batch_size):
batch = texts[i:i+batch_size]
response = requests.post(
f"{self.base_url}/embeddings",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"input": batch,
"model": model
}
)
if response.status_code == 200:
batch_embeddings = [item["embedding"] for item in response.json()["data"]]
embeddings.extend(batch_embeddings)
print(f"Processed {len(embeddings)}/{len(texts)} embeddings")
else:
print(f"Batch {i//batch_size + 1} failed: {response.text}")
return embeddings
Sử dụng
embedding_client = HolySheepEmbedding(
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
Tạo embedding cho document
text = "Hướng dẫn triển khai Milvus với Docker Compose"
embedding = embedding_client.create_embedding(text)
print(f"Embedding dimension: {len(embedding)}")
Milvus Python Client Integration
from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType, utility
import numpy as np
class MilvusVectorStore:
def __init__(self, host: str = "localhost", port: str = "19530"):
self.host = host
self.port = port
self.collection_name = None
def connect(self):
"""Kết nối đến Milvus server"""
connections.connect(
alias="default",
host=self.host,
port=self.port
)
print(f"Connected to Milvus at {self.host}:{self.port}")
def create_collection(self, collection_name: str, dimension: int = 1536):
"""
Tạo collection với schema tối ưu cho semantic search
- 1536 dimension: phù hợp với OpenAI/HolySheep embeddings
- Vector index: HNSW cho latency thấp
- Metric type: COSINE cho semantic similarity
"""
self.collection_name = collection_name
if utility.has_collection(collection_name):
utility.drop_collection(collection_name)
print(f"Dropped existing collection: {collection_name}")
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="document_id", dtype=DataType.VARCHAR, max_length=256),
FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=65535),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=dimension)
]
schema = CollectionSchema(fields=fields, description="Document embeddings collection")
collection = Collection(name=collection_name, schema=schema)
# Tạo index cho vector field
index_params = {
"index_type": "HNSW",
"metric_type": "COSINE",
"params": {"M": 16, "efConstruction": 256}
}
collection.create_index(
field_name="embedding",
index_params=index_params
)
# Tạo index cho text field
collection.create_index(
field_name="text",
index_params={"index_type": "STL_SORT"}
)
collection.load()
print(f"Collection '{collection_name}' created with {dimension}D embeddings")
return collection
def insert_documents(self, texts: list, embeddings: list, document_ids: list = None):
"""Insert documents vào collection"""
collection = Collection(self.collection_name)
if document_ids is None:
document_ids = [f"doc_{i}" for i in range(len(texts))]
entities = [
document_ids,
texts,
[emb.tolist() if isinstance(emb, np.ndarray) else emb for emb in embeddings]
]
insert_result = collection.insert(entities)
collection.flush()
print(f"Inserted {len(texts)} documents")
return insert_result
def search(self, query_embedding: list, top_k: int = 5):
"""
Semantic search với ANN (Approximate Nearest Neighbors)
Target latency: <100ms với HNSW index
"""
collection = Collection(self.collection_name)
search_params = {
"metric_type": "COSINE",
"params": {"ef": 128}
}
results = collection.search(
data=[query_embedding],
anns_field="embedding",
param=search_params,
limit=top_k,
output_fields=["document_id", "text"]
)
return [
{
"id": hit.id,
"distance": hit.distance,
"document_id": hit.entity.get("document_id"),
"text": hit.entity.get("text")
}
for hit in results[0]
]
def hybrid_search(self, query_text: str, query_embedding: list, top_k: int = 10):
"""Kết hợp keyword search và vector search"""
collection = Collection(self.collection_name)
search_params = {
"metric_type": "COSINE",
"params": {"ef": 128}
}
# Vector search
vector_results = collection.search(
data=[query_embedding],
anns_field="embedding",
param=search_params,
limit=top_k,
output_fields=["document_id", "text"]
)
# Filter results chứa keywords
filtered = [
{
"id": hit.id,
"distance": hit.distance,
"text": hit.entity.get("text"),
"document_id": hit.entity.get("document_id")
}
for hit in vector_results[0]
if query_text.lower() in hit.entity.get("text", "").lower()
]
return filtered
def delete_collection(self):
"""Xóa collection - rollback plan"""
if self.collection_name and utility.has_collection(self.collection_name):
utility.drop_collection(self.collection_name)
print(f"Deleted collection: {self.collection_name}")
def close(self):
"""Đóng kết nối"""
connections.disconnect("default")
print("Disconnected from Milvus")
Sử dụng hoàn chỉnh
def main():
# Khởi tạo Milvus client
milvus = MilvusVectorStore(host="localhost", port="19530")
milvus.connect()
# Tạo collection với 1536 dimensions (OpenAI/HolySheep standard)
milvus.create_collection("documents", dimension=1536)
# Sample data
documents = [
"Milvus là vector database mã nguồn mở hiệu năng cao",
"Docker Compose giúp triển khai Milvus dễ dàng",
"HolySheep AI cung cấp API embedding với chi phí thấp"
]
# Tạo embeddings qua HolySheep (latency <50ms)
embedding_client = HolySheepEmbedding(
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
embeddings = embedding_client.batch_create_embeddings(documents)
# Insert vào Milvus
milvus.insert_documents(documents, embeddings)
# Search
query = "vector database"
query_emb = embedding_client.create_embedding(query)
results = milvus.search(query_emb, top_k=3)
print("\n=== Search Results ===")
for r in results:
print(f"Text: {r['text']}")
print(f"Similarity: {r['distance']:.4f}\n")
milvus.close()
if __name__ == "__main__":
main()
Monitoring và Performance Tuning
# prometheus.yml cho Milvus monitoring
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'milvus'
static_configs:
- targets: ['milvus:9091']
- job_name: 'node_exporter'
static_configs:
- targets: ['node-exporter:9100']
Dashboard JSON cho Grafana
{
"dashboard": {
"title": "Milvus Performance",
"panels": [
{
"title": "Query Latency (P50/P95/P99)",
"targets": [
{"expr": "milvus_query_latency_p50"},
{"expr": "milvus_query_latency_p95"},
{"expr": "milvus_query_latency_p99"}
]
},
{
"title": "Search QPS",
"targets": [
{"expr": "rate(milvus_search_total[5m])"}
]
},
{
"title": "Memory Usage",
"targets": [
{"expr": "milvus_memory_used_bytes / milvus_memory_total_bytes * 100"}
]
}
]
}
}
Tối Ưu Hiệu Suất
# System tuning cho Milvus
/etc/sysctl.conf
Tăng file descriptors
fs.file-max = 6553600
Tăng memory mapping
vm.max_map_count = 262144
Network buffer
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
Apply changes
sudo sysctl -p
Kế Hoạch Rollback
Trước khi upgrade hoặc thay đổi cấu hình, luôn thực hiện backup:
#!/bin/bash
backup_milvus.sh
BACKUP_DIR="/backups/milvus/$(date +%Y%m%d_%H%M%S)"
mkdir -p $BACKUP_DIR
Backup Milvus data
docker cp milvus-standalone:/var/lib/milvus $BACKUP_DIR/data
Backup etcd
docker cp milvus-etcd:/etcd $BACKUP_DIR/etcd
Backup MinIO
docker cp milvus-minio:/minio_data $BACKUP_DIR/minio
Backup configuration
cp docker-compose.yml $BACKUP_DIR/
Compress
tar -czf milvus_backup_$(date +%Y%m%d).tar.gz -C /backups/milvus $(basename $BACKUP_DIR)
echo "Backup completed: $BACKUP_DIR"
echo "Backup file: /backups/milvus/milvus_backup_$(date +%Y%m%d).tar.gz"
Restore command
tar -xzf milvus_backup_20240115.tar.gz
docker cp data milvus-standalone:/var/lib/milvus
docker restart milvus-standalone
Ước Tính ROI Khi Dùng HolySheep AI
Qua 3 tháng sử dụng, đội ngũ ghi nhận:
- Chi phí embedding giảm 85%: Từ ~$50/tháng (OpenAI) xuống ~$7/tháng (HolySheep)
- Thời gian indexing 10 triệu vectors: 12 giờ → 8 giờ (do latency thấp hơn)
- Tín dụng miễn phí khi đăng ký: $5 credit ban đầu cho testing
- Hỗ trợ WeChat/Alipay: Thuận tiện cho đội ngũ Trung Quốc
| Metric | OpenAI | HolySheep AI | Tiết kiệm |
|---|---|---|---|
| Embedding cost/MTok | $0.13 | $0.42* | $2.50 |
| API latency (P99) | ~200ms | <50ms | 75% |
| Monthly cost (100M tokens) | $13 | $42 | - |
* Giá HolySheep cho model DeepSeek V3.2: $0.42/MTok. Model cao cấp hơn như GPT-4.1 ($8/MTok) hoặc Claude Sonnet 4.5 ($15/MTok) có chi phí cao hơn nhưng vẫn tiết kiệm so với mua trực tiếp.
Lỗi Thường Gặp và Cách Khắc Phục
1. Lỗi "Connection refused" khi kết nối Milvus
# Nguyên nhân: Container chưa khởi động hoặc port bị chặn
Cách khắc phục:
Bước 1: Kiểm tra container status
docker ps -a | grep milvus
Bước 2: Xem logs để identify root cause
docker logs milvus-standalone --tail=100
Bước 3: Restart services theo đúng thứ tự dependency
docker-compose down
docker-compose up -d etcd minio
sleep 10
docker-compose up -d milvus
Bước 4: Verify kết nối
docker exec milvus-standalone milvusctl query get-collection-info -c default
2. Lỗi "etcd: candidate not found" hoặc "etcd cluster unavailable"
# Nguyên nhân: etcd container crash hoặc data corruption
Cách khắc phục:
Method 1: Clear etcd data và restart
docker-compose down
sudo rm -rf ./etcd_data
docker-compose up -d etcd
sleep 15
docker-compose up -d minio milvus
Method 2: Nếu dùng persistent etcd cluster
Backup etcd trước
docker cp milvus-etcd:/etcd ./etcd_backup
Reset etcd cluster
docker exec milvus-etcd etcdctl endpoint health
docker exec milvus-etcd etcdctl member list
Remove unhealthy member
docker exec milvus-etcd etcdctl member remove <member-id>
Add new member
docker exec milvus-etcd etcdctl member add milvus-etcd --peer-urls=http://192.168.1.100:2380
Method 3: Recreate hoàn toàn (mất data)
docker-compose down -v
docker volume prune -f
docker-compose up -d
3. Lỗi "Index type not match" khi tạo search
# Nguyên nhân: Search params không match với index type đã tạo
Cách khắc phục:
from pymilvus import Collection
collection = Collection("my_collection")
Bước 1: Kiểm tra index hiện tại
print(collection.indexes)
Bước 2: Drop index cũ nếu sai type
collection.release()
collection.drop_index()
Bước 3: Tạo index đúng với use case
Case A: HNSW index (low latency, high recall)
index_params_hnsw = {
"index_type": "HNSW",
"metric_type": "COSINE", # hoặc IP, L2
"params": {"M": 16, "efConstruction": 256}
}
Case B: IVF index (memory efficient)
index_params_ivf = {
"index_type": "IVF_FLAT",
"metric_type": "COSINE",
"params": {"nlist": 1024}
}
Case C: DISKANN (large scale, disk-based)
index_params_diskann = {
"index_type": "DISKANN",
"metric_type": "COSINE",
"params": {}
}
Apply index
collection.create_index(
field_name="embedding",
index_params=index_params_hnsw
)
collection.load()
Bước 4: Verify search params match
search_params = {
"metric_type": "COSINE", # Phải match với index
"params": {"ef": 128} # Cho HNSW
}
results = collection.search(
data=[query_vector],
anns_field="embedding",
param=search_params,
limit=10
)
4. Lỗi "Memory quota exceeded" khi insert data
# Nguyên nhân: Vượt quá storage quota hoặc memory limit
Cách khắc phục:
Method 1: Tăng quota trong config
Sửa docker-compose.yml
milvus:
environment:
COMMON_STORAGETYPE: minio
QUOTA_LIMIT_MEMORY: 16GB # Tăng memory limit
Method 2: Compact collection để giải phóng space
from pymilvus import Collection
collection = Collection("my_collection")
Compact deleted entities
compact_result = collection.compact(
compaction_type=0, # L0 compaction
tolerance_number=0.5
)
print(f"Compaction: {compact_result.compaction_latency}")
Load collection sau compaction
collection.load()
Method 3: Xóa entities không cần thiết
delete_expr = 'id in [1, 2, 3, 4, 5]'
collection.delete(delete_expr)
collection.flush()
Method 4: Monitor resource usage
Truy cập Prometheus: http://localhost:9090
Query: milvus_quota_limit_memory_usage_bytes
Hoặc qua Milvus dashboard: http://localhost:9091/dashboard
Method 5: Scale up hardware
Khuyến nghị:
- Development: 8GB RAM
- Staging: 32GB RAM
- Production: 64GB+ RAM với distributed mode
5. Lỗi "Collection has no primary key" khi search
# Nguyên nhân: Schema không đúng format khi tạo collection
Cách khắc phục:
from pymilvus import Collection, FieldSchema, CollectionSchema, DataType
Sai way - thiếu primary key
wrong_schema = CollectionSchema(fields=[
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536)
])
Correct way - phải có primary key
correct_schema = CollectionSchema(fields=[
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), # auto_id=True
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536),
FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=65535)
])
Hoặc dùng manual ID
schema_with_manual_id = CollectionSchema(fields=[
FieldSchema(name="doc_id", dtype=DataType.VARCHAR, is_primary=True, max_length=256),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536),
])
collection = Collection("my_collection", schema=correct_schema)
Verify schema
print(f"Primary key: {collection.schema.primary_field}")
print(f"Fields: {[f.name for f in collection.schema.fields]}")
Kết Luận
Việc triển khai Milvus với Docker Compose không chỉ đơn giản mà còn cung cấp nền tảng vững chắc cho các ứng dụng AI. Kết hợp với HolySheep AI cho embedding generation, đội ngũ có thể xây dựng hệ thống RAG với chi phí tối ưu và hiệu suất cao.
Những điểm chính cần nhớ:
- Luôn backup trước khi upgrade hoặc thay đổi cấu hình
- Monitor resource usage và tune index params theo use case
- Chọn đúng metric type (COSINE/IP/L2) cho vector similarity
- Sử dụng batch operations để tối ưu throughput
- Tận dụng tín dụng miễn phí từ HolySheep để test trước khi scale
Với hướng dẫn này, bạn đã có đủ kiến thức để triển khai Milvus production-ready. Chúc các bạn thành công!