Milvus 架构深挖版
目标:把 Milvus 当前 master 分支里的真实架构拆开看清楚,尤其是控制面、数据面、WAL/streaming、存储和查询执行之间的关系。
1. 为什么说 Milvus 是“数据库系统”而不是“ANN 封装”
Milvus 真正解决的问题不是“给你一个 HNSW 接口”,而是这组系统问题:
- 如何持续接收 mutation
- 如何在近实时写入下保持可查
- 如何把新数据转成适合分布式加载和索引管理的物理块
- 如何做 segment 的放置、加载、均衡、恢复和重构
- 如何用统一的时间语义管理写入可见性
因此,如果用数据库术语去理解 Milvus,它的关键抽象是:
- catalog / metadata
- mutation log / WAL
- segment
- background maintenance
- query scheduling
- execution engine
2. 当前架构中的控制面:MixCoord 统一编排
2.1 MixCoord 是控制面容器
在 internal/coordinator/mix_coord.go 中,mixCoordImpl 直接持有:
rootcoordServerqueryCoordServerdatacoordServerstreamingCoord
这意味着当前控制面并不是“独立 RootCoord / DataCoord / QueryCoord 三个完全分离的 server 进程”这种最朴素形态,而是进程级聚合 + 模块级分层。
2.2 RootCoord:全局 metadata 与时序入口
RootCoord 的本质是系统级元数据主控。它负责:
- collection / partition / alias / schema DDL
- 全局 ID / timestamp 分配
- 某些 cache invalidation / service coordination
- 和 streaming / proxy / datacoord 等模块协同更新系统状态
如果类比数据库内核,它更接近 catalog manager + global timestamp service。
2.3 DataCoord:segment 生命周期控制器
DataCoord 是写路径里最核心的控制面模块之一。它关心的是:
- segment 什么时候是 growing / sealed / flushed
- 哪些 segment 该触发 index build
- 哪些 segment 需要 compaction
- flush checkpoint 和持久化状态如何维护
Milvus 的“数据库性”很大程度体现在 DataCoord 上:它把 mutation 和物理 segment 的管理做成了一个完整 subsystem。
2.4 QueryCoordV2:查询面资源调度器
QueryCoordV2 负责:
- load / release collection
- replica 管理
- channel / segment 分发
- 节点负载均衡
- 资源组与恢复
为什么它很重要?因为在分布式检索系统里,真正难的往往不是向量距离计算,而是:
- 数据该放在哪里
- 怎么在节点增减和失败时恢复
- 如何保障热点 collection 的吞吐与副本均衡
2.5 StreamingCoord:WAL 子系统控制面
StreamingCoord 是当前架构演进里非常关键的新角色。它负责:
- PChannel 到 StreamingNode 的分配
- 通道级健康管理
- DDL/DCL 的跨通道广播协调
- streaming service discovery 与控制面事务
它不是“边缘模块”,而是当前 mutation 事实源模型里的关键控制层。
3. 数据面:真正处理写入和查询的节点
3.1 Proxy:请求编排层
internal/proxy/task_insert.go 和 task_search.go 展示了 Proxy 的真正角色:
插入前处理包括:
- collection / schema 拉取
- request size 和合法性检查
- rowID 自动分配
- timestamp 填充
- dynamic field / namespace / struct field 处理
- schema timestamp / version 检查
查询前处理包括:
- collection schema 绑定
- partition / partition key 模式处理
- output fields 翻译
- guarantee timestamp / consistency level 推导
- advanced search / trace / ignore growing 等参数初始化
因此 Proxy 不是 dumb gateway,而是 用户请求语义转换层。
3.2 DataNode:mutation → segment buffer → flush
DataNode 负责:
- 消费 WAL/mq 中的 mutation
- 在内存中组织 growing segment
- 把缓冲数据转换成可 flush 的物理形式
- 生成 binlog / deltalog / statslog
- 上传对象存储
关键实现之一是 internal/flushcommon/writebuffer/write_buffer.go。
从 WriteBuffer 接口可以看到它支持:
CreateNewGrowingSegmentBufferDataSealSegmentsGetCheckpointEvictBufferSetFlushTimestamp
这说明 DataNode 内部有非常典型的“按 channel 组织的 mutable segment / flush buffer”结构。
3.3 QueryNodeV2:真正的查询执行节点
QueryNodeV2 一方面要加载 sealed segment 和已建好的索引,另一方面要把 growing segment 中尚未固化的数据纳入查询可见性。
其最核心抽象是 ShardDelegator:
- 维护 shard/vchannel 级状态
- 统一处理 sealed / growing / delete / tsafe
- 协调本地和远端查询执行
- 同步 partition stats 和 segment 分布
可以把它理解为 QueryNode 上的 per-shard runtime。它是 Milvus 查询系统最复杂、也最值钱的地方之一。
3.4 StreamingNode:WAL/PChannel 承载体
StreamingNode 负责:
- 管理一部分 PChannels
- 提供 append / read / tx / timetick 等 WAL 服务
- 参与恢复和 broadcaster ACK 路径
这一层使 mutation log 在系统里具备明确的“node identity”和“分片归属”。
4. WAL / MQ / Streaming:当前系统的事实源设计
4.1 配置层表明消息后端是可插拔的
configs/milvus.yaml 明确支持:
rocksmqpulsarkafkawoodpecker
并且对 standalone / cluster 模式给出不同默认优先级。说明 Milvus 的日志后端不是死板绑定的,而是抽象了一层统一 WAL / MQ 语义。
4.2 新 streaming 文档的中心思想
docs/agent_guides/streaming-system/streaming-system.md 的最关键一句话是:
Milvus uses a log-structured WAL as its single source of truth for all data mutations and metadata changes.
这件事意义很大。它表示:
- mutation 和一部分 metadata 变化都进入统一日志语义
- 其他系统状态可以被视为该日志的物化形式或恢复结果
4.3 PChannel / VChannel / CChannel 三层模型
- PChannel:物理分片,映射到 StreamingNode 和 backend topic
- VChannel:逻辑 shard,通常按 collection 的分片维度组织
- CChannel:控制通道,用于 cluster-wide ordering / control event
这使得:
- DML 可以按 append 模式进入具体物理通道
- DDL/DCL 可通过广播器跨多个 PChannel 原子提交
- streaming system 能同时表达物理分布和逻辑 collection shard
4.4 DML / DDL 的不同路径
文档中的数据流很清楚:
- DML:Client → Proxy → StreamingClient.Append → StreamingNode → WAL backend
- DDL/DCL:Client → Proxy → StreamingClient.Broadcast → StreamingCoord.Broadcaster → StreamingNodes → WAL backend
这背后的系统思想是:
- 普通数据 mutation 追求吞吐和顺序 append
- 控制类变更追求跨通道原子性和有序性
5. segment 生命周期:Milvus 的主轴
5.1 segment 是统一物理单元
无论是写入、索引、查询、调度还是 compaction,Milvus 几乎都以 segment 为基本物理单元。
5.2 生命周期大致可以理解为
- 创建 growing segment
- 接收 mutation
- sealed
- flush 到对象存储
- index build
- load 到 QueryNode
- 被 compaction / clustering / sort 重写
这个设计让 Milvus 具备两个关键能力:
- 近实时:growing segment 立即参与查询
- 高性能:sealed/indexed segment 提供高效 ANN 检索
5.3 为什么这个设计成立
如果所有数据都必须等索引建好才可查,Milvus 就失去实时性;如果所有数据都永远只在内存 growing 态里查,就失去成本和吞吐优势。Milvus 通过 dual-path:
- growing path
- sealed/indexed path
把 freshness 和 query efficiency 分开处理。
6. 存储层:metadata、对象存储、本地缓存
6.1 metadata:etcd / TiKV
配置里可以看到:
etcd用于 metadata 和 service discoverymetastore.type可切换到tikv
这意味着:
- etcd 仍是服务协调核心
- TiKV 被用来提升 metadata 扩展能力
6.2 对象存储:MinIO/S3 是持久化承载体
Milvus 把:
- binlog
- deltalog
- statslog
- index files
都落在对象存储上。这是计算存储分离的关键。
相关实现位于:
internal/storage/internal/core/src/storage/
6.3 localStorage:查询节点本地化缓冲
配置里的 localStorage.path 用于在 search/query 时减少对 MinIO/S3 的重复访问。说明 QueryNode 不会把对象存储当作低延迟在线存储,而是会把必要数据 materialize 到本地。
7. 查询架构深挖:为什么 QueryNodeV2 才是精华
7.1 QueryCoord 负责 placement
QueryCoordV2 决定:
- 哪些 segment / channel 去哪个节点
- 哪些 replica 服务这个 collection
- 扩缩容和节点故障后怎么恢复
7.2 QueryNodeV2 负责 execution state
真正复杂的状态组织在 QueryNodeV2。特别是 ShardDelegator 内部维护:
- sealed segment 分布
- growing segment
- delete buffer
- partition stats
- schema version
- catchingUpStreamingData
- latestRequiredMVCCTimeTick
这说明查询执行在 Milvus 里不是一个“直接查索引”的简单过程,而是一个 持续维护可见性、增量、负载和分布状态 的系统。
7.3 C++ segcore 是最终执行点
internal/core/src/segcore/segment_c.h 暴露的 C 接口包括:
NewSegmentSegmentLoadAsyncSegmentLoadAsyncSearchAsyncRetrieveInsertGetMemoryUsageInBytes
这几乎已经直接说明架构边界:
- Go 层 orchestrate
- C++ 层 execute
因此查询分析不能只停留在 Go 层,否则会错过真正的数据访问和检索内核。
8. 后台任务体系:compaction 不再是附属功能
internal/datacoord/compaction_trigger_v2.go 说明当前 Milvus 的 compaction 已经形成了一套策略系统,而不只是“小文件合并”。
当前触发类型包括:
- L0 delete compaction
- mix compaction
- clustering compaction
- sort compaction
- force merge
- storage version upgrade
- backfill compaction
并且有多个 ticker 周期性巡检。
这说明 Milvus 背后的长期维护逻辑已经在向成熟数据库系统靠近:
- 数据整理
- 删除清理
- 排序/聚类优化
- 版本升级重写
- 后台回填
9. Milvus 当前最值得研究的三个系统问题
问题 1:如何让 mutation log 真正成为系统事实源
Streaming 体系是这个答案的一部分。
问题 2:如何让 segment 同时服务写入、查询、索引和 compaction
segment lifecycle 是这个答案的核心。
问题 3:如何在近实时状态下做正确的分布式查询
QueryNodeV2 + QueryCoordV2 + ShardDelegator 是这个答案的核心。
10. 最后的压缩理解
如果要把当前 Milvus 压缩成一句工程判断:
Milvus 是一个以 WAL 驱动 mutation、以 segment 为物理核心、以对象存储承载持久化、以 QueryNodeV2/segcore 提供执行能力、以 MixCoord 聚合控制面的分布式 AI 检索数据库。