This guide is the operational and architectural reference for Milvus, the open-source distributed vector database. It targets administrators, SREs, platform engineers, and architects who deploy, configure, secure, monitor, and extend Milvus in production. It assumes familiarity with the user-facing concepts (collections, vectors, indexes, search) covered in the companion User Guide.
Milvus is written in Go (the distributed control and data planes) and C++ (the
internal/core vector search and storage engine, "Segcore" and the Knowhere index library).
It is designed to be cloud-native and K8s-native, separating compute from storage so that
read and write capacity scale independently. Source references in this guide point at the
Milvus codebase at commit d9bbbc1.
1. Executive Summary
| Aspect | Summary |
|---|---|
| What it is | A distributed vector database for similarity search over billions of embeddings |
| Languages | Go (control/data plane), C++ (Segcore search engine), Python (test client) |
| Architecture | Disaggregated: a coordinator, stateless workers, a streaming/WAL layer, and external storage |
| External dependencies | etcd (metadata + service discovery), object storage (MinIO/S3/GCS/Azure), a message queue / WAL (Woodpecker, Pulsar, Kafka, or RocksMQ) |
| Deployment modes | Milvus Lite (embedded), Standalone (one container), Distributed (Kubernetes) |
| Client interfaces | gRPC (19530), REST v2 (/v2/vectordb/*), SDKs (Python/Go/Java/Node) |
| Security | User auth, RBAC (Casbin), TLS (external + internal), quotas & rate limits |
| Observability | Prometheus metrics + health on 9091, OpenTelemetry tracing, built-in Web UI |
| License | Apache 2.0, under the LF AI & Data Foundation |
The defining design choice is storage/compute disaggregation built on a shared log. All durable state lives in external systems (etcd for metadata, object storage for data, a WAL for the recent mutation stream). Milvus's own processes are stateless and restartable, which is what enables horizontal scaling and fast failure recovery.
Important
As of the 2.6 line (this codebase, image
milvusdb/milvus:v3.0-beta), the streaming service is enabled by default and the three legacy coordinators (root/data/query) are unified into a single MixCoord process. Plan deployments around MixCoord + workers + StreamingNode, not the older per-coordinator model.
2. Architecture
2.1 Component model
A Milvus deployment is composed of these roles, each started by the milvus binary via
milvus run <role> (cmd/roles/roles.go, cmd/components/*):
┌──────────────────────────────┐
SDK / REST clients ──▶│ Proxy │ stateless gateway (gRPC+REST :19530)
└──────────────┬───────────────┘
│
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌────────────────┐ ┌────────────────┐
│ MixCoord │ │ QueryNode(s) │ │ DataNode(s) │
│ root+data+ │ │ load segments │ │ consume WAL, │
│ query coord │ │ run searches │ │ flush, compact│
└───────┬───────┘ └───────┬────────┘ └───────┬────────┘
│ │ │
│ ┌───────┴─────────┐ │
│ │ StreamingNode │ WAL append/scan, time-tick
│ └───────┬─────────┘ │
┌──────────┴───────────┬───────────┴─────────────┬───────────┴────────┐
▼ ▼ ▼ ▼
etcd Message queue / WAL Object storage (optional GPU)
metadata + Woodpecker | Pulsar | MinIO | S3 | GCS |
service discovery Kafka | RocksMQ Azure Blob
| Role | Responsibility | Stateful? |
|---|---|---|
| Proxy | Client gateway: validates requests, enforces auth/RBAC and quotas, routes to coordinators and nodes, reduces results | No |
| MixCoord | Unified coordinator — DDL/DCL (collections, partitions, schema), data lifecycle (segments, compaction, indexing, GC), query topology and load balancing | No (state in etcd) |
| QueryNode | Loads sealed/growing segments into memory, executes vector + scalar search and query | No (data in object storage) |
| DataNode | Consumes the write stream, buffers and flushes segments to object storage, runs compaction and index building | No |
| StreamingNode | Owns the write-ahead log (WAL): appends mutations, serves scans, drives time-tick and recovery | No (log is durable) |
| CDC | Optional change-data-capture role for cross-cluster replication | No |
Note
MixCoord internally still contains the RootCoord (DDL/DCL), DataCoord (data/segment management), and QueryCoord (query topology) subsystems — their configuration sections (
rootCoord.*,dataCoord.*,queryCoord.*) remain separate even though they run in one process. In a fully disaggregated cluster you may still run them as separate processes via themixtureserver type with role flags.
2.2 The milvus run role matrix
cmd/milvus/util.go:GetMilvusRoles maps a server type to the set of enabled components:
| Server type | Components enabled |
|---|---|
standalone |
MixCoord + Proxy + QueryNode + DataNode + StreamingNode (single process, Local=true, may embed etcd/RocksMQ) |
mixcoord |
MixCoord only |
mixture |
Any combination via flags: -rootcoord -querycoord -datacoord -querynode -datanode -proxy -streamingnode |
proxy |
Proxy only |
querynode |
QueryNode only |
datanode |
DataNode only |
streamingnode |
StreamingNode (also enables an embedded QueryNode label) |
cdc |
CDC only |
embedded |
Like standalone but for Milvus Lite (embedded, config from embedded-milvus.yaml) |
Roles are also selectable by environment variable (ENABLE_PROXY, ENABLE_QUERY_NODE,
ENABLE_DATA_NODE, ENABLE_STREAMING_NODE, ENABLE_ROOT_COORD, ENABLE_QUERY_COORD,
ENABLE_DATA_COORD, ENABLE_CDC).
2.3 The storage layers
Milvus separates three kinds of state into three external systems:
- Metadata & coordination → etcd. Collection schemas, segment metadata, index metadata,
node sessions, and service discovery live in etcd under
etcd.rootPath(defaultby-dev). TiKV is an alternative metadata store for very large metadata (metastore.type: tikv), but etcd is still required for service discovery. - Durable data → object storage. Sealed segment binlogs, delta logs, statistics, and
index files are written to MinIO/S3/GCS/Azure under
minio.*. This is the system of record for data. - Recent mutations → WAL / message queue. New inserts and deletes flow through a write-ahead log before they are flushed to object storage. The WAL implementation is pluggable: Woodpecker (native, recommended for new installs), Pulsar, Kafka, or RocksMQ (standalone only).
Tip
For new deployments the project recommends Woodpecker as the WAL/MQ for better performance, simpler operations, and lower cost. RocksMQ is only valid in standalone mode; cluster mode defaults to Pulsar when
mq.typeis left atdefault.
2.4 Data lifecycle and segments
Data moves through growing → sealed → indexed segments:
- Writes land in growing segments (in memory, also mmappable) via the WAL.
- DataCoord seals a segment when it reaches size/age thresholds (
dataCoord.segment.maxSize,sealProportion,maxLife,maxIdleTime, or thesealPolicy.channel.*watermarks). - Sealed segments are flushed to object storage and indexed (vector and scalar indexes are built by DataNode/index tasks).
- Compaction merges small segments, applies deletes, and runs clustering compaction
(
dataCoord.compaction.*). Garbage collection removes orphaned files (dataCoord.gc.*). - QueryNodes load sealed+indexed segments to serve search; a delegator forwards streaming deletes and growing data.
2.5 The C++ core (Segcore + Knowhere)
The internal/core/src tree is the C++ engine, reached from Go via cgo wrappers
(internal/util/segcore, indexcgowrapper, analyzecgowrapper):
- Segcore — in-segment storage, chunked columnar layout, expression evaluation, and the search/query operators.
- Knowhere — the vector index library (
knowhere.*config) implementing FLAT, IVF*, HNSW, SCANN, DISKANN, and GPU (CAGRA) indexes with CPU SIMD acceleration (common.simdType: auto/avx512/avx2/avx/sse4_2). - Tiered storage —
queryNode.segcore.tieredStorage.*controls memory/disk cache warmup and eviction watermarks for hot/cold data.
3. Requirements
3.1 Build requirements
From README.md / DEVELOPMENT.md, building Milvus from source needs (Linux/Ubuntu 20.04+):
Go: >= 1.21 (go.mod pins go 1.25.x)
CMake: >= 3.26.4 && < 4
GCC: >= 11 (Linux) / llvm >= 15 (macOS)
Python: > 3.8 and <= 3.11
git clone https://github.com/milvus-io/milvus.git
cd milvus
./scripts/install_deps.sh
make
3.2 Runtime dependencies
| Dependency | Version (dev compose) | Role |
|---|---|---|
| etcd | v3.5.x | Metadata + service discovery |
| MinIO | RELEASE.2024-05-28 | Object storage (S3-compatible) |
| Pulsar | 2.8.x | Optional WAL/MQ (cluster default) |
| Kafka | — | Optional WAL/MQ |
| Woodpecker | built-in | Native WAL (recommended) |
Object storage may instead be AWS S3, Google Cloud Storage (gcpnative), Azure Blob, Aliyun
OSS, Tencent COS, or Huawei OBS (see minio.cloudProvider and pkg/objectstorage/*).
3.3 Sizing guidance
- Memory is the primary constraint for QueryNodes — loaded segments and indexes are held in RAM (or mmap/tiered cache). Size query nodes to your loaded dataset plus index overhead.
- DataNodes are CPU/memory bound during flush, compaction, and index building.
- Object storage must hold all segment, index, delta, and stats files; plan for several times the raw vector size after indexing and replication.
4. Configuration
Milvus is configured by configs/milvus.yaml (1,500+ keys). Configuration is layered:
YAML file → environment variables (a subset, e.g. ETCD_ENDPOINTS, MINIO_ADDRESS,
MINIO_ACCESS_KEY_ID) → runtime overrides via etcd (some keys are hot-reloadable; the
paramtable watches etcd and applies changes live). Some keys are immutable and persisted
at first startup (e.g. the selected WAL name).
Note
Many keys preferentially read an environment variable when present —
etcd.endpointsreadsETCD_ENDPOINTS,minio.addressreadsMINIO_ADDRESS, and the MinIO keys readMINIO_ACCESS_KEY_ID/MINIO_SECRET_ACCESS_KEY. This is how the Docker Compose files inject infrastructure addresses.
4.1 Metadata store — etcd / metastore / tikv
| Key | Default | Purpose |
|---|---|---|
etcd.endpoints |
localhost:2379 |
etcd endpoints (env ETCD_ENDPOINTS) |
etcd.rootPath |
by-dev |
Root prefix for all Milvus keys — change per cluster sharing one etcd |
etcd.metaSubPath / kvSubPath |
meta / kv |
Sub-prefixes for metadata and KV |
etcd.ssl.enabled |
false |
TLS to etcd (tlsCert/tlsKey/tlsCACert, tlsMinVersion 1.3) |
etcd.use.embed |
false |
Embed an in-process etcd (standalone/testing only) |
etcd.auth.enabled |
true |
etcd auth (userName/password) |
etcd.requestTimeout |
10000 ms |
etcd op timeout |
metastore.type |
etcd |
etcd or tikv |
metastore.maxEtcdTxnNum |
64 |
Max ops per etcd transaction |
tikv.endpoints |
127.0.0.1:2389 |
TiKV PD endpoint (when metastore.type: tikv) |
Caution
Changing
etcd.rootPath,metaSubPath,kvSubPath, or themsgChannelprefixes after a cluster has data will make existing data unreadable. Set them once, before first start.
4.2 Object storage — minio / localStorage
| Key | Default | Purpose |
|---|---|---|
minio.address / port |
localhost / 9000 |
Storage endpoint (env MINIO_ADDRESS) |
minio.accessKeyID / secretAccessKey |
minioadmin |
Credentials (env MINIO_ACCESS_KEY_ID / MINIO_SECRET_ACCESS_KEY) |
minio.useSSL |
false |
TLS to storage (ssl.tlsCACert, ssl.tlsMinVersion) |
minio.bucketName |
a-bucket |
Bucket (created if absent) |
minio.rootPath |
files |
Key prefix in the bucket |
minio.useIAM |
false |
Use IAM role instead of static keys |
minio.cloudProvider |
aws |
aws, gcp, gcpnative, aliyun, tencent, huawei, azure |
minio.region |
— | Storage region |
localStorage.path |
/var/lib/milvus/data/ |
Local cache for query/search to avoid re-fetching from object storage |
common.storageType |
remote |
remote, local, or opendal |
Tip
In production prefer
useIAM: truewith instance/workload identity over staticaccessKeyID/secretAccessKey. Static keys inmilvus.yamlare a credential-leak risk.
4.3 Message queue / WAL — mq / woodpecker / pulsar / kafka / rocksmq
| Key | Default | Purpose |
|---|---|---|
mq.type |
default |
default, pulsar, kafka, rocksmq, woodpecker |
mq.enablePursuitMode |
true |
Catch-up mode for lagging consumers |
woodpecker.storage.type |
minio |
Native WAL storage backend (minio or local) |
woodpecker.client.segmentRollingPolicy.maxSize |
256M |
WAL segment roll size |
pulsar.address / port |
localhost / 6650 |
Pulsar broker (env PULSAR_ADDRESS) |
pulsar.maxMessageSize |
2097152 |
Max Pulsar message (2 MB) |
pulsar.tenant / namespace |
public / default |
Pulsar multi-tenancy |
kafka.brokerList |
(commented) | Kafka brokers + SASL/SSL block |
rocksmq.path |
/var/lib/milvus/rdb_data |
RocksMQ data dir (standalone only) |
rocksmq.retentionTimeInMinutes |
4320 |
RocksMQ retention (3 days) |
Priority when mq.type: default: standalone → rocksmq > Pulsar > Kafka > Woodpecker;
cluster → Pulsar > Kafka > Woodpecker (RocksMQ unsupported in cluster).
4.4 Coordinator and node configuration
Each role has its own section. Key knobs (selected — see configs/milvus.yaml for the full
set):
rootCoord (DDL/DCL): maxPartitionNum (1024), maxDatabaseNum (64), dmlChannelNum
(16), minSegmentSizeToEnableIndex (1024), enableActiveStandby (false), port 22125.
proxy (gateway): maxNameLength (255), maxFieldNum (64), maxVectorFieldNum (10),
maxShardNum (16), maxDimension (32768), maxTaskNum (1024), maxConnectionNum (10000),
http.enabled (true), http.enableWebUI (true), accessLog.*, port 19530,
internalPort 19529, grpc.serverMaxRecvSize (64 MB), grpc.serverMaxSendSize (256 MB).
queryCoord (topology/balance): autoBalance (true), balancer (ScoreBasedBalancer),
overloadedMemoryThresholdPercentage (90), balanceIntervalSeconds (60),
loadTimeoutSeconds (600), enableStoppingBalance (true), port 19531.
queryNode (search execution):
- Segcore:
segcore.chunkRows(128),knowhereThreadPoolNumRatio(4),interimIndex.enableIndex(true),interimIndex.nlist/nprobe. - Memory/mmap:
mmap.vectorField(true),mmap.vectorIndex(false),cache.readAheadPolicy(willneed),loadMemoryUsageFactor(1),enableDisk(false),maxDiskUsagePercentage(95). - Tiered storage:
segcore.tieredStorage.warmup.*(sync/async/disable),memoryLowWatermarkRatio(0.75) /memoryHighWatermarkRatio(0.8),evictionEnabled(false). - Scheduler:
scheduler.maxReadConcurrentRatio,scheduler.scheduleReadPolicy.name(fifooruser-task-polling).port21123.
dataCoord (data lifecycle):
- Segments:
segment.maxSize(1024 MB),diskSegmentMaxSize(2048 MB),sealProportion(0.12),maxLife(86400 s),maxIdleTime(600 s). - Compaction:
enableCompaction(true),compaction.enableAutoCompaction(true),compaction.clustering.enable(true),compaction.taskPrioritizer(level), L0/mix/single/clustering trigger intervals. - GC:
enableGarbageCollection(true),gc.interval(3600 s),gc.missingTolerance(86400 s),gc.dropTolerance(10800 s).port13333.
dataNode (flush/compaction):
- Sync:
dataSync.flowGraph.maxQueueLength(16),memory.forceSyncEnable(true),memory.forceSyncWatermark(0.5). - Segment buffer:
segment.insertBufSize(16 MB),segment.deleteBufBytes(16 MB),segment.syncPeriod(600 s). - Slots:
slot.slotCap(16). Storage format:storage.format(parquet),storage.deltalog(json).gracefulStopTimeout(1800 s).port21124.
streamingNode / streaming (WAL service): streamingNode.port 22222;
streaming.walBalancer.* (balance policy vchannelFair), streaming.flush.*
(memory/growing-segment watermarks), streaming.walRecovery.*, streaming.txn.*,
streaming.replication.*.
4.5 Common, GPU, Knowhere
common holds cross-cutting settings: common.security.* (see Security),
common.gracefulStopTimeout (1800 s), common.simdType (auto), common.storageType
(remote), thread-pool coefficients (threadCoreCoefficient.*), DiskIndex tuning
(common.DiskIndex.*), bloom-filter settings, and JSON-shredding toggles.
gpu (GPU builds only): gpu.initMemSize (2048 MB), gpu.maxMemSize (4096 MB),
gpu.overloadedMemoryThresholdPercentage (95).
knowhere: per-index-type default parameters (AISAQ, DISKANN build/search params)
auto-populated when knowhere.enable is true.
4.6 Logging, gRPC, tracing
| Section | Key | Default |
|---|---|---|
log |
level |
info (trace/debug/info/warn/error/panic/fatal) |
log |
file.rootPath |
empty (stdout) |
log |
format |
text (or JSON) |
grpc |
client.dialTimeout / keepAliveTime |
200 / 10000 ms |
grpc |
gracefulStopTimeout |
3 s |
trace |
exporter |
noop (or stdout, jaeger, otlp) |
trace |
sampleFraction |
0 |
trace |
otlp.endpoint / jaeger.url |
— |
Log level is hot-reloadable — the server watches log.level in etcd and applies changes
without restart (cmd/roles/roles.go:setupLogger). Tracer config is likewise re-applied on
change.
5. Security
Caution
A default Milvus install is insecure by design for ease of first use: authorization is off (
common.security.authorizationEnabled: false) and therootuser has the well-known passwordMilvus. Before exposing Milvus to any shared or untrusted network, enable auth, change the root password, and enable TLS.
5.1 Authentication
common.security.authorizationEnabled— settrueto require credentials on every request.common.security.defaultRootPassword(Milvus) — change this; the root account is the bootstrap admin. (Max length 72 chars.)common.security.superUsers— users that bypass some checks (e.g. the old-password check on credential update).common.security.rootShouldBindRole— require root to bind a role when auth is on.common.security.enablePublicPrivilege(true) — whether a default public privilege exists.
Clients authenticate with username/password (sent base64-encoded in the authorization
metadata header) or an API key (client/milvusclient/client.go:parseAuthentication).
5.2 RBAC
Milvus implements role-based access control backed by Casbin (github.com/casbin/casbin).
Administrators manage users, roles, privileges, and privilege groups (SDK methods in
client/milvusclient/rbac.go and rbac_v2.go):
- Users —
CreateUser,UpdatePassword,DropUser,ListUsers,DescribeUser. - Roles —
CreateRole,DropRole,GrantRole,RevokeRole,DescribeRole,ListRoles. - Privileges (v2) —
GrantPrivilegeV2,RevokePrivilegeV2grant a privilege on an object (collection/database/etc.) to a role. - Privilege groups —
CreatePrivilegeGroup,AddPrivilegesToGroup,RemovePrivilegesFromGroup,ListPrivilegeGroupsbundle privileges for reuse. - Backup/restore —
BackupRBAC/RestoreRBACexport and import the entire RBAC model (users, roles, grants, privilege groups) — use these before upgrades or for DR.
proxy.resolveAliasForPrivilege (true) controls whether aliases resolve to real collection
names during privilege checks.
5.3 TLS
Two independent TLS scopes:
- External TLS (
tls.*) secures client↔Proxy traffic:serverPemPath,serverKeyPath,caPemPath. Enable on the client withEnableTLSAuth. - Internal TLS (
internaltls.*+common.security.internaltlsEnabled) secures intra-cluster gRPC between components:serverPemPath,serverKeyPath,caPemPath, and ansnimatching the certificate.common.security.tlsModeselects the TLS mode (0/1/2 for off/one-way/two-way). - etcd, MinIO, and Kafka each have their own TLS blocks (
etcd.ssl,minio.ssl,kafka.ssl).
Note
A FIPS-validated build is available: the binary can enable OpenSSL FIPS / Go BoringCrypto (
cmd/milvus/boring_*.go,pkg/util/fips). The startup banner reportsMilvus FIPS in Go: BoringCrypto <bool>.
5.4 The /expr debug endpoint
common.security.exprEnabled (default false) gates the /expr HTTP endpoint used for live
expression debugging. When enabled it is restricted to the root user via HTTP Basic Auth on
Proxy nodes. Leave it disabled in production.
5.5 Quotas and rate limits
quotaAndLimits.* is both a stability mechanism and a multi-tenant fairness control. By
default Milvus enables time-tick protection, memory protection, and disk-quota
protection; you can additionally enable DML/DDL/DQL rate limits.
| Protection | Key | Default |
|---|---|---|
| Master switch | quotaAndLimits.enabled |
true |
| Memory protection | limitWriting.memProtection.enabled |
true (low 0.85 / high 0.95 water marks for data & query nodes) |
| Disk quota | limitWriting.diskProtection.enabled |
true (diskQuota -1 = unlimited) |
| Time-tick protection | limitWriting.ttProtection.enabled |
false (maxDelay 1200 s) |
| DDL throttle | ddl.enabled |
false (collectionRate/partitionRate -1) |
| DML throttle | dml.enabled |
false (insertRate/deleteRate per db/collection/partition) |
| DQL throttle | dql.enabled |
false (searchRate/queryRate) |
| Flush throttle | flushRate.enabled |
true (collection 0.1 qps) |
| Force-deny writes/reads | limitWriting.forceDeny / limitReading.forceDeny |
false |
| Max result entries | proxy.maxResultEntries |
-1 (disabled) |
Warning
When memory or disk water marks are crossed, Milvus throttles or rejects DML to protect the cluster. "Quota exceeded" / write-denied errors usually mean a node is near its memory high-water mark or the disk quota is hit — scale out or raise the quota rather than retrying blindly.
6. Deployment
6.1 Standalone (Docker Compose)
Use deployments/docker/standalone/docker-compose.yml (see the User Guide for the full file).
It launches milvus-etcd, milvus-minio, and milvus-standalone (milvus run standalone),
publishing 19530 (API) and 9091 (health/metrics/Web UI). A GPU variant lives at
deployments/docker/gpu/standalone/.
sudo docker compose up -d
curl -f http://localhost:9091/healthz # -> OK
6.2 Distributed cluster
For production scale, run roles as independent, separately scaled deployments on Kubernetes
(the official Milvus Helm chart / Milvus Operator; this repository provides reference Ansible
roles under deployments/docker/cluster-distributed-deployment/). Typical topology:
- Multiple Proxies behind a load balancer (stateless; scale for connection/throughput).
- MixCoord with
enableActiveStandbyfor HA (one active, standbys ready). - QueryNodes scaled for read/memory (each holds loaded segments).
- DataNodes scaled for write/compaction/index throughput.
- StreamingNodes for the WAL service.
- External etcd (3+ nodes), object storage, and Pulsar/Kafka/Woodpecker.
Tip
Scale QueryNodes for read-heavy or large-resident-data workloads and DataNodes for write-heavy/ingest workloads — this independent scaling is the main reason to choose the cluster topology over standalone.
6.3 High availability
- Coordinators support active-standby (
*.enableActiveStandby): standbys take over via etcd session/lease on failure. - Workers are stateless; losing one triggers QueryCoord auto-balance to redistribute segments.
- The WAL plus object storage make data durable independent of any Milvus process; recovery replays from the WAL and reloads from object storage.
- Replicas (multiple loaded copies of segments across query nodes) increase read
throughput and fault tolerance — manage with resource groups and
TransferReplica.
6.4 Resource groups
Resource groups partition QueryNodes into pools so you can isolate workloads/tenants
(client/milvusclient/resource_group.go): CreateResourceGroup, UpdateResourceGroup,
TransferReplica, DescribeReplica. quotaAndLimits.limits.maxResourceGroupNumOfQueryNode
(1024) bounds the count.
7. Operations
7.1 Starting and stopping
milvus run standalone # or: run mixcoord / proxy / querynode / datanode / streamingnode
milvus stop standalone # graceful stop (sends SIGTERM via PID file)
Each role honors a gracefulStopTimeout; on timeout the process dumps goroutine/heap/block/
mutex pprof profiles to ProfileCfg.PprofPath and force-exits (cmd/components/util.go).
7.2 Health and readiness
GET /healthzon9091— liveness.- Component readiness is tracked internally; the Web UI and
GetComponentStatesexpose per-role health (Healthy/Abnormal/StandBy).
7.3 Monitoring
- Prometheus metrics at
:9091/metrics(Milvus registry) and/metrics_default(Go runtime). Build info, per-role metrics, meta/msgstream/storage metrics are registered at startup (cmd/roles/roles.go). - Grafana dashboards are provided under
deployments/monitor/. - OpenTelemetry tracing via
trace.exporter(jaeger/otlp); sampling viatrace.sampleFraction. - Access logs (
proxy.accessLog.*) record every request with method, status, user, latency, and trace ID; optionally uploaded to object storage. - Slow queries are flagged when they exceed
proxy.slowQuerySpanInSeconds(1 s) and shown in the Web UI.
7.4 The Web UI
Enabled by proxy.http.enableWebUI (default true) on :9091/webui — inspect collections,
segment distribution, query-node balance, slow queries, and component health.
7.5 Consistency check (mck)
milvus mck run scans etcd and object storage for orphaned task/segment references and
reports invalid tasks, segments, and missing object-storage paths; milvus mck cleanTrash
removes the orphaned entries (with backup to an mck-trash prefix). Flags: -etcdIp,
-etcdRootPath, -minioAddress, -minioUsername, -minioPassword, -minioUseSSL,
-minioBucketName.
Warning
mckmutates metadata. Run it against a quiesced cluster and keep the etcd backup it creates. It is a recovery tool, not routine maintenance.
7.6 Backup and restore
- RBAC:
BackupRBAC/RestoreRBAC(SDK) export/import the full access-control model. - Snapshots:
CreateSnapshot/RestoreSnapshotcapture and restore point-in-time collection data;dataCoord.snapshot.*governs retention and compaction protection. - Data: because data lives in object storage and metadata in etcd, a consistent backup pairs an etcd snapshot with the object-storage bucket. The community Milvus Backup tool automates this.
7.7 Upgrades and migration
cmd/tools/migration performs metadata migrations between Milvus versions
(deployments/migrate-meta/). DataCoord can rebuild segment indexes to a target index-engine
version (dataCoord.autoUpgradeSegmentIndex, targetVecIndexVersion,
forceRebuildSegmentIndex). Always back up etcd before a version upgrade and follow the
official rolling-upgrade procedure for clusters.
7.8 Change data capture (CDC) and replication
The cdc role and streaming.replication.* settings support replicating data between
clusters (internal/cdc/*). SDK surface: GetReplicateInfo, CreateReplicateStream,
UpdateReplicateConfiguration. Use for cross-region DR or migration.
8. Internals (Developer Reference)
8.1 Repository layout
| Path | Contents |
|---|---|
cmd/ |
Entry points: cmd/milvus (CLI), cmd/roles, cmd/components, cmd/tools/* |
internal/proxy |
The gateway: request validation, RBAC, rate limiting, result reduction |
internal/rootcoord |
DDL/DCL coordinator subsystem |
internal/datacoord |
Segment/data lifecycle, compaction, GC, index scheduling |
internal/querycoordv2 |
Query topology, load balancing, checkers/observers |
internal/querynodev2 |
Search/query execution, segment loading, delegators |
internal/datanode |
WAL consumption, flush, compaction, indexing |
internal/streamingnode, internal/streamingcoord |
WAL service and coordination |
internal/distributed/* |
gRPC servers/clients per role |
internal/core/src |
C++ Segcore + Knowhere bindings |
internal/storage, internal/storagev2 |
Binlog/segment serialization, object-storage chunk managers |
internal/metastore |
etcd/TiKV-backed metadata models and KV catalogs |
pkg/ |
Shared libraries: paramtable (config), proto (gRPC defs), streaming, mq, log, metrics, util/* |
client/ |
The official Go SDK (client/v2) |
8.2 Process orchestration
cmd/roles/roles.go:Run starts enabled components concurrently via conc.Future, waits for
all to be ready, registers them with the health subsystem and Prometheus, wires signal
handling for graceful shutdown, and tears down in order (coordinators → nodes → proxy →
shared etcd client). Config changes propagate through paramtable watchers on etcd.
8.3 API surface
The wire API is the gRPC milvuspb.MilvusService (defined in the external milvus-proto
repository) plus the REST v2 layer (internal/distributed/proxy/httpserver, paths
/v2/vectordb/<group>/<action>). The extraction TSVs only see test handlers; the real API is
the proto service and the SDK methods enumerated in the User Guide.
Note
Because the protobuf service definitions live in the separate
milvus-io/milvus-protorepository (vendored asgithub.com/milvus-io/milvus-proto/go-api/v3), the gRPC method list is not present in this repository's source. The authoritative client-visible surface is the Go SDK inclient/(and the equivalent pymilvus methods).
8.4 Key dependencies
From go.mod: go.etcd.io/etcd (metadata), minio-go + cloud SDKs (storage),
apache/pulsar-client-go (MQ), apache/arrow/go (columnar), antlr4-go (search-expression
parser), gin-gonic/gin (REST), casbin (RBAC), prometheus/client_golang (metrics),
go.opentelemetry.io/otel (tracing), grpc, tikv/client-go, cockroachdb/errors.
8.5 Build and test
make builds the Go binaries and C++ core. make verifiers runs linters; make unittest
runs unit tests. The dev environment is reproduced by the root docker-compose.yml (builder
image plus etcd/pulsar/minio/azurite/jaeger). Client linting uses a strict golangci-lint
config (client/.golangci.yml) that, for example, forbids the stdlib errors package in
favor of cockroachdb/errors.
9. Code Quality and Conventions
- Error handling uses a centralized
merrpackage (pkg/util/merr) producing a rich, catalogued error set (2,000+ messages) with codes — this is what surfaces to clients and feeds troubleshooting. - Config access is centralized in
paramtable; code reads typed accessors (.GetAsBool(),.GetAsInt(),.GetAsDuration()) rather than parsing YAML directly, enabling hot reload and type checking (common.enableConfigParamTypeCheck). - Concurrency uses
conc.Future/pools and structured goroutine management. - cgo boundaries are isolated in
*cgowrapperpackages with explicit lifetime management for the C++ core. - Linters are strict and enforced in CI (
make verifiers, ruleguard custom rules).
10. Potential Improvements / Operational Watch-list
These are observations for operators and contributors, drawn from configuration and code:
- Deprecated knobs remain in
milvus.yaml(e.g.queryNode.cache.memoryLimit,queryNode.segcore.multipleChunkedEnable,dataCoord.compaction.maxParallelTaskNum). Audit your config against the current defaults on upgrade rather than copying an old file forward. - Storage format is evolving —
dataNode.storage.formatsupportsparquet(default) andvortex;deltalogsupportsjson/parquet; Storage V2 (common.storage.stv2.*) anduseLoonFFIare newer paths. Pin and test the format before large migrations. - WAL choice matters — RocksMQ does not work in cluster mode; the project recommends Woodpecker for new installs. Migrating an existing cluster's WAL backend is non-trivial.
- Default credentials and disabled auth are the single biggest production risk; secure them before any network exposure.
- Memory-bound query nodes — without tiered storage/mmap tuning, large loaded collections
can exhaust RAM and trigger write throttling cluster-wide. Tune
queryNode.segcore.tieredStorage.*andqueryNode.mmap.*, and use resource groups for isolation.
11. Quick Reference
11.1 Default ports
| Port | Component | Purpose |
|---|---|---|
19530 |
Proxy | gRPC + REST client API |
19529 |
Proxy | Internal port |
9091 |
All | Health (/healthz), metrics (/metrics), Web UI (/webui) |
22125 |
RootCoord | gRPC |
19531 |
QueryCoord | gRPC |
13333 |
DataCoord | gRPC |
21123 |
QueryNode | gRPC |
21124 |
DataNode | gRPC |
22222 |
StreamingNode | gRPC |
2379 |
etcd | Metadata (external dep) |
9000 / 9001 |
MinIO | Storage / console (external dep) |
11.2 Essential commands
milvus run standalone # start all-in-one
milvus run mixcoord # start unified coordinator
milvus run proxy|querynode|datanode|streamingnode
milvus stop <server type> # graceful stop
milvus mck run -etcdIp <ip> ... # consistency check
milvus mck cleanTrash # clean orphaned data
curl -f http://localhost:9091/healthz # health probe
11.3 Critical config keys (change before first start)
| Key | Why |
|---|---|
common.security.authorizationEnabled |
Turn on auth |
common.security.defaultRootPassword |
Change from Milvus |
etcd.rootPath / msgChannel.chanNamePrefix.cluster |
Per-cluster isolation; immutable after data exists |
minio.bucketName / rootPath |
Per-cluster storage isolation |
mq.type |
Pick the WAL/MQ (Woodpecker recommended) |
tls.* / internaltls.* |
Enable transport security |
11.4 External dependency checklist
- [ ] etcd reachable at
etcd.endpoints(3+ nodes for HA) - [ ] Object storage reachable at
minio.address, bucket creatable/writable - [ ] WAL/MQ reachable (Pulsar/Kafka) or Woodpecker storage configured
- [ ] Auth enabled and root password changed
- [ ] TLS configured (external + internal)
- [ ] Prometheus scraping
:9091/metrics; Grafana dashboards loaded - [ ] Backups configured (etcd snapshot + object storage + RBAC export)