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

milvus-logo
LFAI
  • Home
  • Blog
  • 向量数据库中的数据插入和数据持久性

向量数据库中的数据插入和数据持久性

  • Engineering
April 06, 2022
Bingyi Sun

Cover image 封面图片

本文由孙冰怡撰写,倪安琪翻译。

在 "深度挖掘 "系列的上一篇文章中,我们已经介绍了全球最先进的向量数据库Milvus 是如何处理数据的。在本文中,我们将继续研究数据插入所涉及的组件,详细说明数据模型,并解释 Milvus 中如何实现数据持久性。

跳转到

Milvus 架构回顾

Milvus architecture. Milvus 架构。

SDK 通过负载平衡器将数据请求发送给代理,即门户。然后,代理与协调器服务交互,将 DDL(数据定义语言)和 DML(数据操作语言)请求写入消息存储。

包括查询节点、数据节点和索引节点在内的工作节点从消息存储中消费请求。具体来说,查询节点负责数据查询;数据节点负责数据插入和数据持久化;索引节点主要处理索引构建和查询加速。

底层是对象存储,主要利用 MinIO、S3 和 AzureBlob 来存储日志、delta binlog 和索引文件。

数据插入请求的入口

Proxy in Milvus. Milvus 中的代理。

代理是数据插入请求的入口。

  1. 最初,代理接受来自 SDK 的数据插入请求,并使用哈希算法将这些请求分配到多个桶中。
  2. 然后,代理请求数据协调器分配段(Milvus 数据存储的最小单位)。
  3. 然后,代理将请求分段的信息插入信息存储区,以确保这些信息不会丢失。

数据协调器和数据节点

数据协调器的主要功能是管理信道和段的分配,而数据节点的主要功能是消耗和持久化插入的数据。

Data coord and data node in Milvus. Milvus 中的数据协调器和数据节点。

功能

数据协调器在以下方面发挥作用:

  • 分配网段空间数据协调器向代理分配不断增长的网段空间,以便代理使用网段中的空闲空间插入数据。

  • 记录段分配和段中已分配空间的到期时间数据协调器分配的每个段中的空间都不是永久性的,因此数据协调器还需要记录每个段分配的到期时间。

  • 自动刷新分段数据如果分段已满,数据协调器会自动触发数据刷新。

  • 为数据节点分配通道一个 Collections 可以有多个vchannels。数据协调器决定哪些数据节点使用哪些 v 通道。

数据节点在以下方面提供服务:

  • 消耗数据数据节点从数据协调器分配的通道中消耗数据,并为数据创建序列。

  • 数据持久化 在内存中缓存插入的数据,并在数据量达到一定阈值时自动将插入的数据刷新到磁盘。

工作流程

One vchannel can only be assigned to one data node. 一个 v 通道只能分配给一个数据节点

如上图所示,Collection 有四个 v 通道(V1、V2、V3 和 V4),两个数据节点。数据协调器很有可能分配一个数据节点消耗来自 V1 和 V2 的数据,另一个数据节点消耗来自 V3 和 V4 的数据。单个 v 通道不能分配给多个数据节点,这是为了防止重复消耗数据,否则会导致同一批数据重复插入同一数据段。

根节点和时间标记

根节点管理 TSO(时间戳 Oracle),并在全球范围内发布时间刻度信息。每个数据插入请求都有一个由根协调器分配的时间戳。时间刻度是 Milvus 的基石,它就像 Milvus 中的时钟,表示 Milvus 系统处于哪个时间点。

在 Milvus 中写入数据时,每个数据插入请求都带有一个时间戳。在数据消耗过程中,每个时间数据节点消耗时间戳在一定范围内的数据。

An example of data insertion and data consumption based on timestamp. 基于时间戳的数据插入和数据消耗示例

上图是数据插入的过程。时间戳的值用数字 1、2、6、5、7、8 表示。数据通过两个代理写入系统:P1 和 P2。在数据消耗过程中,如果时间戳的当前时间为 5,数据节点只能读取数据 1 和 2。然后在第二次读取时,如果当前的时间刻度变为 9,数据节点就可以读取数据 6、7、8。

数据组织:Collection、分区、碎片(通道)、段

Data organization in Milvus. Milvus 中的数据组织。

请先阅读本文,了解 Milvus 中的数据模型以及 Collections、shard、partition 和 segment 的概念。

总之,Milvus 中最大的数据单元是 Collections,它可以比作关系数据库中的表。一个 Collections 可以有多个分区(每个分区对应一个通道),每个分区内可以有多个分区。如上图所示,通道(分块)是垂直条形图,而分区是水平条形图。每个交叉点都有段的概念,即数据分配的最小单位。在 Milvus 中,索引建立在段上。在查询过程中,Milvus 系统还会平衡不同查询节点中的查询负载,而这一过程就是以分段为单位进行的。分段包含多个binlog,当分段数据耗尽时,将生成一个 binlog 文件。

分段

在 Milvus 中,有三种状态不同的分段:生长分段、密封分段和冲洗分段。

成长段

成长段是一个新创建的段,可分配给代理用于插入数据。段的内部空间可以使用、分配或释放。

Three status in a growing segment 成长段的三种状态

  • 已使用:增长段的这部分空间已被数据节点消耗。
  • 已分配:增长区段的这部分空间已由代理申请并由数据协调员分配。分配的空间将在一段时间后过期。
  • 空闲:增长区段的这部分空间未被使用。可用空间的值等于段的总空间减去已用空间和已分配空间的值。因此,段的可用空间会随着分配空间的到期而增加。

密封分段

密封网段是一个封闭的网段,不能再分配给代理插入数据。

Sealed segment in Milvus Milvus 中的密封网段

在以下情况下,增长中的数据段会被密封:

  • 如果增长段中已用空间达到总空间的 75%,该段将被封存。
  • Milvus 用户手动调用 Flush() 以持久化 Collections 中的所有数据。
  • 由于过多的增长段会导致数据节点过度占用内存,因此长时间未封存的增长段将被封存。

刷新段

已刷新段是指已写入磁盘的段。刷新是指为了数据持久性而将段数据存储到对象存储中。只有当密封段中分配的空间到期时,才能刷新段。刷新时,密封段会变成已刷新段。

Flushed segment in Milvus Milvus 中被刷新的 数据

通道

一个通道被分配给 :

  • 数据节点启动或关闭时;或
  • 代理请求分配段空间时。

通道分配有几种策略。Milvus 支持其中两种策略:

  1. 一致性散列

Consistency hashing in Milvus Milvus 中的一致性哈希算法

Milvus 的默认策略。该策略利用散列技术为每个通道分配一个环上的位置,然后沿时钟方向搜索离通道最近的数据节点。因此,在上图中,通道 1 被分配给数据节点 2,而通道 2 被分配给数据节点 3。

然而,这种策略的一个问题是,数据节点数量的增减(如新数据节点启动或数据节点突然关闭)会影响信道分配过程。为了解决这个问题,数据协调器通过 etcd 监控数据节点的状态,以便在数据节点状态发生变化时立即通知数据协调器。然后,数据协调器会进一步确定向哪个数据节点正确分配通道。

  1. 负载平衡

第二种策略是将相同 Collections 的通道分配给不同的数据节点,确保通道的平均分配。这种策略的目的是实现负载平衡。

数据分配:何时以及如何分配

The process of data allocation in Milvus Milvus 的数据分配过程

数据分配过程从客户端开始。它首先向代理发送带有时间戳t1 的数据插入请求。然后,代理向数据协调员发送段分配请求。

收到分段分配请求后,数据协调器会检查分段状态并分配分段。如果已创建分段的当前空间足以容纳新插入的数据行,数据协调器就会分配这些已创建的分段。但是,如果当前分段的可用空间不足,数据协调器将分配一个新的分段。每次请求时,数据协调器都会返回一个或多个数据段。与此同时,数据协调器还会将分配的数据段保存在元服务器中,以便数据持久化。

随后,数据协调器将已分配数据段的信息(包括数据段 ID、行数、过期时间t2 等)返回给代理。代理会将已分配区段的这些信息发送到消息存储区,以便正确记录这些信息。请注意,t1 的值必须小于t2 的值。t2 的默认值为 2,000 毫秒,可通过data_coord.yaml 文件中的参数segment.assignmentExpiration 进行更改。

Binlog 文件结构和数据持久性

Data node flush 数据节点刷新

数据节点订阅消息存储,因为数据插入请求保存在消息存储中,因此数据节点可以消费插入消息。数据节点首先将插入请求放入插入缓冲区,随着请求的累积,在达到阈值后会被刷新到对象存储区。

Binlog 文件结构

Binlog file structure. Binlog 文件结构

Milvus 中的 binlog 文件结构与 MySQL 中的 binlog 文件结构类似。binlog 有两个功能:数据恢复和索引构建。

一个 binlog 包含许多事件。每个事件都有一个事件头和事件数据。

包括 binlog 创建时间、写节点 ID、事件长度和 NextPosition(下一个事件的偏移量)等元数据都写在事件头中。

事件数据可分为两部分:固定数据和可变数据。

File structure of an insert event. 插入事件的文件结构

INSERT_EVENT 的事件数据中的固定部分包含StartTimestampEndTimestampreserved

可变部分实际上存储的是插入数据。插入数据以 parquet 格式排序并存储在该文件中。

数据持久性

如果 Schema 中有多个列,Milvus 将在列中存储 Binlog。

Binlog data persistence. Binlog 数据持久性

如上图所示,第一列是主键 binlog。第二列是时间戳列。其余为 Schema 中定义的列。上图还显示了 MinIO 中 binlog 的文件路径。

关于深入研究系列

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

Like the article? Spread the word

扩展阅读