第 3 篇 把数据切成 Growing / Sealed;第 5 篇 说明 Streaming Node 上的 Query Delegator 负责 shard 级增量查询。仍缺一环:Sealed 段在 Query Node 上如何被加载并执行段级 search,以及它与 Knowhere 索引内核的边界。
本文以官方 Data Processing、Architecture Overview、Streaming Service、Knowhere 为准,描述查询数据面。不展开索引类型参数(第 8 篇),不展开跨 shard reduce 的全部细节(第 9 篇)。
本文是「向量检索引擎」系列第 7 篇(共 18 篇)。→ 系列目录
版本锚定:Milvus 2.6.x。文中「Segcore」指 Milvus 用于 segment 级向量/标量执行 的 C++ 核心层(与 Go 控制面、Knowhere 索引库分层);段生命周期与查询流以官方 Data Processing 叙述为 A 级依据。
一、谁回答一次
search?
官方把 Collection 上的查询定义为:在指定集合中找与目标向量最近的 \(k\) 个向量,或距离阈值内的全部向量,并返回主键与字段。
物理上:
| 数据 | 持有者 | 角色 |
|---|---|---|
| Growing segments | Streaming Node | 实时、可变 |
| Sealed segments | Query Node(从对象存储加载) | 历史、不可变 |
Proxy 并不自己扫所有段;它把请求交到相关 shard 的 Streaming Node。每个 Streaming Node 上的 Query Delegator:
- 生成查询计划;
- 本地搜索 Growing;
- 联系持有相关 Sealed 的 Query Node 取历史结果;
- 聚合成该 shard 的结果。
Proxy 再合并各 shard 结果。Architecture 的 search 示例流与此一致:多级 reduce——Query Node 跨多 segment 归并 → Streaming Node 归并 Query Node 结果 → Proxy 归并各 Streaming Node。
flowchart TB
client["Client search"]
proxy["Proxy"]
sn["Streaming Node<br/>Delegator + Growing"]
qn["Query Node<br/>Sealed segments"]
client --> proxy --> sn
sn -->|"segment search"| qn
sn -->|"shard reduce"| proxy
二、Query Node:历史数据面
Architecture 对 Query Node 的定义很短:从对象存储加载历史数据,并提供历史数据查询。结合 Data Processing 与 handoff:
- Growing flush 成 Sealed,或 Data Node compaction 完成后,Coordinator handoff。
- Coordinator 在 Query Node 间分配 Sealed,平衡内存、CPU、segment 数,释放冗余。
- Query Node 按需从对象存储加载段数据(及索引,见第 8、10 篇),执行 segment-level search。
- 新建索引加载后,替换对应的增长数据视图(Architecture 插入流)。
Query Node 被描述为存算分离下的 无状态 Worker(状态在对象存储与元数据中):扩缩与故障恢复依赖重新加载 segment,而不是本地磁盘上的可变页缓存语义(与经典 RDBMS buffer pool 不同)。
三、Segcore:段级执行层(相对 Knowhere)
官方 Knowhere 文档给出垂直分层:
- 最底:硬件;
- 其上:第三方索引库(Faiss、Hnswlib、Annoy 等);
- Knowhere:选择在 CPU/GPU 上执行索引构建与搜索,并对接索引/查询路径;
- 通过 CGO,Go 包调用 C/C++ 代码。
在这套分层里,段(segment)是查询与写入的数据单元,索引是段上的加速结构。工程上 Milvus 用 Segcore 表达「一个 segment 内的列式/向量数据 + 检索/过滤执行」;Knowhere 则 只处理向量索引相关计算(Knowhere 文档原话:Knowhere only handles the operations on vector indexing)。
官方 queryNode-related Configurations
将多项参数挂在 queryNode.segcore.* 下(例如
chunkRows:Segcore 把 segment 再切成 chunk
的行数,默认 128;以及 interim index 的 nlist /
nprobe 等),从配置面确认 Query Node
的段执行子系统就叫 Segcore,并与 Knowhere
线程池比例等开关并列。仓库内另有 Segcore Search 设计文档描述
Boolean 表达式 → bitset → 向量引擎的访问者模式(B
级设计笔记,实现细节以当前 release 源码为准)。
本系列采用如下可核对边界(与官方分层与配置命名一致,不展开未稳定的私有符号表):
| 层 | 负责 | 不负责 |
|---|---|---|
| Proxy / Coordinator / Delegator | 路由、计划、归并、拓扑 | 单个向量距离循环的细节 |
| Segcore(段执行) | 段内 search/query 编排、与标量字段/删除位图协作 | 跨 shard 调度 |
| Knowhere | 向量索引 Train/Query、SIMD/GPU 后端 | Collection 级 DDL |
软删与 bitset 的协作在 Knowhere 文档中写明:Milvus 用 bitset 实现软删,Knowhere 把 bitset 应用到暴露的索引查询 API——段执行层必须把「哪些行仍可见」交给索引查询。细节见官方 Bitset 与第 13 篇。
四、Growing 路径 vs Sealed 路径
| 维度 | Growing(Streaming Node) | Sealed(Query Node) |
|---|---|---|
| 数据位置 | 节点内存侧增长结构 + WAL 已提交 | 对象存储快照,加载到 Query Node |
| 索引 | 实时路径优先保证可搜;重索引在封段后由 Data Node 做 | 每段可有独立向量/标量/主键索引 |
| 可变性 | 追加、删除广播影响可见性 | 不可变;替换靠 compaction + handoff |
| 失败模式 | WAL 迁移、Wait for Ready | 加载失败、内存不足以容纳段/索引 |
一次用户可见的 search 必须在 Delegator 侧
合并两类候选。若只测 Sealed、忽略
Growing,会在持续写入场景下得到偏乐观的延迟与偏悲观的新鲜度。
五、段级归并:本篇只需记住的接口直觉
在单个 Query Node 上,一次请求可能覆盖 多个 Sealed segment。Architecture 写明 Query Node 先做跨 segment 的 reduce,再交给 Streaming Node。实现上等价于:
- 对每个相关 segment 调用段级 search(经 Segcore → Knowhere);
- 按距离(或评分)合并 Top-\(k\);
- 应用一致性与删除可见性约束(第 12–13 篇)。
跨 Query Node、跨 shard 的归并留给第 9
篇;本篇强调:ANN 库一次 search ≠
Milvus 一次
search——后者是分布式段候选的归并树。
六、学术谱系、工程间隙、开放问题
6.1 谱系
| 阶段 | 内容 |
|---|---|
| 静态 ANN | 单索引结构上的近似 Top-\(k\) |
| 向量 DBMS | SIGMOD 2021 Milvus:动态数据 + 异构执行(Knowhere) |
| 2.6 数据面 | Growing/Sealed 分流 + Delegator 拼装一次查询 |
段级执行让「动态更新」与「不可变索引」可以并存:更新打在 Growing/删除 bitset,重型图索引建在 Sealed 上。
6.2 工程间隙
- 文档层的 Query Node「按需加载」在生产中受内存与加载并发限制;handoff 后瞬时延迟尖刺常见于冷段加载(第 17 篇)。
- Knowhere 文档中的 AVX512「相对 AVX2 提升 20%–30%」是 官方对 Knowhere 的陈述,本篇不转为「你的集群一定快 25%」。
- Segcore 与 Go 控制面的 CGO 边界带来调试复杂度:延迟尖刺要区分在 Delegator、加载、还是 Knowhere Query。
6.3 开放问题
- 多副本下 Delegator 与 Query Node 的调度如何最小化跨节点往返(第 14 篇)?
- 极高过滤选择性时,段级执行应先滤后搜还是先搜后滤——算法争论见 frontier/09,引擎路径见第 11 篇。
- GPU Knowhere 路径下,段加载与设备内存的编排是否与 CPU 段缓存同构?
七、小结
Query Node 服务 Sealed 历史;Streaming
Node 服务 Growing 实时;Delegator
把两者拼成 shard 结果。Segcore 是段级执行层,Knowhere
是向量索引内核——一次 Milvus search
是二者之上的分布式归并,而不是单次 FAISS 调用。
下一篇进入索引内核:Knowhere。
参考资料
- Milvus Documentation v2.6.x, Data Processing(data query、handoff)。
- Milvus Documentation v2.6.x, Architecture Overview(Query Node、search 多级 reduce)。
- Milvus Documentation v2.6.x, Streaming Service(Query Delegator)。
- Milvus Documentation v2.6.x, Knowhere(分层、CGO、bitset、只处理向量索引运算)。
- Milvus Documentation v2.6.x, queryNode-related
Configurations(
queryNode.segcore.*配置面)。 - milvus-io/milvus, docs/design-docs/…/segcore/Search.md(Segcore 搜索与表达式 bitset;B 级设计笔记)。
- Wang et al., SIGMOD 2021(异构执行与动态向量数据动机)。
- 第 3 篇、第 5 篇、系列 index。
返回 系列目录 | 上一篇:Streaming 与 WAL | 下一篇:Knowhere
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【向量检索引擎】Collection · Partition · Segment · Channel:Growing 到 Sealed 的状态机
钉住 Milvus 2.6.x 的数据模型词汇:Collection/Partition、vchannel/pchannel 与 Streaming Node 绑定,Growing/Sealed 段类型、flush 与 handoff,为后续写路径与读路径提供共同状态机。
【向量检索引擎】向量引擎全景:算法、RAG 与专用引擎之间的一层
定位专用向量检索引擎相对 ANN 算法、RAG 应用与湖仓格式的分工;以 Milvus 2.6.x 四层架构给出本系列 18 篇地图,并交代从 SIGMOD 2021 系统论文到存算分离演进的谱系。
【向量检索引擎】分布式 search 归并:Delegator、多级 reduce 与 GuaranteeTs
按 Milvus 2.6.x Data Processing 与 Architecture 拆解 search 的多级归并树:Proxy → Streaming Node Delegator → Query Node 段级结果;说明 shard 并发、Top-k 合并直觉,以及 GuaranteeTs/ServiceTime 如何让一致性变成等待。
【向量检索引擎】Data Node:compaction 与 index build
说明 Milvus 2.6.x 中 Data Node 作为离线 Worker 如何承接 Coordinator 下发的建索引与 compaction,输入输出如何进出对象存储,以及索引堆积与 handoff 如何影响查询新鲜度与资源争用。