milvus学习笔记

本文主要由AI生成,请注意自己查看源代码校验。

Milvus v2.4+ 系统架构概览

Milvus 采用分布式微服务架构,将计算层(Proxy、QueryCoord、QueryNode、IndexCoord、DataCoord、DataNode 等)与存储层(Pulsar、MinIO/S3、etcd)分离,实现高并发、高可用和水平扩展。在查询场景下,查询请求首先经过前端 Proxy,由 Proxy 调度到后端查询服务,再由 QueryNode 在数据分片(segment)上并行执行向量检索,最后汇总结果返还给客户端。总体架构示意如图所示,重点标出了 Proxy、QueryCoord、QueryNode、DataCoord 等模块及它们之间通过 gRPC 和消息队列(如 Pulsar)通信的路径。

图1:Milvus 存算分离架构示意(Proxy -> 消息队列 -> DataNode -> 对象存储 -> QueryNode)

整体而言,Milvus 将写流程和读流程分离:写入时,客户端经由 Proxy 将数据写入日志流(Pulsar),DataNode 消费写日志并生成 segment(上传到对象存储),DataCoord/QueryCoord 收集和管理 segment;查询时,客户端经由 Proxy 发起检索请求,Proxy 将查询信息作为消息放入查询通道(QueryChannel),各个 QueryNode 订阅该通道接收查询。在查询前,QueryCoord 会根据 DataCoord 提供的 segment 信息对 QueryNode 做负载均衡(按 segment 或通道分配)。整个系统中,etcd 用于存储元数据和服务发现,Pulsar 用作日志 broker(可替换为 Kafka 等),MinIO/S3 作为大文件存储(segment、索引等)。

Proxy 模块源码结构

Proxy 作为客户端访问层,负责接收各种客户端请求(DML、查询、DDL 等),做校验和预处理后分发给后端服务。其核心结构体在 internal/proxy 包中定义,包含如下主要成员:

type Server struct {ctx                context.Contextproxy              types.ProxyComponent      // 实现 proxy 功能的接口(对外暴露 gRPC 服务)rootCoordClient    types.RootCoordClient    // gRPC 客户端:RootCoorddataCoordClient    types.DataCoordClient    // gRPC 客户端:DataCoordqueryCoordClient   types.QueryCoordClient   // gRPC 客户端:QueryCoord// ... 其他成员 ...
}

其中,types.ProxyComponent 接口由 internal/proxy/proxy.go 中的 Proxy 结构体实现。ServerRun() 方法启动 gRPC 服务并注册各类任务处理入口。对于向量检索(Search)请求,Proxy 内部会生成一个 SearchTask(位于 internal/proxy/task_search.go),将用户的查询参数(如集合 ID、向量、Top-K、过滤表达式等)封装成任务,然后将该任务发送给调度器或下游组件。在新版 Milvus 中,Proxy 并不直接执行搜索逻辑,而是根据查询信息将查询消息发往 Pulsar 的查询通道(QueryChannel)。同时,Proxy 维护对 RootCoord/DataCoord/QueryCoord 的客户端,用于获取集合元数据、segment 分布、时间戳等信息。例如,在 LoadCollection 操作中,Proxy 会先调用 RootCoord 创建加载任务,再通过 QueryCoord 获取需要加载的 segment 信息。总之,Proxy 起到“入口和汇聚”作用,无状态地对外提供统一服务。

QueryCoord 模块源码结构

QueryCoord 是查询协调节点,负责管理整个查询集群的拓扑和负载均衡,以及查询使用的 segment 分配和增量数据(Growing Segment)切换。其核心结构体位于 internal/querycoord 包中,主要成员包括:

type Server struct {queryCoord   types.QueryCoordComponent  // 实现 querycoord 功能的接口dataCoord    types.DataCoordClient      // gRPC 客户端:DataCoordrootCoord    types.RootCoordClient      // gRPC 客户端:RootCoord// ... 其他成员 ...
}

其中,types.QueryCoordComponent 接口由 internal/querycoord/query_coord.go 中的 QueryCoord 结构体实现。Server.Run() 启动 gRPC 服务,处理来自 Proxy 或客户端的查询加载等请求。典型的功能包括:LoadCollection(预加载指定集合到查询集群)和Search(调度查询任务)等。当用户调用 collection.load() 时,Proxy 会将加载请求转发给 QueryCoord。QueryCoord 首先通过 dataCoord.GetRecoveryInfo() 获取集合在存储中的已封存段(Sealed Segment)及对应的检查点;然后根据配置选择“按段分配”或“按通道分配”策略,将不同的封存段 (或日志通道) 分配到各个 QueryNode 上。QueryCoord 的任务调度器 (segment allocatorchannel allocator) 负责这一步骤。此外,QueryCoord 还负责监控 QueryNode 的负载,触发流式到封存段的转换(handoff),以及均衡重分配。官方文档指出:“QueryCoord 管理查询节点的拓扑和负载平衡,并处理从增长段到封存段的切换”。在代码层面,internal/querycoord 下的 querycoordsegment_allocatorchannel_allocator 等包实现了以上逻辑。

QueryNode 模块源码结构

QueryNode 是实际执行查询计算的工作节点,负责在加载到本地的 segment 数据上运行向量检索。其核心代码位于 internal/querynodev2(Milvus 2.x 采用 v2 版本实现)。一个 QueryNode 进程启动时,会初始化以下主要组件:流图(FlowGraph)用于处理增量数据,索引服务用于处理已封存的数据检索,和 Segment Manager 管理加载的 segment。Milvus 文档中描述:“QueryNode 订阅日志代理获取增量日志,将其转换为增长段,并从对象存储加载历史数据,在向量和标量数据之间运行混合搜索”。

在实现上,QueryNode 包括:server.go 定义了 QueryNode 结构体(实现 types.QueryNodeComponent 接口),负责启动 gRPC 服务和管理子模块;flowgraph 子包实现了增长段(Growing Segment)的流式数据接收与过滤;delegate 子包负责封装和分发具体的搜索请求到适当的 segment 或索引;segcore(SegCore)则提供 C++ 的向量检索核心调用。QueryNode 的主要方法包括 Search() (接受 QueryChannel 的查询消息)、LoadSegments()(加载指定 segment 的数据到内存),以及定期从 DataCoord 读取全局时间戳和消费位置,实现读取增量数据并触发持久化/封存。在并发执行向量检索时,QueryNode 会对本地所有加载的封存段并行搜索,然后与增长段(当前写入的数据)一起做融合,最后本地归约(去重)输出结果。可见,QueryNode 相对复杂,涉及流式处理和检索执行两大功能。

一次完整的向量检索流程

下面按步骤说明客户端一次查询请求在 Milvus 中的流转路径:

  1. 客户端请求 -> Proxy:客户端通过 SDK 发起 Search 请求到 Proxy(gRPC)。Proxy 接收后,将请求信息(包括集合 ID、查询向量、搜索参数等)封装成一个查询消息,并写入日志中间件(Pulsar)的查询通道。同时,Proxy 可从 RootCoord/DataCoord 获取集合的元数据和可用 segment 列表,为后续的调度做准备。

  2. (预先)Load Collection -> QueryCoord:在发起搜索前,如果用户调用了 collection.load(),Proxy 会触发 QueryCoord 的加载操作。QueryCoord 向 DataCoord 查询集合所有已封存段(和各段的消费检查点),然后执行负载分配。例如,按段分配时将不同封存段分配给不同 QueryNode;按通道分配时让 QueryNode 订阅不同的 DMChannel。在此步骤结束后,相关 QueryNode 已从对象存储加载了对应的历史数据段(封存段),并订阅了增量日志通道(收到新的写入数据)。

  3. QueryCoord 分配 -> QueryNode 订阅:QueryCoord 调度后,各 QueryNode 会执行对应的 LoadSegmentsWatchChannels 操作,准备好查询环境。每个 QueryNode 都在其本地维持了若干封存段(Sealed Segment)和对应的增长段(Growing Segment)(参见图2)。

图2:QueryCoord 为每个 QueryNode 分配封存段和日志通道示意。QueryNode1 加载了 S1、S3 等历史段,并订阅了 DMChannel1;QueryNode2 加载了 S2、S4,并订阅 DMChannel2。最终每个节点在本地同时拥有历史数据和增量流数据。

  1. QueryProxy 将查询推送至查询通道:客户端的查询请求已经写入 Pulsar 查询通道后,各 QueryNode 会监听此通道并取出查询消息。在消息中包含了执行时间戳等信息。Milvus 首先比较当前服务时间戳(service_ts)与查询消息中的保证时间戳(guarantee_ts)。只有当 service_ts >= guarantee_ts 时,才执行查询;否则该查询消息会暂时“悬挂”直到达到条件。

  2. QueryNode 执行检索并归约:当查询消息符合执行条件后,每个 QueryNode 并行地在本地的历史数据和增量数据上执行搜索。这包括对已经加载的封存段(离线历史数据)和正接收写入的增长段(在线流数据)分别进行搜索。由于两者可能重叠,QueryNode 内部会做一次“本地归约”(Local Reduce)去重。搜索完成后,各 QueryNode 将本地结果发布到结果通道(ResultChannel)。此时,结果消息中包含了本节点所搜索的封存段和通道信息。

  3. Proxy 聚合返回结果:Proxy 订阅结果通道,收集来自所有 QueryNode 的结果集。收到后,Proxy 会做一次全局归约(Global Reduce),去除不同节点间的重复结果。为确保结果完整性,Proxy 通过结果消息中的字段跟踪是否所有封存段和通道的数据都已返回。当条件满足后,Proxy 将最终合并排序后的 Top-K 结果返回给客户端。整个流程中,Proxy 仅负责路由和汇总;QueryCoord 只在查询准备阶段调度;真正的搜索计算由各 QueryNode 执行。

模块间调用链示意

以下伪代码描述了上述交互的主要调用顺序(忽略错误处理和并发细节):

// Proxy 接收到客户端的搜索请求
func ProxyHandleSearch(req QueryRequest) {// 1. 向 RootCoord 请求集合元数据(例如分片、索引信息)collectionInfo := RootCoord.GetCollectionInfo(req.CollectionID)// 2. 将查询信息封装为消息写入 Pulsar 查询通道Pulsar.Publish(QueryChannel, req)// 3. 监听结果通道,收集 QueryNode 返回结果results := collectResultsFromChannel(ResultChannel)// 4. 对所有 QueryNode 的结果做归约并返回merged := globalReduce(results)return merged
}// QueryCoord 预加载流程(LoadCollection)
func QueryCoordLoad(collectionID) {// 从 DataCoord 获取所有已封存段和检查点segments := DataCoord.GetRecoveryInfo(collectionID)// 选择分配策略(按段或按通道)// 将 segment 列表分配给不同的 QueryNodeassignments := allocateSegmentsToNodes(segments)// 通知各 QueryNode 加载数据或订阅通道for each node, segs in assignments:node.LoadSegments(segs)
}// QueryNode 搜索处理
func QueryNodeOnQueryMessage(msg QueryRequest) {if serviceTS < msg.GuaranteeTS {// 不满足时间条件,等待return}// 在本地封存段和增长段上并行检索resultsOffline := searchSealedSegments(msg.Vector, req)resultsStream := searchGrowingSegments(msg.Vector, req)localResults := localReduce(resultsOffline, resultsStream)// 发布到结果通道Pulsar.Publish(ResultChannel, localResults)
}

该调用链中,关键的是 Proxy、QueryCoord、QueryNode 三层协作:Proxy 负责接收请求与返回结果,QueryCoord 负责查询准备与调度,QueryNode 负责具体检索执行。

代码目录与主要文件(参考)

Milvus 仓库 internal 目录下包含各组件的实现子目录,其中与查询相关的主要路径有:

  • internal/proxy/:Proxy 服务实现,包括 proxy.go(Proxy 结构体、接口)、task_search.go(SearchTask 实现)等。

  • internal/querycoord/:QueryCoord 服务实现,包括 query_coord.go(QueryCoord 结构体、接口)、segment_allocator/channel_allocator/ 等调度逻辑。

  • internal/querynodev2/:QueryNode 服务实现,包括 server.go(QueryNode 结构体、接口)、flowgraph/(流式处理)、delegate/(查询代理)、segments/(本地 segment 管理)等。

下图为 Milvus 源码(部分)目录结构示意:

internal/
├── proxy/
│   ├── proxy.go          # ProxyComponent 实现(types.ProxyComponent)
│   ├── task_search.go    # SearchTask 逻辑
│   └── ...              
├── querycoord/
│   ├── query_coord.go    # QueryCoordComponent 实现(types.QueryCoordComponent)
│   ├── segment_allocator/
│   └── channel_allocator/
│   └── ...
├── querynodev2/
│   ├── server.go         # QueryNodeComponent 实现(types.QueryNodeComponent)
│   ├── flowgraph/        # 增量数据流式处理
│   ├── delegate/         # 查询请求分发
│   ├── segments/         # 本地 Segment 管理
│   └── ...
└── datacoord/            # DataCoord 服务(管理存储相关)└── ...

从以上目录可见,每个组件都用一个 Server 结构体启动 GRPC 服务,并持有对应的客户端接口,如 ProxyServer 包含 rootCoordClientqueryCoordClient 等。组件间通过 gRPC 和 Pulsar 消息进行协同,如 Proxy 调用 QueryCoord.LoadCollection 获取 segment 信息,QueryCoord 调用 DataCoord.GetRecoveryInfo 获取段信息,QueryNode 从 Pulsar 查询通道接收 Search 请求等。

参考资料

  • Milvus 官方文档与博客:《Milvus 架构概览》《QueryCoord 相关配置》《实时查询解析》等。

  • Zilliz/Milvus GitHub 代码:internal/proxyinternal/querycoordinternal/querynodev2 包。

  • 开源社区文章:Milvus 源码解析博客(见 “SearchTask”、“实时查询” 部分)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/81335.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用教程:8x16模拟开关阵列可级联XY脚双向导通自动化接线

以下通过点亮LED进行基本使用流程演示&#xff0c;实际可以连接复杂外设&#xff08;SPI、CAN、ADC等&#xff09; 单模块使用 RX、TX、5V和GND接到串口模块&#xff1b;X5接5V&#xff1b;Y2接LED;LED-接GND 串口模块插上电脑后&#xff0c;LED没有亮&#xff1b;因为此时模…

HarmonyOS NEXT~鸿蒙应用上架指南:HarmonyOS应用发布全流程解析

HarmonyOS NEXT&#xff5e;鸿蒙应用上架指南&#xff1a;HarmonyOS应用发布全流程解析 引言 随着华为鸿蒙操作系统(HarmonyOS)生态的快速发展&#xff0c;越来越多的开发者希望将自己的应用上架到鸿蒙应用市场。本文将详细介绍鸿蒙应用上架的全流程&#xff0c;帮助开发者顺…

20250517 我设想一个空间,无限大,空间不与其中物质进行任何作用,甚至这个空间能容纳可以伸缩的空间

1.我设想一个空间&#xff0c;无限大&#xff0c;空间不与其中物质进行任何作用&#xff0c;甚至这个空间能容纳可以伸缩的空间 您设想的这个空间具有一些有趣的特点&#xff1a; 无限大&#xff1a;空间本身没有边界或限制&#xff0c;理论上可以容纳无限多的物质或结构。非…

使用 Kaniko来构建镜像

使用 Kaniko来构建镜像 Kaniko 是一种专注于容器镜像构建的开源工具&#xff0c;其核心设计理念与 Docker 存在显著差异。以下从功能定位、技术实现和适用场景三方面进行对比分析&#xff1a; 一、Kaniko 的核心特性 无需 Docker 守护进程 Kaniko 直接在容器或 Kubernetes 集…

webman用nginx代理静态json文件的异步跨域

场景 有.json文件置于webman的public目录下&#xff0c;使用了nginx做代理&#xff0c;直接访问文件是可以正常加载的&#xff0c;但跨域浏览器就无法加载文件。 nginx配置 文件是否存在于跟目录&#xff0c;存在则设置请求头&#xff0c;不存在则将请求交给webman处理即可。…

JDK 21新特性全面解析

Java Development Kit (JDK) 21作为Oracle长期支持(LTS)版本&#xff0c;于2023年9月正式发布&#xff0c;带来了多项令人振奋的新特性和改进。本文将全面介绍JDK 21中的主要更新&#xff0c;帮助开发者了解如何利用这些新功能提升开发效率和代码质量。 一、虚拟线程(Virtual …

如何选择高性价比的 1T 服务器租用服务​

选择高性价比的 1T 服务器租用服务​&#xff0c;可参考以下内容&#xff1a; 1、根据需求选配置​ 明确自身业务需求是关键。若为小型网站或轻量级应用&#xff0c;数据存储与处理需求不高&#xff0c;选择基础配置服务器即可。如个人博客网站&#xff0c;普通的 Intel Xeon …

JavaScript性能优化实战(11):前沿技术在性能优化中的应用

引言 随着Web应用复杂度和性能需求不断提高,传统的JavaScript优化技术已经无法满足某些高性能计算场景的需求。本文将深入探讨前沿Web技术如何突破JavaScript的性能瓶颈,为Web应用提供接近原生应用的性能体验。从底层计算到图形渲染,从并发处理到动画优化,我们将通过实际案…

package.json 和 package-lock.json 的区别

package.json​​ ​​作用​​ ​​声明项目元数据​​&#xff1a;如项目名称、版本、描述、入口文件等。​​定义依赖范围​​&#xff1a;在 dependencies 和 devDependencies 中声明项目​​直接依赖​​的包及其​​版本范围​​&#xff08;如 ^1.2.3&#xff09;。​​…

Rollup入门与进阶:为现代Web应用构建超小的打包文件

我们常常面临Webpack复杂配置或是Babel转译后的冗余代码&#xff0c;结果导致最终的包体积居高不下加载速度也变得异常缓慢&#xff0c;而在众多打包工具中Rollup作为一个轻量且高效的选择&#xff0c;正悄然改变着这一切&#xff0c;本文将带你深入了解这个令人惊艳的打包工具…

基于C#的MQTT通信实战:从EMQX搭建到发布订阅全解析

MQTT(Message Queueing Telemetry Transport) 消息队列遥测传输&#xff0c;在物联网领域应用的很广泛&#xff0c;它是基于Publish/Subscribe模式&#xff0c;具有简单易用&#xff0c;支持QoS&#xff0c;传输效率高的特点。 它被设计用于低带宽&#xff0c;不稳定或高延迟的…

Mysql数据库之集群进阶

一、日志管理 5.7版本自定义路径时的文件需要自己提前创建好文件&#xff0c;不会自动创建&#xff0c;否则启动mysql会报错 错误日志 rpm包(yum) /var/log/mysql.log 默认错误日志 ###查询日志路径 [rootdb01 ~]# mysqladmin -uroot -pEgon123 variables | grep -w log_e…

当硅基存在成为人性延伸的注脚:论情感科技重构社会联结的可能性

在东京大学机器人实验室的档案室里&#xff0c;保存着一份泛黄的二战时期设计图——1943年日本陆军省秘密研发的“慰安妇替代品”草图。这个诞生于战争阴霾的金属躯体&#xff0c;与2025年上海进博会上展出的MetaBox AI伴侣形成时空对话&#xff1a;当人类将情感需求投射于硅基…

5月17日

这几天不知道为啥没更新。可能是玩得太疯了。或者是考试有点集中&#xff1f;&#xff1f; 线性代数开课了&#xff0c;英语昨天完成了debate 昨天中午debate结束我们就出去玩了&#xff0c;去的那里时光民俗&#xff0c;别墅很好&#xff0c;770平米&#xff0c;但是缺点是可…

FIFO的应用案例(基于Zephyr OS )

目录 概述 1. 软硬件环境 1.1 软件开发环境 1.2 硬件环境 2 FIFO的函数接口 3 FIFO的应用函数实现 3.1 实现步骤 3.2 代码设计 3.3 测试代码实现 3.4 源代码文件 4 编译和测试 4.1 编译代码 4.2 测试 概述 本文介绍了在nRF52832开发板上使用Zephyr操作系统进行…

AWS Elastic Beanstalk部署极简Spring工程(EB CLI失败版)

弃用 这里我没有走通EB CLI方式部署。 问题 最近又加入了AWS项目组&#xff0c;又要再次在AWS云上面部署Spring服务&#xff0c;我这里使用的使用AWS中国云。需要使用AWS Elastic Beanstalk部署一个极简Spring工程。 EB CLI安装 安装EB CLI之前需要先在本地安装好Git&…

粒子群算法(PSO算法)

粒子群算法概述 1.粒子群优化算法&#xff08;Particle Swarm Optimization&#xff0c;简称PSO&#xff09;。粒子群优化算法是在1995年由Kennedy博士和Eberhart博士一起提出的&#xff0c;它源于对鸟群捕食行为的研究。 2.基本核心是利用群体中的个体对信息的共享从而使得整…

leetcode2934. 最大化数组末位元素的最少操作次数-medium

1 题目&#xff1a;最大化数组末位元素的最少操作次数 官方标定难度&#xff1a;中 给你两个下标从 0 开始的整数数组 nums1 和 nums2 &#xff0c;这两个数组的长度都是 n 。 你可以执行一系列 操作&#xff08;可能不执行&#xff09;。 在每次操作中&#xff0c;你可以选…

Elasticsearch 官网阅读之 Term-level Queries

Term-level Queries 参考&#xff1a;https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-exists-query 一、Term Query Term Query 是 term 精准查询。需要注意的是&#xff0c;在进行 Term Query 的时候&#xff0c;要避免 text 类型的字段&#x…

信贷域——互联网金融业务

摘要 本文深入探讨了信贷域全托与半托业务的定义、特点、适用场景及注意事项&#xff0c;并分析了互联网金融核心信息流的多个方面&#xff0c;包括资金流、信息流、风险流、合规流、物流、技术流和商流&#xff0c;还阐述了金融系统“断直连”业务的相关内容&#xff0c;以及…