MixCoord / QueryCoordV2 / QueryNodeV2 三者交互图
目标:把 Milvus 当前控制面和查询面的三个关键角色——MixCoord、QueryCoordV2、QueryNodeV2——如何协作讲清楚。
1. 为什么单独看这三者
如果说 Milvus 最关键的控制链条是什么,我会选:
- MixCoord:控制面总入口 / 聚合容器
- QueryCoordV2:查询资源调度器
- QueryNodeV2:查询执行节点
这三者共同回答了两个问题:
- 哪些数据应该被谁服务?
- 这些数据如何真正被查到?
2. 先看角色定位
2.1 MixCoord:控制面顶层聚合
在当前实现中,MixCoord 聚合了:
- RootCoord
- DataCoord
- QueryCoordV2
- StreamingCoord
它更像一个控制面容器,而不是“一个新功能模块”。
它的价值
- 统一控制面初始化和存活管理
- 统一 metadata 依赖(etcd/TiKV/session)
- 把多个 coordinator 组合成一个进程级服务面
2.2 QueryCoordV2:查询资源与 placement 控制器
QueryCoordV2 不做真正的向量搜索,但它决定:
- 哪些 QueryNode 应该持有哪些 collection/segment/channel
- replica 怎么布局
- load/release 如何执行
- 如何做 rebalance 和 failover
2.3 QueryNodeV2:查询执行节点
QueryNodeV2 是真正执行 search/query 的节点。它需要:
- 接受 load segment / watch channel 等控制操作
- 保持 growing / sealed 数据都可见
- 用 ShardDelegator 管理每个 vchannel/shard 的执行状态
3. 最核心的交互图
+------------------+
| MixCoord |
|------------------|
| RootCoord |
| DataCoord |
| QueryCoordV2 |
| StreamingCoord |
+---------+--------+
|
| 控制面指令 / metadata / placement
v
+------------------+
| QueryCoordV2 |
|------------------|
| load/release |
| replica mgmt |
| segment/channel |
| balance / failover|
+---------+--------+
|
| 下发 load / watch / sync distribution
v
+------------------+
| QueryNodeV2 |
|------------------|
| ShardDelegator |
| SegmentManager |
| segcore execute |
+------------------+4. MixCoord 和 QueryCoordV2 的关系
4.1 MixCoord 中实际嵌入 QueryCoordV2
在 internal/coordinator/mix_coord.go 里:
queryCoordServer *querycoordv2.Server
这说明 QueryCoordV2 并不是外部附属模块,而是当前 MixCoord 控制面里的一部分。
4.2 启动顺序说明依赖关系
在 mix_coord.go 的 initInternal() 中,大致顺序是:
- 启动 streaming coord
- 初始化并启动 rootcoord
- 并行初始化 dataCoord 和 queryCoord
这说明:
- QueryCoordV2 的生命周期受 MixCoord 管理
- RootCoord ready 是 QueryCoordV2 正常工作的前置条件之一
4.3 你该怎么理解
MixCoord 负责把“全局 metadata / coord 体系”拉起来, QueryCoordV2 则是在这个全局控制面里专门负责 query placement 的模块。
5. QueryCoordV2 和 QueryNodeV2 的关系
这是控制面到执行面的核心接口。
5.1 QueryCoordV2 对 QueryNodeV2 发什么类型的指令
典型包括:
- LoadCollection / LoadPartitions
- ReleaseCollection / ReleasePartitions
- Watch / unwatch channel
- segment distribution sync
- rebalance / move 操作
- replica 相关同步
5.2 QueryCoordV2 的视角是什么
QueryCoordV2 看的是“全局放置图”——
- 哪些 node 存活
- 哪些 collection 已 load
- 哪些 segment 在哪个 replica / node 上
- 哪些 channel 被哪个 QueryNode watch
它不是“数据执行者”,而是“数据服务拓扑管理者”。
5.3 QueryNodeV2 的视角是什么
QueryNodeV2 看的是“本地执行图”——
- 我本机持有哪些 sealed segments
- 我维护哪些 growing segments
- 我 watch 哪些 channel
- 每个 shard 的 tsafe 是多少
- delete buffer 有多少
- partition stats 怎么更新
所以:
- QueryCoordV2 负责 global placement
- QueryNodeV2 负责 local execution state
6. QueryNodeV2 内部的真正执行中心:ShardDelegator
6.1 为什么它是 QueryNode 的灵魂
在 internal/querynodev2/delegator/delegator.go 中,ShardDelegator 接口承担:
SearchQueryProcessInsertProcessDeleteLoadGrowingLoadSegmentsSyncDistributionSyncPartitionStatsUpdateTSafe
这说明 QueryNode 不是“持有一堆 segment 的壳”,而是由多个 ShardDelegator 组成的 shard 级执行系统。
6.2 它和 QueryCoordV2 的互动
QueryCoordV2 的 placement 决策,最终要落到 QueryNodeV2 上形成具体状态,而这个具体状态主要就体现在:
- 哪些 shardDelegator 被创建/销毁
- 哪些 segments 被分配给它们
- 哪些 distribution / stats 被同步
所以你可以把 QueryCoordV2 → QueryNodeV2 看成:
global metadata placement → local shard runtime realization
7. 三者协作的几个典型场景
场景 A:LoadCollection
Client / Proxy
↓
MixCoord 中的 QueryCoordV2 接到 load collection
↓
查询 metadata / replica / node 状态
↓
决定哪些 QueryNodeV2 负责哪些 segment / channel
↓
向对应 QueryNodeV2 下发 load/watch 指令
↓
QueryNodeV2 建立或更新 ShardDelegator
↓
加载 sealed segment,接入 growing channel关键点
- MixCoord 提供全局控制面环境
- QueryCoordV2 做放置和副本决策
- QueryNodeV2 负责把这些决策变成真实可查询状态
场景 B:节点故障恢复
某 QueryNodeV2 故障
↓
QueryCoordV2 感知 node 不可用
↓
重新计算 replica / segment / channel 放置
↓
其他 QueryNodeV2 接管 segment/channel
↓
新的 ShardDelegator / distribution 生效关键点
真正保证服务连续性的,不是 ANN 算法,而是这套 placement 恢复机制。
场景 C:实时查询中的 growing 数据可见
新 mutation 进入 WAL
↓
QueryNodeV2 相关 shard 持续消费 / catch up streaming data
↓
ShardDelegator 更新 growing state 和 tsafe
↓
查询时 sealed + growing 一起回答关键点
这里 QueryCoordV2 不直接参与每一条增量执行,但它负责宏观的 shard/channel 放置和 watch 拓扑。
8. 为什么 MixCoord 的存在会改变理解方式
如果没有 MixCoord,你可能会简单理解成:
- RootCoord / DataCoord / QueryCoord 各自是独立服务
但当前实现更像:
- 控制面在进程级被整合到 MixCoord
- 模块之间的依赖和初始化路径更紧密
- QueryCoordV2 是 MixCoord 内部的一部分,而不是“系统外的一层”
这会影响你读源码时的路径选择:
- 先从
mix_coord.go建图 - 再分别下钻
rootcoord/datacoord/querycoordv2 - 不要一开始就假设它们是完全分裂的外部微服务
9. 最值得追的源码路径
第一层:控制面总图
internal/coordinator/mix_coord.gointernal/distributed/mixcoord/service.go
第二层:QueryCoordV2
internal/querycoordv2/server.gointernal/querycoordv2/services.gointernal/querycoordv2/meta/
第三层:QueryNodeV2
internal/querynodev2/server.gointernal/querynodev2/services.gointernal/querynodev2/delegator/delegator.gointernal/querynodev2/segments/
10. 压缩总结
用最短的话讲三者关系
- MixCoord:把控制面拉起来并统一承载 QueryCoordV2 等模块
- QueryCoordV2:决定“谁应该服务哪些数据”
- QueryNodeV2:把这个决策变成“这个 shard 现在真的可查”
再压缩成一句话
MixCoord 提供控制面宿主,QueryCoordV2 维护查询放置图,QueryNodeV2 通过 ShardDelegator 把放置图落实成真实的 shard 级查询执行状态。