在本系列博客的前两篇文章中,我们已经介绍了世界上最先进的矢量数据库Milvus的系统架构,以及它的Python SDK和API。
这篇文章主要是帮助你了解Milvus的数据是如何处理的,通过深入Milvus系统,研究数据处理组件之间的互动。
下面列出了一些开始前的有用资源。我们建议先阅读它们,以便更好地理解本帖的主题。
MsgStream接口
MsgStream接口对Milvus的数据处理至关重要。当Start() 被调用时,后台的coroutine将数据写进日志中介或从那里读取数据。当Close() 被调用时,coroutine停止。
MsgStream接口
MsgStream可以作为一个生产者和一个消费者。AsProducer(channels []string) 接口将MsgStream定义为生产者,而AsConsumer(channels []string, subNamestring)将其定义为消费者。参数channels 在两个接口中都是共享的,它被用来定义哪些(物理)通道要写入数据或从中读取数据。
当一个集合被创建时,可以指定集合中的分片数量。每个分片对应于一个虚拟通道(vchannel)。因此,一个集合可以有多个vchannel。Milvus给日志经纪人中的每个vchannel分配一个物理通道(pchannel)。
每个虚拟通道/碎片对应于一个物理通道
Produce() 在MsgStream接口中,负责将数据写入日志代理中的pchannel。数据可以通过两种方式写入。
- 单一写入。实体通过主键的哈希值被写入不同的分片(vchannel)中。然后这些实体流入日志代理中相应的pchannels。
- 广播式写入。实体被写入由参数
channels指定的所有pchannel中。
Consume() 是一种阻塞式的API。如果在指定的pchannel中没有可用的数据,在MsgStream接口中调用 ,coroutine将被阻塞。另一方面, 是一种非阻塞式的API,这意味着只有在指定的pchannel中存在现有数据时,coroutine才会读取和处理数据。否则,coroutine可以处理其他任务,在没有数据可用时不会被阻塞。Consume() Chan()
Seek() 是一种故障恢复的方法。当一个新的节点被启动时,可以获得数据消耗记录,通过调用 ,可以从被中断的地方恢复数据消耗。Seek()
写入数据
写入不同v信道(碎片)的数据可以是以下两种:插入消息或删除消息。这些v通道也可以被称为DmChannels(数据操作通道)。
不同的集合可以在日志代理中共享相同的pchannels。一个集合可以有多个分片,因此有多个相应的v通道。同一集合中的实体因此会流入日志经纪人中多个相应的p通道。因此,共享p通道的好处是,由于日志经纪人的高并发性,增加了吞吐量。
当一个集合被创建时,不仅要指定分片的数量,还要决定日志代理中vchannels和pchannels之间的映射。
Milvus中的写入路径
如上图所示,在写入路径中,代理机构通过MsgStream的AsProducer() 接口将数据写入日志代理。然后数据节点消耗数据,然后转换和存储消耗的数据到对象存储中。存储路径是一种元信息,将由数据协调器记录在etcd中。
流程图
由于不同的集合可能在日志代理中共享相同的pchannel,当消耗数据时,数据节点或查询节点需要判断pchannel中的数据属于哪个集合。为了解决这个问题,我们在Milvus中引入了flowgraph。它主要负责通过集合ID来过滤共享pchannel中的数据。因此,我们可以说,每个flowgraph处理一个集合中相应分片(vchannel)的数据流。
写入路径中的流图
创建MsgStream
当写入数据时,MsgStream对象在以下两种情况下被创建。
- 当代理收到一个数据插入请求时,它首先尝试通过根协调器(root coordinator)获得vchannels和pchannels之间的映射。然后代理创建一个MsgStream对象。
在写入路径中创建MsgStream对象_场景1
- 当数据节点启动并读取etcd中通道的元信息时,MsgStream对象被创建。
在写入路径中创建MsgStream对象_场景2
读取数据
Milvus中的读取路径
读取数据的一般工作流程如上图所示。查询请求通过DqRequestChannel广播给查询节点。查询节点并行地执行查询任务。来自查询节点的查询结果通过gRPC和代理汇总结果并返回给客户端。
仔细看一下数据读取过程,我们可以看到代理将查询请求写入DqRequestChannel中。然后,查询节点通过订阅DqRequestChannel来消费该消息。DqRequestChannel中的每条消息都是广播的,这样所有订阅的查询节点都能收到该消息。
当查询节点收到查询请求时,他们对存储在密封段中的批量数据和动态插入Milvus并存储在增长段中的流媒体数据进行本地查询。之后,查询节点需要对密封段和增长段的查询结果进行汇总。这些汇总的结果通过gRPC传递给代理。
代理机构收集来自多个查询节点的所有结果,然后将其汇总以获得最终结果。然后,代理将最终的查询结果返回给客户端。由于每个查询请求和其对应的查询结果都由相同的唯一的requestID标记,代理可以找出哪些查询结果与哪个查询请求对应。
流程图
读取路径中的流图
与写路径类似,流图也被引入到读路径中。Milvus实现了统一的Lambda架构,它整合了增量数据和历史数据的处理。因此,查询节点也需要获得实时流数据。同样,读取路径中的流图会过滤和区分不同集合的数据。
创建MsgStream
在读取路径中创建MsgStream对象
读取数据时,MsgStream对象在以下情况下被创建。
- 在Milvus中,除非数据被加载,否则无法读取。当代理收到数据加载请求时,它将请求发送到查询协调器,查询协调器决定将分片分配给不同查询节点的方式。分配信息(即v通道的名称以及v通道和其相应的p通道之间的映射)通过方法调用或RPC(远程过程调用)被发送到查询节点。随后,查询节点创建相应的MsgStream对象来消耗数据。
DDL操作
DDL是数据定义语言的缩写。对元数据的DDL操作可以分为写请求和读请求。然而,在元数据处理过程中,这两类请求被同等对待。
对元数据的读取请求包括以下内容,以及更多。
- 查询集合模式
- 查询索引信息
写请求包括以下内容,以及更多。
- 创建一个集合
- 删除一个集合
- 建立一个索引
- 删除一个索引
DDL请求从客户端被发送到代理。代理进一步将这些请求按照收到的顺序传递给根坐标,根坐标为每个DDL请求分配一个时间戳并对请求进行动态检查。代理以串行方式处理每个请求,即一次处理一个DDL请求。代理在完成对前一个请求的处理并从根坐标收到结果之前,不会处理下一个请求。
DDL操作
如上图所示,在根坐标任务队列中有K DDL请求。任务队列中的DDL请求是按照根坐标收到的顺序排列的。因此,ddl1 是第一个发送到根坐标的请求,ddlK 是这批请求中的最后一个。根协调人按照时间顺序逐一处理这些请求。
在一个分布式系统中,代理机构和根坐标之间的通信是由gRPC实现的。根坐标保持一个已执行任务的最大时间戳值的记录,以确保所有的DDL请求按照时间顺序被处理。
假设有两个独立的代理:代理1和代理2。它们都向同一个根坐标发送DDL请求。然而,有一个问题是,在这些请求被另一个代理后来收到之前,早期的请求不一定会被发送到根坐标。例如,在上面的图片中,当DDL_K-1 从代理1发送到根坐标时,代理2的DDL_K 已经被根坐标接受并执行。根据根坐标的记录,此时执行的任务的最大时间戳值是K 。因此,为了不打断时间顺序,请求DDL_K-1 ,将被根坐标的任务队列拒绝。然而,如果代理2在此时向根坐标发送请求DDL_K+5 ,该请求将被接受到任务队列中,并将根据其时间戳值在以后执行。
编制索引
建立索引
在收到来自客户端的索引建立请求后,代理首先对这些请求进行静态检查,并将其发送到根坐标。然后,根坐标将这些索引构建请求持久化到元存储(etcd)中,并将这些请求发送给索引协调器(索引协调器)。
建立一个索引
如上图所示,当索引协调器收到来自根协调器的索引构建请求时,它首先将任务持久化到etcd的元存储中。索引构建任务的初始状态是Unissued 。索引协调器维护每个索引节点的任务负载记录,并将入站任务发送到负载较少的索引节点。任务完成后,索引节点将任务的状态,即Finished 或Failed 写入元存储,元存储在Milvus中是etd。然后,索引协调人将通过在etcd中查找来了解索引构建任务是成功还是失败。如果任务因系统资源有限或索引节点退出而失败,索引协调人将重新触发整个过程并将同一任务分配给另一个索引节点。
丢弃一个索引
此外,索引协调人还负责丢弃索引的请求。
丢弃一个索引
当根坐标收到来自客户端的放弃索引的请求时,它首先将该索引标记为 "放弃",并将结果返回给客户端,同时通知索引坐标。然后,索引协调人用IndexID ,过滤所有的索引任务,那些符合条件的任务被放弃。
索引协调器的后台程序将逐渐从对象存储(MinIO和S3)中删除所有标记为 "放弃 "的索引任务。这个过程涉及recycleIndexFiles接口。当所有相应的索引文件被删除后,被删除的索引任务的元信息也会从元存储(etcd)中删除。
关于 "深度探究 "系列
随着Milvus2.0的正式宣布全面上市,我们精心策划了这个Milvus深潜博客系列,对Milvus的架构和源代码进行了深入解读。这个博客系列涵盖的主题包括。
- Milvus架构概述
- APIs和Python SDKs
- 数据处理
- 数据管理
- 实时查询
- 标量执行引擎
- QA系统
- Milvus_Cli和Attu
- 矢量执行引擎