分布式系统:向量时钟

在上一篇文章分布式系统:Lamport 逻辑时钟中咱们知道Lamport 逻辑时钟帮助咱们获得了分布式系统中的事件全序关系,可是对于同时发生的关系却不能很好的描述,致使没法描述事件的因果关系。向量时钟是在 Lamport 时间戳基础上演进的另外一种逻辑时钟方法,它经过向量结构不但记录本节点的 Lamport 时间戳,同时也记录了其余节点的 Lamport 时间戳,所以可以很好描述同时发生关系以及事件的因果关系。html

注意:算法

  • 本文中的因果关系指的是时序关系,即时间的先后,并非逻辑上的缘由和结果
  • 本文中说起的时间戳如无特别说明,都指的是逻辑时钟的时间戳,不是物理时钟的时间戳

为何须要向量时钟

首先咱们来回顾一下 Lamport 逻辑时钟算法,它提供了一种判断分布式系统中事件全序关系的方法:若是 a -> b,那么 C(a) < C(b),可是 C(a) < C(b) 并不能说明 a -> b。也就是说C(a) < C(b) 是 a -> b 的必要不充分条件,咱们不能经过 Lamport 时间戳对事件 a、b 的因果关系进行判断。 下面咱们举一个例子来讲明。 bash

图1
假设有三个进程在发消息,Ts(mi)表示消息mi的发送时间戳,Tr(mi)表示消息mi的接受时间戳,显然 Ts(mi) < Tr(mi),可是这个能说明什么呢?

咱们能够发如今进程 P2 中,Tr(m1) < Ts(m3),说明 m3 是在 m1 被接收以后发送的,也就是说 m3 的发送跟 m1 的接收有关系。难道经过 Lamport 时间戳就能区分事件的因果的关系了吗?答案是 No,咱们仔细看能够发现,虽然 Tr(m1) < Ts(m2),但实际上 m2 的发送跟 m1 并无关系。网络

综上所述,咱们能够发现 Lamport 逻辑时钟算法中每一个进程只拥有本身的本地时间,没有其余进程的时间,致使没法描述事件的因果关系。若是每一个进程都可以知道其余全部进程的时间,是否就可以获得事件的因果关系了呢?为此,有人提出了向量时钟算法,在 Lamport 逻辑时钟的基础上进行了改良,提出了一种在分布式系统中描述事件因果关系的算法。数据结构

可能有人会有疑问:向量时钟到底有什么用呢?举一个常见的工程应用:数据冲突检测。分布式系统中数据通常存在多个副本,多个副本可能被同时更新,这会引发副本间数据不一致,此时冲突检测就很是重要。**基于向量时钟咱们能够得到任意两个事件的顺序关系,结果要么是有因果关系(前后顺序),要么是没有因果关系(同时发生)。**经过向量时钟,咱们可以识别到若是两个数据更新操做是同时发生的关系,那么说明出现了数据冲突。后面咱们会详细说明相关的实现。分布式

什么是向量时钟

经过上面的分析咱们知道向量时钟算法是**在 Lamport 逻辑时钟的基础上进行了改良,用于在分布式系统中描述事件因果关系的算法。**那么为何叫向量时钟呢?前面咱们知道若是每一个进程都可以知道其余全部进程的时间,就可以经过计算获得事件的因果关系。向量时钟算法利用了向量这种数据结构将全局各个进程的逻辑时间戳广播给各个进程:每一个进程发送事件时都会将当前进程已知的全部进程时间写入到一个向量中,附带在消息中。这就是向量时钟命名的由来。post

如何实现向量时钟

假设分布式系统中有 N 个进程,每一个进程都有一个本地的向量时间戳 Ti,向量时钟算法实现以下:3d

  1. 对于进程 i 来讲,Ti[i] 是进程 i 本地的逻辑时间
  2. 当进程 i 当有新的事件发生时,Ti[i] = Ti[i] + 1
  3. 当进程 i 发送消息时将它的向量时间戳(MT=Ti)附带在消息中。
  4. 接受消息的进程 j 更新本地的向量时间戳:Tj[k] = max(Tj[k], MT[k]) for k = 1 to N。(MT即消息中附带的向量时间戳)

下图是向量时钟的示例: cdn

那么如何利用向量时钟判断事件的因果关系呢?咱们知道分布式系统中的事件要么是有因果关系(前后顺序),要么是没有因果关系(同时发生),下面咱们来看一下如何利用向量时钟判断时间的因果关系。htm

假设有事件 a、b 分别在节点 P、Q 上发生,向量时钟分别为 Ta、Tb,若是 Tb[Q] > Ta[Q] 而且 Tb[P] >= Ta[P],则a发生于b以前,记做 a -> b,此时说明事件 a、b 有因果关系; 反之,若是 Tb[Q] > Ta[Q] 而且 Tb[P] < Ta[P],则认为a、b同时发生,记做 a <-> b。例如上图中节点 B 上的第 4 个事件 (A:2,B:4,C:1) 与节点 C 上的第 2 个事件 (B:3,C:2) 没有因果关系,属于同时发生事件。

向量时钟的实际应用

前面咱们提到向量时钟能够用来检测分布式系统中多副本更新的数据冲突问题,注意是检测(发现问题),它并不能解决问题。数据冲突的解决是另外一个课题,这里不展开了。

亚马逊的 Dynamo 是一个分布式Key/Value存储系统,为了高可用,即便在出现网络分区或者机器宕机时依然可读可写。当网络分区恢复以后,多个副本同步数据必定会出现数据不一致的状况,那么如何检测数据冲突呢?参考向量时钟(Vector clock)的思想,Dynamo 中使用了版本向量(Version vector)来检测数据冲突,下面咱们来看看算法的实现。

  1. client 端写入数据,该请求被 Sx 处理并建立相应的 vector ([Sx, 1]),记为数据 D1
  2. 第 2 次请求也被 Sx 处理,数据修改成 D2,vector 修改成([Sx, 2])
  3. 第 三、4 次请求分别被 Sy、Sz 处理,client 端先读取到 D2,而后 D三、D4 被写入 Sy、Sz
  4. 第 5 次更新时 client 端读取到 D二、D3 和 D4 3个数据版本,经过相似向量时钟判断同时发生关系的方法可判断 D三、D4 是同时发生的事件,所以存在数据冲突,最终经过必定方法解决数据冲突并写入 D5

注意,向量时钟和版本向量并非同一个东西,版本向量借鉴了向量时钟中利用向量来判断事件的因果关系的思想,用于检测数据冲突。向量时钟还有其余的应用,例如强制因果通讯(Enforcing Causal Communication),这里不展开了,有兴趣的读者自行谷歌。

总结

向量时钟算法利用了向量这种数据结构将全局各个进程的逻辑时间戳广播给各个进程,经过向量时间戳就可以比较任意两个事件的因果关系(前后关系或者同时发生关系)。向量时钟被用于解决数据冲突检测、强制因果通讯等须要判断事件因果关系的问题。

参考资料

相关文章
相关标签/搜索