跳到主要内容

数据处理

本文详细描述了 Milvus 中数据插入、索引构建和数据查询的实现。

数据插入

您可以在 Milvus 中为每个 Collection 指定若干分片,每个分片对应一个虚拟通道(vchannel)。如下图所示,Milvus 为日志代理中的每个 vchannel 分配一个物理通道(pchannel)。任何传入的插入/删除请求都根据主键的哈希值路由到分片。

DML 请求的验证被移到 proxy,因为 Milvus 没有复杂的事务。Proxy 会从 TSO(时间戳预言机)请求每个插入/删除请求的时间戳,TSO 是与 root coordinator 并置的时序模块。通过较旧的时间戳被较新的时间戳覆盖,时间戳用于确定正在处理的数据请求的顺序。Proxy 从 data coord 批量检索信息,包括实体的 segment 和主键,以提高整体吞吐量并避免中央节点过载。

Channels 1

DML(数据操作语言)操作和 DDL(数据定义语言)操作都写入日志序列,但 DDL 操作由于发生频率较低,仅分配一个通道。

Channels 2

Vchannel 在底层日志代理节点中维护。每个通道在物理上是不可分割的,可供任何但仅一个节点使用。当数据摄取速率达到瓶颈时,考虑两个问题:日志代理节点是否过载需要扩展,以及是否有足够的分片来确保每个节点的负载均衡。

写入日志序列

上图概括了写入日志序列过程中涉及的四个组件:proxy、日志代理、数据节点和对象存储。该过程涉及四个任务:DML 请求验证、日志序列的发布-订阅、从流日志到日志快照的转换以及日志快照的持久化。这四个任务彼此解耦,以确保每个任务由其对应的节点类型处理。同类型的节点是平等的,可以弹性和独立扩展以适应各种数据负载,特别是大量且高度波动的流数据。

索引构建

索引构建由索引节点执行。为了避免频繁的数据更新索引构建,Milvus 中的 Collection 进一步分为 segment,每个 segment 都有自己的索引。

索引构建

Milvus 支持为每个向量字段、标量字段和主字段构建索引。索引构建的输入和输出都涉及对象存储:索引节点从 segment(位于对象存储中)将日志快照加载到内存中进行索引,反序列化相应的数据和元数据以构建索引,在索引构建完成时序列化索引,并将其写回对象存储。

索引构建主要涉及向量和矩阵运算,因此是计算和内存密集型的。由于向量的高维特性,无法使用传统的基于树的索引有效地对向量进行索引,但可以使用在这一主题上更成熟的技术进行索引,如基于聚类或基于图的索引。无论其类型如何,构建索引都涉及对大规模向量的大量迭代计算,如 Kmeans 或图遍历。

与标量数据的索引不同,构建向量索引必须充分利用 SIMD(单指令,多数据)加速。Milvus 对 SIMD 指令集有固有支持,例如 SSE、AVX2 和 AVX512。考虑到向量索引构建的"打嗝"和资源密集特性,弹性在经济方面对 Milvus 变得至关重要。未来的 Milvus 版本将进一步探索异构计算和无服务器计算,以降低相关成本。

此外,Milvus 还支持标量过滤和主字段查询。它具有内置索引来提高查询效率,例如 Bloom filter 索引、哈希索引、基于树的索引和倒排索引,并计划引入更多外部索引,例如位图索引和粗糙索引。

数据查询

数据查询是指在指定 Collection 中搜索与目标向量最近的 k 个向量或在指定距离范围内的 所有 向量的过程。向量与其对应的主键和字段一起返回。

数据查询

Milvus 中的 Collection 被分为多个 segment,查询节点按 segment 加载索引。当搜索请求到达时,它被广播到所有查询节点进行并发搜索。然后每个节点修剪本地 segment,搜索满足条件的向量,并减少和返回搜索结果。

在数据查询中,查询节点彼此独立。每个节点只负责两个任务:按照 query coord 的指令加载或释放 segment;在本地 segment 内进行搜索。Proxy 负责减少来自每个查询节点的搜索结果并将最终结果返回给客户端。

Handoff

有两种类型的 segment:growing segment(用于增量数据)和 sealed segment(用于历史数据)。查询节点订阅 vchannel 以接收最近更新(增量数据)作为 growing segment。当 growing segment 达到预定义阈值时,data coord 密封它并开始索引构建。然后由 query coord 发起的 handoff 操作将增量数据转换为历史数据。Query coord 将根据内存使用情况、CPU 开销和 segment 数量在所有查询节点之间均匀分布 sealed segment。

下一步