Milvus 架构设计:从向量索引到分布式检索,AI 原生存储引擎的内部机制

引言:AI 原生时代的向量数据库

在人工智能应用爆炸式增长的今天,非结构化数据(如图片、视频、音频、文本)的处理成为核心挑战。传统的关系型数据库擅长处理结构化数据,但对高维向量数据的存储、索引和检索却力不从心。Milvus 作为一款开源的向量数据库,专为 AI 应用而生,其架构设计深刻体现了"AI 原生"的理念------从底层存储到上层查询,都围绕向量数据的高效处理而构建。

本文将深入剖析 Milvus 的架构设计,揭示其如何将向量索引、分布式存储与检索、流批一体等复杂技术融合,构建出一个高性能、可扩展的 AI 数据基础设施。

1. 整体架构概览:解耦与协同

Milvus 采用云原生、分层解耦的架构设计,其核心思想是将系统的不同职责(存储、计算、索引、协调)分离,通过标准接口进行通信。这种设计带来了极高的灵活性和可扩展性。

1.1 系统组件构成

Milvus 2.x 版本主要由以下核心组件构成:

  • 接入层 (Access Layer): 提供统一的 RESTful 和 gRPC 接口,负责接收客户端请求,并进行负载均衡和协议转换。
  • 协调服务 (Coordinator Service) : 系统的"大脑",负责集群元数据管理、负载均衡、任务调度与故障恢复。它进一步细分为:
    • 根协调器 (Root Coordinator): 管理数据库、集合、分区的元数据(DDL 操作)。
    • 查询协调器 (Query Coordinator): 管理查询节点的负载均衡与故障转移。
    • 数据协调器 (Data Coordinator): 管理数据节点的数据刷新、压缩与均衡。
    • 索引协调器 (Index Coordinator): 管理索引的构建与维护任务。
  • 工作节点 (Worker Nodes) : 系统的"四肢",负责实际的数据处理:
    • 查询节点 (Query Node): 执行向量和标量数据的检索(查询)操作。
    • 数据节点 (Data Node): 处理数据的插入、删除,并将日志数据持久化到对象存储。
    • 索引节点 (Index Node): 专门负责构建和管理向量索引。
  • 存储层 (Storage) : 持久化数据的基石,采用日志即数据 (Log-as-Data) 模型:
    • 元存储 (Meta Store): 通常使用 etcd 或 MySQL,存储集合、分区、索引结构等元数据。
    • 对象存储 (Object Storage): 如 AWS S3、Azure Blob、MinIO,用于持久化向量和标量数据文件。
    • 消息队列 (Message Queue): 如 Pulsar、Kafka,作为系统的发布-订阅日志总线,用于实时数据传输与同步。

#mermaid-svg-MCJdo1qO3i4oCbHk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MCJdo1qO3i4oCbHk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MCJdo1qO3i4oCbHk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MCJdo1qO3i4oCbHk .error-icon{fill:#552222;}#mermaid-svg-MCJdo1qO3i4oCbHk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MCJdo1qO3i4oCbHk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MCJdo1qO3i4oCbHk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MCJdo1qO3i4oCbHk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MCJdo1qO3i4oCbHk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MCJdo1qO3i4oCbHk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MCJdo1qO3i4oCbHk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MCJdo1qO3i4oCbHk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MCJdo1qO3i4oCbHk .marker.cross{stroke:#333333;}#mermaid-svg-MCJdo1qO3i4oCbHk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MCJdo1qO3i4oCbHk p{margin:0;}#mermaid-svg-MCJdo1qO3i4oCbHk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MCJdo1qO3i4oCbHk .cluster-label text{fill:#333;}#mermaid-svg-MCJdo1qO3i4oCbHk .cluster-label span{color:#333;}#mermaid-svg-MCJdo1qO3i4oCbHk .cluster-label span p{background-color:transparent;}#mermaid-svg-MCJdo1qO3i4oCbHk .label text,#mermaid-svg-MCJdo1qO3i4oCbHk span{fill:#333;color:#333;}#mermaid-svg-MCJdo1qO3i4oCbHk .node rect,#mermaid-svg-MCJdo1qO3i4oCbHk .node circle,#mermaid-svg-MCJdo1qO3i4oCbHk .node ellipse,#mermaid-svg-MCJdo1qO3i4oCbHk .node polygon,#mermaid-svg-MCJdo1qO3i4oCbHk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MCJdo1qO3i4oCbHk .rough-node .label text,#mermaid-svg-MCJdo1qO3i4oCbHk .node .label text,#mermaid-svg-MCJdo1qO3i4oCbHk .image-shape .label,#mermaid-svg-MCJdo1qO3i4oCbHk .icon-shape .label{text-anchor:middle;}#mermaid-svg-MCJdo1qO3i4oCbHk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MCJdo1qO3i4oCbHk .rough-node .label,#mermaid-svg-MCJdo1qO3i4oCbHk .node .label,#mermaid-svg-MCJdo1qO3i4oCbHk .image-shape .label,#mermaid-svg-MCJdo1qO3i4oCbHk .icon-shape .label{text-align:center;}#mermaid-svg-MCJdo1qO3i4oCbHk .node.clickable{cursor:pointer;}#mermaid-svg-MCJdo1qO3i4oCbHk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MCJdo1qO3i4oCbHk .arrowheadPath{fill:#333333;}#mermaid-svg-MCJdo1qO3i4oCbHk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MCJdo1qO3i4oCbHk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MCJdo1qO3i4oCbHk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MCJdo1qO3i4oCbHk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MCJdo1qO3i4oCbHk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MCJdo1qO3i4oCbHk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MCJdo1qO3i4oCbHk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MCJdo1qO3i4oCbHk .cluster text{fill:#333;}#mermaid-svg-MCJdo1qO3i4oCbHk .cluster span{color:#333;}#mermaid-svg-MCJdo1qO3i4oCbHk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MCJdo1qO3i4oCbHk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MCJdo1qO3i4oCbHk rect.text{fill:none;stroke-width:0;}#mermaid-svg-MCJdo1qO3i4oCbHk .icon-shape,#mermaid-svg-MCJdo1qO3i4oCbHk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MCJdo1qO3i4oCbHk .icon-shape p,#mermaid-svg-MCJdo1qO3i4oCbHk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MCJdo1qO3i4oCbHk .icon-shape .label rect,#mermaid-svg-MCJdo1qO3i4oCbHk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MCJdo1qO3i4oCbHk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MCJdo1qO3i4oCbHk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MCJdo1qO3i4oCbHk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 存储层
工作节点
协调服务
接入层
客户端
查询流
SDK/CLI
Web UI
代理服务
根协调器
查询协调器
数据协调器
索引协调器
查询节点
数据节点
索引节点
元存储 etcd
对象存储 S3
消息队列 Pulsar

图:Milvus 2.x 架构组件与数据流示意图

1.2 数据流与读写路径

理解架构的关键是追踪数据的生命周期:

  1. 写入路径:客户端插入数据 -> 代理服务 -> 消息队列(作为预写日志 WAL)-> 数据节点消费日志 -> 数据节点将数据打包成段(Segment)并上传至对象存储 -> 通知协调器更新元数据。
  2. 查询路径:客户端发起查询 -> 代理服务 -> 查询协调器分配查询节点 -> 查询节点从对象存储加载相关数据段和索引 -> 执行检索运算 -> 返回结果。

这种将计算与存储分离日志驱动的架构,使得 Milvus 能够独立扩展计算资源(节点)和存储资源,并天然支持数据的多副本与高可用。
#mermaid-svg-yslCzNePoqS0g9NU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yslCzNePoqS0g9NU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yslCzNePoqS0g9NU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yslCzNePoqS0g9NU .error-icon{fill:#552222;}#mermaid-svg-yslCzNePoqS0g9NU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yslCzNePoqS0g9NU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yslCzNePoqS0g9NU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yslCzNePoqS0g9NU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yslCzNePoqS0g9NU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yslCzNePoqS0g9NU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yslCzNePoqS0g9NU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yslCzNePoqS0g9NU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yslCzNePoqS0g9NU .marker.cross{stroke:#333333;}#mermaid-svg-yslCzNePoqS0g9NU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yslCzNePoqS0g9NU p{margin:0;}#mermaid-svg-yslCzNePoqS0g9NU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yslCzNePoqS0g9NU .cluster-label text{fill:#333;}#mermaid-svg-yslCzNePoqS0g9NU .cluster-label span{color:#333;}#mermaid-svg-yslCzNePoqS0g9NU .cluster-label span p{background-color:transparent;}#mermaid-svg-yslCzNePoqS0g9NU .label text,#mermaid-svg-yslCzNePoqS0g9NU span{fill:#333;color:#333;}#mermaid-svg-yslCzNePoqS0g9NU .node rect,#mermaid-svg-yslCzNePoqS0g9NU .node circle,#mermaid-svg-yslCzNePoqS0g9NU .node ellipse,#mermaid-svg-yslCzNePoqS0g9NU .node polygon,#mermaid-svg-yslCzNePoqS0g9NU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yslCzNePoqS0g9NU .rough-node .label text,#mermaid-svg-yslCzNePoqS0g9NU .node .label text,#mermaid-svg-yslCzNePoqS0g9NU .image-shape .label,#mermaid-svg-yslCzNePoqS0g9NU .icon-shape .label{text-anchor:middle;}#mermaid-svg-yslCzNePoqS0g9NU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yslCzNePoqS0g9NU .rough-node .label,#mermaid-svg-yslCzNePoqS0g9NU .node .label,#mermaid-svg-yslCzNePoqS0g9NU .image-shape .label,#mermaid-svg-yslCzNePoqS0g9NU .icon-shape .label{text-align:center;}#mermaid-svg-yslCzNePoqS0g9NU .node.clickable{cursor:pointer;}#mermaid-svg-yslCzNePoqS0g9NU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yslCzNePoqS0g9NU .arrowheadPath{fill:#333333;}#mermaid-svg-yslCzNePoqS0g9NU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yslCzNePoqS0g9NU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yslCzNePoqS0g9NU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yslCzNePoqS0g9NU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yslCzNePoqS0g9NU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yslCzNePoqS0g9NU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yslCzNePoqS0g9NU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yslCzNePoqS0g9NU .cluster text{fill:#333;}#mermaid-svg-yslCzNePoqS0g9NU .cluster span{color:#333;}#mermaid-svg-yslCzNePoqS0g9NU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yslCzNePoqS0g9NU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yslCzNePoqS0g9NU rect.text{fill:none;stroke-width:0;}#mermaid-svg-yslCzNePoqS0g9NU .icon-shape,#mermaid-svg-yslCzNePoqS0g9NU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yslCzNePoqS0g9NU .icon-shape p,#mermaid-svg-yslCzNePoqS0g9NU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yslCzNePoqS0g9NU .icon-shape .label rect,#mermaid-svg-yslCzNePoqS0g9NU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yslCzNePoqS0g9NU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yslCzNePoqS0g9NU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yslCzNePoqS0g9NU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 查询路径
写入路径
元数据同步
客户端插入数据
代理服务
消息队列

(预写日志 WAL)
数据节点消费日志
打包成段 Segment
上传至对象存储
通知协调器更新元数据
客户端发起查询
代理服务
查询协调器分配查询节点
查询节点加载数据段和索引
执行检索运算
返回结果

图:Milvus 数据写入与查询路径示意图

2. 存储引擎:日志即数据与分层存储

Milvus 的存储设计是其高可靠性与高性能的基石,核心是 "日志即数据 (Log-as-Data)" 模型。

2.1 日志即数据模型

  • 所有数据变更首先作为一条日志记录发布到消息队列(如 Pulsar)。这条日志包含了插入、删除操作的完整信息。
  • 数据节点作为日志的消费者,顺序消费这些日志,将其在内存中组装成有序的数据结构。
  • 当积累的数据达到一定阈值(如时间、行数),数据节点会将这些数据持久化 到对象存储中,形成一个不可变的数据段 (Segment)
  • 元数据中会记录每个段对应的日志位置。因此,从任意时间点恢复数据,只需要从对应的日志位置开始重放即可。

这种设计带来了显著优势:

  • 强一致性:通过日志的顺序性保证。
  • 高吞吐写入:日志追加写入非常高效。
  • 容灾与恢复:存储成本低廉的对象存储保存数据,消息队列保存操作日志,故障恢复速度快。

#mermaid-svg-MWXPtWo2kknPMnhs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MWXPtWo2kknPMnhs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MWXPtWo2kknPMnhs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MWXPtWo2kknPMnhs .error-icon{fill:#552222;}#mermaid-svg-MWXPtWo2kknPMnhs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MWXPtWo2kknPMnhs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MWXPtWo2kknPMnhs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MWXPtWo2kknPMnhs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MWXPtWo2kknPMnhs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MWXPtWo2kknPMnhs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MWXPtWo2kknPMnhs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MWXPtWo2kknPMnhs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MWXPtWo2kknPMnhs .marker.cross{stroke:#333333;}#mermaid-svg-MWXPtWo2kknPMnhs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MWXPtWo2kknPMnhs p{margin:0;}#mermaid-svg-MWXPtWo2kknPMnhs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MWXPtWo2kknPMnhs .cluster-label text{fill:#333;}#mermaid-svg-MWXPtWo2kknPMnhs .cluster-label span{color:#333;}#mermaid-svg-MWXPtWo2kknPMnhs .cluster-label span p{background-color:transparent;}#mermaid-svg-MWXPtWo2kknPMnhs .label text,#mermaid-svg-MWXPtWo2kknPMnhs span{fill:#333;color:#333;}#mermaid-svg-MWXPtWo2kknPMnhs .node rect,#mermaid-svg-MWXPtWo2kknPMnhs .node circle,#mermaid-svg-MWXPtWo2kknPMnhs .node ellipse,#mermaid-svg-MWXPtWo2kknPMnhs .node polygon,#mermaid-svg-MWXPtWo2kknPMnhs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MWXPtWo2kknPMnhs .rough-node .label text,#mermaid-svg-MWXPtWo2kknPMnhs .node .label text,#mermaid-svg-MWXPtWo2kknPMnhs .image-shape .label,#mermaid-svg-MWXPtWo2kknPMnhs .icon-shape .label{text-anchor:middle;}#mermaid-svg-MWXPtWo2kknPMnhs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MWXPtWo2kknPMnhs .rough-node .label,#mermaid-svg-MWXPtWo2kknPMnhs .node .label,#mermaid-svg-MWXPtWo2kknPMnhs .image-shape .label,#mermaid-svg-MWXPtWo2kknPMnhs .icon-shape .label{text-align:center;}#mermaid-svg-MWXPtWo2kknPMnhs .node.clickable{cursor:pointer;}#mermaid-svg-MWXPtWo2kknPMnhs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MWXPtWo2kknPMnhs .arrowheadPath{fill:#333333;}#mermaid-svg-MWXPtWo2kknPMnhs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MWXPtWo2kknPMnhs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MWXPtWo2kknPMnhs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MWXPtWo2kknPMnhs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MWXPtWo2kknPMnhs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MWXPtWo2kknPMnhs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MWXPtWo2kknPMnhs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MWXPtWo2kknPMnhs .cluster text{fill:#333;}#mermaid-svg-MWXPtWo2kknPMnhs .cluster span{color:#333;}#mermaid-svg-MWXPtWo2kknPMnhs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MWXPtWo2kknPMnhs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MWXPtWo2kknPMnhs rect.text{fill:none;stroke-width:0;}#mermaid-svg-MWXPtWo2kknPMnhs .icon-shape,#mermaid-svg-MWXPtWo2kknPMnhs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MWXPtWo2kknPMnhs .icon-shape p,#mermaid-svg-MWXPtWo2kknPMnhs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MWXPtWo2kknPMnhs .icon-shape .label rect,#mermaid-svg-MWXPtWo2kknPMnhs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MWXPtWo2kknPMnhs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MWXPtWo2kknPMnhs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MWXPtWo2kknPMnhs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 数据节点处理


故障恢复时
客户端写入请求
代理服务
消息队列

Pulsar/Kafka
消费日志
内存组装数据结构
达到阈值?

(时间/行数)
持久化为段 Segment
对象存储

S3/MinIO等
元存储

记录段-日志映射
从日志位置重放

图:日志即数据模型工作流程

2.2 分层存储:热数据、温数据、冷数据

Milvus 智能地管理数据在内存和磁盘间的流动:

  • 增长段 (Growing Segment): 最新插入的数据驻留在内存中,属于"热数据",支持低延迟的插入和实时查询。
  • 密封段 (Sealed Segment): 当增长段达到配置大小后,会被"密封",并触发索引构建。密封段会被持久化到对象存储。查询节点可以将其加载到内存或磁盘缓存中进行查询,属于"温数据"。
  • 冷段: 访问频率极低的旧数据段,可能只存在于对象存储中,查询时按需加载,延迟较高。

查询节点通过 LRU (最近最少使用) 等策略管理内存中的段缓存,优化查询性能与资源利用率。
#mermaid-svg-zmm2f9NtcOz6qGoV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zmm2f9NtcOz6qGoV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zmm2f9NtcOz6qGoV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zmm2f9NtcOz6qGoV .error-icon{fill:#552222;}#mermaid-svg-zmm2f9NtcOz6qGoV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zmm2f9NtcOz6qGoV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zmm2f9NtcOz6qGoV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zmm2f9NtcOz6qGoV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zmm2f9NtcOz6qGoV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zmm2f9NtcOz6qGoV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zmm2f9NtcOz6qGoV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zmm2f9NtcOz6qGoV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zmm2f9NtcOz6qGoV .marker.cross{stroke:#333333;}#mermaid-svg-zmm2f9NtcOz6qGoV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zmm2f9NtcOz6qGoV p{margin:0;}#mermaid-svg-zmm2f9NtcOz6qGoV defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-zmm2f9NtcOz6qGoV g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-zmm2f9NtcOz6qGoV g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-zmm2f9NtcOz6qGoV g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-zmm2f9NtcOz6qGoV g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-zmm2f9NtcOz6qGoV g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-zmm2f9NtcOz6qGoV .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-zmm2f9NtcOz6qGoV .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-zmm2f9NtcOz6qGoV .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-zmm2f9NtcOz6qGoV .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-zmm2f9NtcOz6qGoV .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-zmm2f9NtcOz6qGoV .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-zmm2f9NtcOz6qGoV .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-zmm2f9NtcOz6qGoV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zmm2f9NtcOz6qGoV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zmm2f9NtcOz6qGoV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zmm2f9NtcOz6qGoV .edgeLabel .label text{fill:#333;}#mermaid-svg-zmm2f9NtcOz6qGoV .label div .edgeLabel{color:#333;}#mermaid-svg-zmm2f9NtcOz6qGoV .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-zmm2f9NtcOz6qGoV .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-zmm2f9NtcOz6qGoV .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-zmm2f9NtcOz6qGoV .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-zmm2f9NtcOz6qGoV .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-zmm2f9NtcOz6qGoV .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zmm2f9NtcOz6qGoV .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zmm2f9NtcOz6qGoV #statediagram-barbEnd{fill:#333333;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zmm2f9NtcOz6qGoV .cluster-label,#mermaid-svg-zmm2f9NtcOz6qGoV .nodeLabel{color:#131300;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-zmm2f9NtcOz6qGoV .note-edge{stroke-dasharray:5;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-note text{fill:black;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram-note .nodeLabel{color:black;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagram .edgeLabel{color:red;}#mermaid-svg-zmm2f9NtcOz6qGoV #dependencyStart,#mermaid-svg-zmm2f9NtcOz6qGoV #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-zmm2f9NtcOz6qGoV .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zmm2f9NtcOz6qGoV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 数据插入
达到配置大小
索引构建完成
访问频率极低
GrowingSegment
驻留内存
实时查询
HotMemory
SealedSegment
持久化到对象存储
加载到查询节点缓存
温数据查询
WarmStorage
WarmCache
IndexedSegment
仅存对象存储
按需加载
冷数据查询
ColdStorage
OnDemand
ColdSegment

图:数据分层存储状态转换 - 热、温、冷数据生命周期

3. 向量索引核心:近似最近邻搜索的加速器

向量索引是向量数据库的"发动机",其目标是在数十亿甚至数百亿的高维向量中,快速找到与目标向量最相似的 Top-K 个结果。Milvus 集成了多种主流索引类型,适用于不同场景。

3.1 索引类型与算法

  1. FLAT (暴力搜索)

    • 原理:计算查询向量与集合中每个向量的距离(如 L2、内积)。
    • 特点:100% 召回率,精度最高,但速度慢,适合小数据集(百万级以下)或作为精度验证的基准。
    • 在 Milvus 中,FLAT 索引更多代表"无索引",直接使用原始向量数据。
  2. IVF 系列 (倒排文件)

    • IVF_FLAT : 最经典的聚类索引。先对全量向量进行 K-Means 聚类,得到 nlist 个聚类中心。搜索时,先计算查询向量与所有聚类中心的距离,找到最近的 nprobe 个类簇,然后在这些类簇内的所有向量中进行暴力搜索。
    • IVF_SQ8/IVF_PQ: 在 IVF 基础上,对每个类簇内的向量进行标量化(SQ)或乘积量化(PQ),大幅减少内存占用和距离计算成本,以轻微精度损失换取性能和资源的优化。
    • 适用场景:兼顾精度和速度的通用场景,是 Milvus 中最常用的索引类型之一。
  3. HNSW (可导航小世界图)

    • 原理:构建一个多层图结构,上层是"高速公路",下层是"精细道路"。搜索从顶层开始,快速接近目标区域,然后逐层向下细化搜索。
    • 特点:查询速度极快,尤其适合高维数据,但索引构建时间长,内存占用高。支持增量插入。
    • 适用场景:对查询延迟要求极高,且数据量不是特别巨大的场景。
  4. SCANN (基于图的索引)

    • 原理:类似 HNSW 的图索引,但在索引构建和搜索策略上进行了优化。
    • 特点:在千万到亿级数据集上,能在查询性能、内存占用和索引构建时间之间取得更好的平衡。
  5. DISKANN (磁盘ANN)

    • 原理:专为磁盘级向量检索设计。它将图索引与 SSD 的访问特性结合,索引完全存储在磁盘上,仅将搜索路径上的少量节点加载到内存。
    • 特点:支持远超内存容量的大型数据集(百亿级),查询速度比纯内存索引慢,但比传统方法快几个数量级。
    • 适用场景:超大规模向量数据库,成本敏感型应用。

#mermaid-svg-z2dMGRarzmunaFXi{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-z2dMGRarzmunaFXi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-z2dMGRarzmunaFXi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-z2dMGRarzmunaFXi .error-icon{fill:#552222;}#mermaid-svg-z2dMGRarzmunaFXi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-z2dMGRarzmunaFXi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-z2dMGRarzmunaFXi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-z2dMGRarzmunaFXi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-z2dMGRarzmunaFXi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-z2dMGRarzmunaFXi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-z2dMGRarzmunaFXi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-z2dMGRarzmunaFXi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-z2dMGRarzmunaFXi .marker.cross{stroke:#333333;}#mermaid-svg-z2dMGRarzmunaFXi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-z2dMGRarzmunaFXi p{margin:0;}#mermaid-svg-z2dMGRarzmunaFXi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-z2dMGRarzmunaFXi .cluster-label text{fill:#333;}#mermaid-svg-z2dMGRarzmunaFXi .cluster-label span{color:#333;}#mermaid-svg-z2dMGRarzmunaFXi .cluster-label span p{background-color:transparent;}#mermaid-svg-z2dMGRarzmunaFXi .label text,#mermaid-svg-z2dMGRarzmunaFXi span{fill:#333;color:#333;}#mermaid-svg-z2dMGRarzmunaFXi .node rect,#mermaid-svg-z2dMGRarzmunaFXi .node circle,#mermaid-svg-z2dMGRarzmunaFXi .node ellipse,#mermaid-svg-z2dMGRarzmunaFXi .node polygon,#mermaid-svg-z2dMGRarzmunaFXi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-z2dMGRarzmunaFXi .rough-node .label text,#mermaid-svg-z2dMGRarzmunaFXi .node .label text,#mermaid-svg-z2dMGRarzmunaFXi .image-shape .label,#mermaid-svg-z2dMGRarzmunaFXi .icon-shape .label{text-anchor:middle;}#mermaid-svg-z2dMGRarzmunaFXi .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-z2dMGRarzmunaFXi .rough-node .label,#mermaid-svg-z2dMGRarzmunaFXi .node .label,#mermaid-svg-z2dMGRarzmunaFXi .image-shape .label,#mermaid-svg-z2dMGRarzmunaFXi .icon-shape .label{text-align:center;}#mermaid-svg-z2dMGRarzmunaFXi .node.clickable{cursor:pointer;}#mermaid-svg-z2dMGRarzmunaFXi .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-z2dMGRarzmunaFXi .arrowheadPath{fill:#333333;}#mermaid-svg-z2dMGRarzmunaFXi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-z2dMGRarzmunaFXi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-z2dMGRarzmunaFXi .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-z2dMGRarzmunaFXi .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-z2dMGRarzmunaFXi .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-z2dMGRarzmunaFXi .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-z2dMGRarzmunaFXi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-z2dMGRarzmunaFXi .cluster text{fill:#333;}#mermaid-svg-z2dMGRarzmunaFXi .cluster span{color:#333;}#mermaid-svg-z2dMGRarzmunaFXi div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-z2dMGRarzmunaFXi .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-z2dMGRarzmunaFXi rect.text{fill:none;stroke-width:0;}#mermaid-svg-z2dMGRarzmunaFXi .icon-shape,#mermaid-svg-z2dMGRarzmunaFXi .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-z2dMGRarzmunaFXi .icon-shape p,#mermaid-svg-z2dMGRarzmunaFXi .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-z2dMGRarzmunaFXi .icon-shape .label rect,#mermaid-svg-z2dMGRarzmunaFXi .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-z2dMGRarzmunaFXi .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-z2dMGRarzmunaFXi .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-z2dMGRarzmunaFXi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 小数据集

(< 百万)
中等数据集

(百万~千万)
极高
平衡
优化资源
超大规模

(十亿~百亿)


选择向量索引
数据规模?
FLAT

暴力搜索

100%召回率
查询延迟要求?
HNSW

极快查询

高内存占用
IVF系列

兼顾精度速度

通用首选
SCANN

性能平衡

千万~亿级
DISKANN

磁盘级检索

成本敏感
需要压缩?
IVF_PQ/SQ8

内存优化

轻微精度损失
IVF_FLAT

经典聚类

精度优先
确定索引类型

图:Milvus 索引类型选择决策树

3.2 索引构建与管理

  • 异步构建:索引构建由专门的索引节点异步执行,不影响数据插入的可用性。
  • 段级索引:索引以数据段为单位构建。每个密封段都会独立构建自己的索引文件,并上传到对象存储。
  • 自动合并:数据协调器会定期触发"压缩"操作,将多个小段合并成一个大段,并重建索引,以优化查询性能。

4. 分布式检索:让查询飞起来

单机无法处理海量向量的实时检索。Milvus 的分布式检索架构将计算任务并行化,实现了水平扩展。

4.1 查询节点与数据分布

  • 一个集合的数据被水平划分为多个分区 。每个分区内的数据进一步被切分为多个,分布在不同数据节点上持久化。
  • 查询节点是无状态的。查询协调器根据负载情况,将不同的数据段(或分区)分配给不同的查询节点进行加载和管理。
  • 当一个查询请求到来时:
    1. 查询协调器根据查询条件(如过滤表达式)确定需要搜索哪些分区和段。
    2. 协调器将搜索任务分发给管理着这些段的查询节点。
    3. 每个查询节点并行地在自己的内存/缓存中,对负责的段执行检索(包括标量过滤和向量相似度计算)。
    4. 各节点将本地 Top-K 结果返回给协调器或代理节点,进行归并排序,得到全局的 Top-K 结果后返回给客户端。

对象存储 查询节点3 查询节点2 查询节点1 查询协调器 代理服务 客户端 对象存储 查询节点3 查询节点2 查询节点1 查询协调器 代理服务 客户端 #mermaid-svg-QYWTjgEcPCbtc6Cd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QYWTjgEcPCbtc6Cd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QYWTjgEcPCbtc6Cd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QYWTjgEcPCbtc6Cd .error-icon{fill:#552222;}#mermaid-svg-QYWTjgEcPCbtc6Cd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QYWTjgEcPCbtc6Cd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QYWTjgEcPCbtc6Cd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QYWTjgEcPCbtc6Cd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QYWTjgEcPCbtc6Cd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QYWTjgEcPCbtc6Cd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QYWTjgEcPCbtc6Cd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QYWTjgEcPCbtc6Cd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QYWTjgEcPCbtc6Cd .marker.cross{stroke:#333333;}#mermaid-svg-QYWTjgEcPCbtc6Cd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QYWTjgEcPCbtc6Cd p{margin:0;}#mermaid-svg-QYWTjgEcPCbtc6Cd .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QYWTjgEcPCbtc6Cd text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-QYWTjgEcPCbtc6Cd .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-QYWTjgEcPCbtc6Cd .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-QYWTjgEcPCbtc6Cd .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-QYWTjgEcPCbtc6Cd .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-QYWTjgEcPCbtc6Cd #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-QYWTjgEcPCbtc6Cd .sequenceNumber{fill:white;}#mermaid-svg-QYWTjgEcPCbtc6Cd #sequencenumber{fill:#333;}#mermaid-svg-QYWTjgEcPCbtc6Cd #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-QYWTjgEcPCbtc6Cd .messageText{fill:#333;stroke:none;}#mermaid-svg-QYWTjgEcPCbtc6Cd .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QYWTjgEcPCbtc6Cd .labelText,#mermaid-svg-QYWTjgEcPCbtc6Cd .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-QYWTjgEcPCbtc6Cd .loopText,#mermaid-svg-QYWTjgEcPCbtc6Cd .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-QYWTjgEcPCbtc6Cd .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-QYWTjgEcPCbtc6Cd .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-QYWTjgEcPCbtc6Cd .noteText,#mermaid-svg-QYWTjgEcPCbtc6Cd .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-QYWTjgEcPCbtc6Cd .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QYWTjgEcPCbtc6Cd .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QYWTjgEcPCbtc6Cd .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QYWTjgEcPCbtc6Cd .actorPopupMenu{position:absolute;}#mermaid-svg-QYWTjgEcPCbtc6Cd .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-QYWTjgEcPCbtc6Cd .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QYWTjgEcPCbtc6Cd .actor-man circle,#mermaid-svg-QYWTjgEcPCbtc6Cd line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-QYWTjgEcPCbtc6Cd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} par并行查询 发起向量查询请求转发查询解析查询条件确定目标分区/段分配段A查询任务加载段A数据与索引执行本地检索(标量过滤+向量计算)返回本地Top-K结果分配段B查询任务加载段B数据与索引执行本地检索返回本地Top-K结果分配段C查询任务加载段C数据与索引执行本地检索返回本地Top-K结果归并排序所有结果返回全局Top-K结果返回最终查询结果

图:分布式查询并行执行流程

4.2 混合查询:向量 + 标量过滤

现实中的查询很少是纯向量搜索。Milvus 支持强大的混合查询

python 复制代码
# 示例:查找与某图片向量相似,且发布时间在2023年之后,分类为"动物"的条目
results = collection.search(
    data=[query_vector],
    anns_field="image_vector",
    param={"metric_type": "L2", "params": {"nprobe": 10}},
    limit=10,
    expr='publish_year > 2023 and category == "animal"'
)
  • 执行流程:查询节点会先利用倒排索引(如果标量字段已建索引)或暴力扫描进行标量过滤,得到一个候选向量集,然后仅对这个子集进行向量相似度计算。这极大地减少了不必要的向量距离计算。

4.3 一致性级别

Milvus 提供多种查询一致性级别,平衡性能与数据新鲜度:

  • 强一致性:确保读到最新写入的数据,延迟最高。
  • 会话一致性(默认):保证同一客户端会话内读到自身已提交的写入。
  • 有界一致性:允许读到几秒钟前的数据状态,延迟最低,吞吐最高。
  • 最终一致性:不保证顺序,只保证最终能读到。

5. 流批一体与数据生态

现代 AI 应用需要同时处理实时流数据和历史批数据。Milvus 的架构原生支持流批一体

  • 流处理:通过消息队列,新插入的数据能近乎实时地被查询节点感知和加载,支持低延迟的实时检索。
  • 批处理:历史数据以段的形式存储在对象存储中,支持大规模的历史数据分析与检索。
  • 统一入口:用户无需区分流和批,使用同一套 API 即可查询全量数据。

此外,Milvus 积极融入大数据生态:

  • 与 Kafka/Pulsar 集成:直接消费业务日志流,实现向量数据的实时导入。
  • 与 Spark/Flink 集成:方便进行大规模的离线向量索引构建和批量数据导入。
  • 作为 LlamaIndex / LangChain 的向量存储:成为大模型应用(RAG)的核心记忆体。

总结与展望

Milvus 的架构设计是工程智慧的集中体现。它通过存储计算分离 获得了弹性,通过日志即数据 获得了可靠性,通过丰富的向量索引 获得了效率,通过分布式检索 获得了规模,通过流批一体获得了灵活性。

这种设计使得 Milvus 能够支撑从千万级到百亿级向量的 AI 应用场景,涵盖推荐系统、图像检索、智能问答、药物发现、欺诈检测等众多领域。随着 AI 模型多模态化和应用复杂化,对向量数据库的实时性、规模性和易用性提出了更高要求。Milvus 社区正在持续演进,例如探索更智能的索引自动选择、更紧密的云原生集成、以及更强的 GPU 加速能力,以巩固其作为 AI 原生数据基础设施核心的地位。

对于架构师和开发者而言,理解 Milvus 的内部机制,不仅能更好地使用它,更能从中汲取设计分布式数据系统的宝贵经验。

相关推荐
phltxy19 小时前
LangChain文本向量与检索器实践
人工智能·深度学习·语言模型·langchain
稚南城才子,乌衣巷风流19 小时前
链表(Linked List):数据结构详解与实战应用
java
larance19 小时前
机器学习特征预处理之特征选择
人工智能·机器学习
NWU_LK19 小时前
【WebFlux】第二篇 —— Project Reactor 核心数据类型
java
lisw0519 小时前
AI在高端制造中的具体技术瓶颈是什么?预计何时能突破?
人工智能·机器学习·制造
三84419 小时前
笔记:在同一个物理服务器上通过nginx的虚拟主机生成多个不同的web站点
java·前端·nginx
画中有画19 小时前
边缘计算技术的设计与实现
人工智能·边缘计算
Cosolar19 小时前
深入理解 AI Agent:设计原理与工程实践
人工智能·面试·github
LitchiCheng19 小时前
轻量化微调 Qwen2.5 LoRA 训练全流程详解
大数据·人工智能·spark