时间同步
本主题介绍 Milvus 的时间同步机制。
概述
Milvus 中的事件一般可分为两类:
-
数据定义语言(DDL)事件:创建/删除 Collection、创建/删除 Partition 等。
-
数据操作语言(DML)事件:插入、搜索等。
任何事件,不管是 DDL 还是 DML 事件,都标有一个时间戳,可以显示该事件发生的时间。
假设有两个用户在 Milvus 中发起了一系列 DML 和 DDL 事件,时间顺序如下表所示。
| 时间戳 | 用户 1 | 用户 2 |
|---|---|---|
| t0 | 创建了一个名为C0 的 Collection。 | / |
| t2 | / | 在C0 库中进行搜索。 |
| t5 | 将数据A1 插入数据集C0. | / |
| t7 | / | 在文集C0 中进行搜索。 |
| t10 | 将数据A2 插入数据集C0. | / |
| t12 | / | 对数据集进行搜索C0 |
| t15 | 从数据集中删除数据A1 C0 . | / |
| t17 | / | 对数据集进行搜索C0 |
理想情况下,用户 2 应该能够看到
-
一个空的 Collection
C0在t2. -
数据
A1,网址t7。 -
数据
A1和A2均位于t12。 -
只有
t17上的数据A2(因为在此之前,数据A1已从 Collection 中删除)。
当只有一个节点时,这种理想情况很容易实现。但是,Milvus 是一个分布式向量数据库,为了确保不同节点中的所有 DML 和 DDL 操作都能保持有序,Milvus 需要解决以下两个问题:
-
上面例子中的两个用户如果在不同的节点上,他们的时间时钟是不同的。例如,如果用户 2 比用户 1 晚 24 小时,那么用户 1 的所有操作在第二天之前都不会被用户 2 看到。
-
可能存在网络延迟。如果用户 2 在
t17上对 CollectionC0进行搜索,Milvus 应能保证t17之前的所有操作都被成功处理并完成。如果t15上的删除操作因网络延迟而延迟,那么用户 2 在t17上进行搜索时,很可能仍能看到本应删除的数据A1。
因此,Milvus 采用了时间同步系统(timetick)来解决这些问题。
时间戳甲骨文(TSO)
为了解决上一节提到的第一个问题,Milvus 和其他分布式系统一样,提供了时间戳甲骨文(TSO)服务。这意味着 Milvus 中的所有事件都必须分配一个来自 TSO 而不是本地时钟的时间戳。
TSO 服务由 Milvus 的根协调器提供。客户端可以在单个时间戳分配请求中分配一个或多个时间戳。
TSO 时间戳是一种uint64 值,由物理部分和逻辑部分组成。下图展示了时间戳的格式。
TSO_Timestamp.
如图所示,开头的 46 位是物理部分,即以毫秒为单位的 UTC 时间。最后 18 位是逻辑部分。
时间同步系统(timetick)
本节以数据插入操作为例,解释 Milvus 的时间同步机制。
当代理收到 SDK 的数据插入请求时,它会根据主键的哈希值将插入信息分成不同的信息流 (MsgStream) 。
每条插入信息 (InsertMsg) 在发送到MsgStream 之前都会被分配一个时间戳。
MsgStream Timesync_proxy_ins 是消息队列的封装器,在 Milvus 2.0 中默认为 Pulsar。
timesync_proxy_insert_msg
一般原则是,在MsgStream 中,来自同一代理的InsertMsgs 的时间戳必须是递增的。但是,来自不同代理的InsertMsgs 的时间戳却没有这样的规则。
下图是InsertMsgs 在MsgStream 中的示例。该代码段包含五个InsertMsgs ,其中三个来自Proxy1 ,其余来自Proxy2 。
msgstream
来自Proxy1 的三个InsertMsgs 的时间戳是递增的,来自Proxy2 的两个InsertMsgs 的时间戳也是递增的。但是,Proxy1 和Proxy2 InsertMsgs 之间没有特定的顺序。
Proxy1 一种可能的情况是,当从Proxy2 读取时间戳为110 的信息时,Milvus 发现时间戳为80 的信息仍在MsgStream 中。因此,Milvus 引入了时间同步系统 timetick,以确保从MsgStream 读取信息时,必须消耗掉所有时间戳值较小的信息。
时间同步
如上图所示、
-
每个代理定期(默认情况下每 200 毫秒)向根协调器报告
MsgStream中最新InsertMsg的最大时间戳值。 -
根协调器会识别该
Msgstream上的最小时间戳值,无论该InsertMsgs属于哪个代理。然后,根协调器将这个最小时间戳插入Msgstream。这个时间戳也称为 timetick。 -
当消费者组件读取根协调器插入的时间戳时,它们就会明白所有时间戳值较小的插入信息都已被消耗。因此,可以在不中断订单的情况下安全地执行相关请求。
下图是Msgstream 插入时间刻度的示例。
时间戳
MsgStream 根据时间刻度分批处理报文,以确保输出的报文符合时间戳的要求。