跳到主要内容

时间同步

本主题介绍了 Milvus 中的时间同步机制。

概述

Milvus 中的事件通常可以分为两类:

  • 数据定义语言(DDL)事件:创建/删除 Collection,创建/删除 Partition,等等。

  • 数据操作语言(DML)事件:插入、搜索,等等。

任何事件,无论是 DDL 还是 DML 事件,都标有一个时间戳,可以指示此事件何时发生。

假设有两个用户在 Milvus 中按下表所示的时间顺序启动一系列 DML 和 DDL 事件。

时间戳用户 1用户 2
t0创建了一个名为 C0 的 Collection。/
t2/在 Collection C0 上进行搜索。
t5向 Collection C0 中插入数据 A1/
t7/在 Collection C0 上进行搜索。
t10向 Collection C0 中插入数据 A2/
t12/在 Collection C0 上进行搜索
t15从 Collection C0 中删除数据 A1/
t17/在 Collection C0 上进行搜索

理想情况下,用户 2 应该能够看到:

  • t2 时,一个空的 Collection C0

  • t7 时,数据 A1

  • t12 时,数据 A1A2

  • t17 时,只有数据 A2(因为数据 A1 在此时间点之前已从 Collection 中删除)。

当只有一个单一节点时,这种理想情况很容易实现。但是,Milvus 是一个分布式向量数据库,为了确保不同节点中的所有 DML 和 DDL 操作都保持有序,Milvus 需要解决以下两个问题:

  1. 如果上述示例中的两个用户在不同的节点上,他们的时间时钟是不同的。例如,如果用户 2 比用户 1 晚 24 小时,那么用户 1 的所有操作对用户 2 来说都是不可见的,直到第二天。

  2. 可能存在网络延迟。如果用户 2 在 t17 时对 Collection C0 进行搜索,Milvus 应该能够保证 t17 之前的所有操作都已成功处理和完成。如果 t15 的删除操作由于网络延迟而延迟,用户 2 在 t17 进行搜索时很可能仍然能看到本应被删除的数据 A1

因此,Milvus 采用时间同步系统(timetick)来解决这些问题。

时间戳预言机(TSO)

为了解决前一节中提到的第一个问题,Milvus 像其他分布式系统一样,提供了时间戳预言机(TSO)服务。这意味着 Milvus 中的所有事件都必须从 TSO 而不是从本地时钟分配时间戳。

TSO 服务由 Milvus 中的 root coordinator 提供。客户端可以在单个时间戳分配请求中分配一个或多个时间戳。

TSO 时间戳是一种 uint64 值类型,由物理部分和逻辑部分组成。下图演示了时间戳的格式。

TSO_Timestamp.

如图所示,开头的 46 位是物理部分,即以毫秒为单位的 UTC 时间。最后 18 位是逻辑部分。

时间同步系统(timetick)

本节使用数据插入操作的示例来解释 Milvus 中的时间同步机制。

当 proxy 从 SDK 接收到数据插入请求时,它根据主键的哈希值将插入消息分配到不同的消息流(MsgStream)中。

每个插入消息(InsertMsg)在发送到 MsgStream 之前都会被分配一个时间戳。

MsgStream 是消息队列的包装器,在 Milvus 2.0 中默认为 Pulsar。

timesync_proxy_insert_msg

一个通用原则是,在 MsgStream 中,来自同一个 proxy 的 InsertMsgs 的时间戳必须是递增的。但是,对于来自不同 proxy 的 InsertMsgs,没有这样的规则。

下图是 MsgStreamInsertMsgs 的示例。该片段包含五个 InsertMsgs,其中三个来自 Proxy1,其余来自 Proxy2

msgstream

来自 Proxy1 的三个 InsertMsgs 的时间戳是递增的,来自 Proxy2 的两个 InsertMsgs 也是如此。但是,Proxy1Proxy2InsertMsgs 之间没有特定的顺序。

一种可能的情况是,当从 Proxy2 读取时间戳为 110 的消息时,Milvus 发现来自 Proxy1 的时间戳为 80 的消息仍在 MsgStream 中。因此,Milvus 引入了时间同步系统 timetick,以确保当从 MsgStream 读取消息时,所有具有较小时间戳值的消息都必须被消费。

time_synchronization

如上图所示,

  • 每个 proxy 定期(默认每 200 毫秒)向 root coord 报告 MsgStream 中最新 InsertMsg 的最大时间戳值。

  • Root coord 识别此 Msgstream 上的最小时间戳值,无论 InsertMsgs 属于哪个 proxy。然后 root coord 将此最小时间戳插入到 Msgstream 中。此时间戳也称为 timetick。

  • 当消费者组件读取 root coord 插入的 timetick 时,它们了解所有具有较小时间戳值的插入消息都已被消费。因此,相关请求可以安全执行而不会中断顺序。

下图是插入了 timetick 的 Msgstream 示例。

timetick

MsgStream 根据时间戳批量处理消息,以确保输出消息满足时间戳的要求。在上面的示例中,它将消费除了 Proxy2Timestamp: 120InsertMsgs 之外的所有记录,因为它在最新的 TimeTick 之后。

下一步