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:

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:

MetricOpenAIHolySheep AITiết kiệm
Embedding cost/MTok$0.13$0.42*$2.50
API latency (P99)~200ms<50ms75%
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ớ:

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!

👉 Đăng ký HolySheep AI — nhận tín dụng miễn phí khi đăng ký