🚀 免费试用 Zilliz Cloud,完全托管的 Milvus,体验 10 倍的性能提升!立即试用>

milvus-logo
LFAI

HomeBlogs使用 Milvus 向量数据库进行实时查询

使用 Milvus 向量数据库进行实时查询

  • Engineering
April 11, 2022
Xi Ge

Cover image 封面图片

本文由Xi Ge撰写,Angela Ni 译。

在上一篇文章中,我们已经谈到了 Milvus 中的数据插入和数据持久性。在本文中,我们将继续讲解 Milvus 中的其他组件是如何交互完成实时数据查询的。

下面列出了开始之前的一些有用资源。我们建议首先阅读这些资源,以便更好地理解本篇文章的主题。

向查询节点加载数据

在执行查询之前,必须先将数据加载到查询节点。

加载到查询节点的数据有两类:来自日志代理的流数据和来自对象存储(下文也称为持久存储)的历史数据。

Flowchart 流程图

数据协调器负责处理不断插入 Milvus 的流数据。当 Milvus 用户调用collection.load() 加载一个 Collections 时,查询协调器将查询数据协调器,以了解哪些片段已被持久化存储及其对应的检查点。检查点是一个标记,表示检查点之前的持久化片段会被消耗,而检查点之后的片段不会被消耗。

然后,查询协调器根据数据协调器提供的信息输出分配策略:按段或按通道分配。段分配器负责将持久存储(批量数据)中的段分配给不同的查询节点。例如,在上图中,段分配器将段 1 和段 3(S1、S3)分配给查询节点 1,将段 2 和段 4(S2、S4)分配给查询节点 2。通道分配器为不同的查询节点分配日志代理中的多个数据操作通道(DMChannels)。例如,在上图中,信道分配器将查询节点 1 分配给信道 1 (Ch1),将查询节点 2 分配给信道 2 (Ch2)。

在这种分配策略下,每个查询节点都会加载段数据并相应地监视信道。在图像中的查询节点 1 中,历史数据(批量数据)通过分配的 S1 和 S3 从持久存储中加载。同时,查询节点 1 通过订阅日志代理中的通道 1 来加载增量数据(流数据)。

查询节点的数据管理

查询节点需要管理历史数据和增量数据。历史数据存储在密封段中,而增量数据存储在增长段中。

历史数据管理

历史数据管理主要有两个考虑因素:负载平衡和查询节点故障切换。

Load balance 负载平衡

例如,如图所示,查询节点 4 比其他查询节点分配了更多的密封分段。这很可能使查询节点 4 成为瓶颈,拖慢整个查询过程。为了解决这个问题,系统需要将查询节点 4 中的几个网段分配给其他查询节点。这就是所谓的负载平衡。

Query node failover 查询节点故障转移

另一种可能的情况如上图所示。其中一个节点(查询节点 4)突然宕机。在这种情况下,需要将负载(分配给查询节点 4 的数据段)转移到其他工作的查询节点,以确保查询结果的准确性。

增量数据管理

查询节点监视 DMChannels 以接收增量数据。在此过程中引入了流程图。它首先过滤所有数据插入信息。这是为了确保只加载指定分区中的数据。Milvus 中的每个 Collections 都有一个相应的通道,该通道由该 Collections 中的所有分区共享。因此,如果 Milvus 用户只需要加载某个分区中的数据,就需要使用流程图来过滤插入的数据。否则,Collection 中所有分区的数据都将加载到查询节点。

经过过滤后,增量数据被插入到不断增长的分段中,并进一步传递到服务器时间节点。

Flowgraph 流程图

在数据插入过程中,每个插入信息都会分配一个时间戳。在上图所示的 DMChannel 中,数据按从左到右的顺序插入。第一条插入信息的时间戳是 1,第二条是 2,第三条是 6。 第四条红色标记的信息不是插入信息,而是时间戳信息。这表示时间戳小于该时间戳的插入数据已经在日志代理中。换句话说,在该时间戳信息之后插入的数据,其时间戳值都应大于该时间戳。例如,在上图中,当查询节点感知到当前时间刻度为 5 时,这意味着所有时间戳值小于 5 的插入信息都被加载到了查询节点。

服务器时间节点每次从插入节点接收到一个时间戳后,都会提供一个更新的tsafe 值。tsafe 表示安全时间,在这个时间点之前插入的所有数据都可以被查询。举例来说,如果tsafe = 9,那么时间戳小于 9 的插入数据都可以被查询。

Milvus 中的实时查询

Milvus 中的实时查询是通过查询信息实现的。查询信息通过代理插入日志代理。然后,查询节点通过查看日志代理中的查询通道获取查询信息。

查询信息

Query message 查询信息

查询信息包括以下有关查询的关键信息:

  • msgID:消息 ID,系统分配的查询消息 ID。
  • collectionID:要查询的 Collections ID(如果用户指定)。
  • execPlan:执行计划主要用于查询中的属性过滤。
  • service_ts:服务时间戳将与上述tsafe 一起更新。服务时间戳表示服务的时间点。在service_ts 之前插入的所有数据都可供查询。
  • travel_ts:旅行时间戳指定过去的时间范围。查询将在travel_ts 指定的时间段内进行。
  • guarantee_ts:保证时间戳指定查询需要在其后进行的时间段。只有当service_ts >guarantee_ts 时,才会进行查询。

实时查询

Query process 查询过程

收到查询信息后,Milvus 首先判断当前服务时间service_ts 是否大于查询信息中的保证时间戳guarantee_ts 。如果是,则执行查询。查询将在历史数据和增量数据上并行执行。由于流数据和批处理数据之间可能会有数据重叠,因此需要执行一个名为 "局部缩减 "的操作来过滤掉多余的查询结果。

但是,如果当前服务时间小于新插入查询信息的保证时间戳,查询信息将成为未解决信息,等待处理,直到服务时间大于保证时间戳。

查询结果最终会推送到结果通道。代理从该通道获取查询结果。同样,代理也会进行 "全局还原",因为它从多个查询节点接收结果,而且查询结果可能是重复的。

为确保代理在向 SDK 返回所有查询结果之前已收到所有查询结果,结果信息还将保留一份信息记录,包括已搜索的密封段、已搜索的 DMChannels 和全局密封段(所有查询节点上的所有段)。只有同时满足以下两个条件,系统才能断定代理已收到所有查询结果:

  • 所有结果信息中记录的所有搜索密封段的总和大于全局密封段、
  • Collections 中的所有 DMChannels 都被查询。

最终,代理将 "全局还原 "后的最终结果返回给 Milvus SDK。

关于深入研究系列

随着 Milvus 2.0正式宣布全面上市,我们精心策划了这个 Milvus 深度剖析系列博客,对 Milvus 架构和源代码进行深入解读。本系列博客涉及的主题包括

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started

Like the article? Spread the word

扩展阅读