Milvus 源码精读版路线图

目标读者:已经熟悉数据库 / 存储系统概念,希望从架构实现角度系统理解 Milvus 的人。


总体策略

不要从 API 教程开始读,也不要一上来钻 ANN 算法。先看控制面和物理抽象,再看写路径和查询路径,最后下潜到 C++ segcore。

推荐分成 6 个阶段。


阶段 0:建立全局地图(半天)

必读文件

  1. /home/zouhaipeng/work/db/milvus/README.md
  2. /home/zouhaipeng/work/db/milvus/cmd/main.go
  3. /home/zouhaipeng/work/db/milvus/internal/types/types.go
  4. /home/zouhaipeng/work/db/milvus/configs/milvus.yaml

要回答的问题

  • 当前 Milvus 到底有哪些主要角色?
  • 默认是否启用了 streaming?
  • metadata / object store / mq 的外部依赖是什么?
  • Go 层的组件接口边界是什么?

读完后你应该得到的图

  • 入口层:cmd/
  • 组件边界:internal/types/types.go
  • 系统依赖:configs/milvus.yaml
  • 当前演进信号:streaming 默认开启

阶段 1:先看控制面骨架(1 天)

必读文件 / 目录

  1. internal/coordinator/mix_coord.go
  2. internal/distributed/mixcoord/service.go
  3. internal/rootcoord/
  4. internal/datacoord/
  5. internal/querycoordv2/
  6. internal/streamingcoord/

阅读顺序建议

  1. 先读 mix_coord.go 看启动和聚合关系
  2. 再看 rootcoorddatacoordquerycoordv2 各自负责什么
  3. 最后看 streamingcoord 在当前架构里的位置

阅读重点

  • 为什么 MixCoord 聚合了多个 coord
  • RootCoord 和 DataCoord / QueryCoord 的依赖关系
  • QueryCoordV2 管的到底是 segment、channel 还是 replica
  • streamingCoord 是否只是附属模块,还是控制面一等公民

阶段产出

你应该能画出“当前控制面真实拓扑图”。


阶段 2:吃透写路径(1~2 天)

主线问题

写入请求从客户端进入 Milvus 后,如何一步步变成 segment 和 binlog?

必读文件

  1. internal/proxy/task_insert.go
  2. internal/proxy/task_insert_streaming.go
  3. internal/datanode/
  4. internal/flushcommon/writebuffer/write_buffer.go
  5. internal/storage/
  6. docs/agent_guides/streaming-system/streaming-system.md

推荐读法

第一步:Proxy insert

task_insert.goPreExecute()

  • collection/schema 获取
  • request 校验
  • rowID 自动分配
  • timestamp 填充
  • schema version 检查
  • dynamic field 处理

要理解:Proxy 在写路径里不是简单转发,而是 mutation normalization 层。

第二步:streaming / wal

看 streaming 文档,理解:

  • DML append 路径
  • PChannel / VChannel / CChannel
  • StreamingClient / StreamingNode / StreamingCoord 的职责

第三步:WriteBuffer

重点读 write_buffer.go

  • CreateNewGrowingSegment
  • BufferData
  • SealSegments
  • GetCheckpoint
  • EvictBuffer

这是理解 DataNode 数据组织的关键。

第四步:存储格式

internal/storage/

  • binlog writer
  • data codec
  • chunk manager

这一阶段要回答的问题

  • growing segment 何时创建、何时 seal
  • flush checkpoint 怎么推进
  • mutation 是如何从 WAL 物化到对象存储的
  • DataNode 和 DataCoord 的职责边界在哪里

阶段 3:吃透查询路径(2 天)

主线问题

Search/query 请求如何从 Proxy 一路走到 QueryNodeV2,并同时覆盖 sealed/growing 数据?

必读文件

  1. internal/proxy/task_search.go
  2. internal/querycoordv2/server.go
  3. internal/querycoordv2/services.go
  4. internal/querycoordv2/meta/
  5. internal/querynodev2/server.go
  6. internal/querynodev2/services.go
  7. internal/querynodev2/delegator/delegator.go
  8. internal/querynodev2/segments/

推荐读法

task_search.goPreExecute()

  • collection / schema 绑定
  • partition / partition key 逻辑
  • output fields 翻译
  • consistency / guarantee timestamp
  • advanced search 初始化

第二步:QueryCoordV2

重点看:

  • load/release collection
  • replica 管理
  • segment/channel 分配
  • 资源组与均衡

第三步:QueryNodeV2

重点看:

  • node 服务接口
  • segment manager
  • watch channel / load segment 的流程

第四步:ShardDelegator

这是本阶段最重要的文件:delegator.go

读这个文件时重点标记:

  • Search
  • Query
  • ProcessInsert
  • ProcessDelete
  • LoadGrowing
  • LoadL0
  • SyncDistribution
  • UpdateTSafe
  • catchingUpStreamingData

这一阶段要回答的问题

  • QueryCoord 决定什么,QueryNode 决定什么
  • growing 和 sealed 数据怎么一起查
  • delete buffer、partition stats、tsafe 如何影响可见性
  • shard 级运行时是怎么维护的

阶段 4:下潜到执行内核(2~3 天)

主线问题

Milvus 真正的数据执行、segment load 和 search 内核在哪里?

必读目录

  1. internal/core/src/segcore/
  2. internal/core/src/index/
  3. internal/core/src/query/
  4. internal/core/src/storage/
  5. internal/core/src/segcore/segment_c.h

推荐读法

第一步:看 C 接口头文件

segment_c.h 入手,先建立边界:

  • NewSegment
  • SegmentLoad
  • AsyncSegmentLoad
  • AsyncSearch
  • AsyncRetrieve
  • Insert

这一步的目的是看清:Go 层到底把什么交给 C++。

第二步:segcore 内部对象

顺着 segment/load/search 相关类型往下追,看:

  • growing vs sealed segment
  • field / index load
  • memory accounting
  • search plan 执行

第三步:index 子系统

internal/core/src/index/,理解:

  • 向量索引封装
  • 标量索引
  • 倒排 / text match / bitmap / json 等能力

这一阶段要回答的问题

  • segment 在 C++ 层的内部表示是什么
  • search / retrieve 的执行入口在哪里
  • 索引和原始 field data 在执行时如何配合
  • Go 和 C++ 的真正边界在哪里

阶段 5:后台维护与长期演化(1~2 天)

主线问题

Milvus 如何维持长期稳定,而不是只跑通基础搜索?

必读文件

  1. internal/datacoord/compaction_trigger_v2.go
  2. internal/datacoord/compaction_task_*.go
  3. configs/milvus.yaml
  4. docs/agent_guides/streaming-system/ 下各子文档

阅读重点

  • 不同 compaction 类型和触发源
  • clustering / sort / backfill / storage version upgrade
  • woodpecker / kafka / pulsar / rocksmq 的位置
  • streaming 当前是否已成为主路径

这一阶段要回答的问题

  • compaction 为什么不是“简单 merge”
  • 后台维护如何影响查询和存储布局
  • 系统的长期演化方向是什么

阶段 6:对照官方资料,校正文档与现实(半天)

推荐对照材料

  • docs/developer_guides/chap01_system_overview.md
  • 官方文档 architecture_overview.md
  • GitHub README
  • release notes / blog

做什么

  • 哪些旧文档描述仍然成立
  • 哪些只代表历史设计
  • 当前源码已经演化到了哪里

最终产出

建议你自己写一张表:

主题旧文档说法当前源码事实备注
控制面独立 coordMixCoord 聚合当前实现优先
WALhash ring 叙事streaming/PChannel 叙事更关键两者有历史承接
查询节点query nodequerynodev2 + delegator当前复杂度显著提升

精读时的 12 个关键问题

  1. Milvus 为什么需要 MixCoord?
  2. RootCoord 的 timestamp / ID 分配语义是什么?
  3. DataCoord 如何维护 segment 生命周期?
  4. mutation 到 WriteBuffer 的关键状态转换是什么?
  5. flush checkpoint 的推进条件是什么?
  6. QueryCoordV2 的 replica / distribution 模型是什么?
  7. QueryNodeV2 为什么需要 ShardDelegator?
  8. growing / sealed / delete / tsafe 如何共同决定查询可见性?
  9. C++ segcore 和 Go 层如何分工?
  10. index build 为什么要异步化?
  11. compaction 有哪些系统级目标?
  12. streaming 为何被提升到 single source of truth 的地位?

最终推荐阅读顺序(压缩版)

  1. README.md
  2. cmd/main.go
  3. internal/types/types.go
  4. internal/coordinator/mix_coord.go
  5. internal/proxy/task_insert.go
  6. internal/flushcommon/writebuffer/write_buffer.go
  7. internal/proxy/task_search.go
  8. internal/querycoordv2/
  9. internal/querynodev2/delegator/delegator.go
  10. internal/core/src/segcore/segment_c.h
  11. internal/core/src/segcore/
  12. internal/datacoord/compaction_trigger_v2.go
  13. docs/agent_guides/streaming-system/streaming-system.md
  14. configs/milvus.yaml

一句话建议

先把 Milvus 当成数据库系统读,再把它当成向量检索系统读;不要反过来。