分布式系统:逻辑时钟与向量时钟

1. 为什么要引入逻辑时钟(Logic Clock)?

在分布式系统中,不同的机器的时间可能不一样,使用时间戳(timestamp)的方式会导致产生误差。也许你会说让机器定期进行 NTP 时间同步,但是在一个集群中,不同机器内部时间计算也会产生误差,可能有些机器时间前进的快点,有些机器会慢点,这种现象也叫时钟漂移(Clock Drift)。

2. 如何实现逻辑时钟(Logic Clock)?

Logic Clock 中最出名的就是 Lamport Timestamp。通过逻辑时间,我们可以判断不同事件的因果顺序关系。

Lamport Timestamp 算法的实现遵循以下规则:

  • 每一台机器内部都有一个时间戳(Timestamp),初始值为 0。
  • 机器执行一个事件(event)之后,该机器的 timestamp + 1。
  • 当机器发送信息(message)给另一台机器,它会附带上自己的时间戳,如 <message, timestamp> 。
  • 当机器接受到一条 message,它会将本机的 timestamp 和 message 的 timestamp 进行对比,选取大的 timestamp 并 +1。

首先规定一个事件 A 的逻辑时间戳表示方式为 C(A)。下面所有的时间戳都为逻辑时间戳,不是机器真实时间。

如果事件 A 在事件 B 之前发生,叫做 happened-before,表示为 A->B,那么事件 A 的时间戳一定小于事件 B。即表达为:

A\to B\Rightarrow C(A)<C(B)

但是我们要注意这种推导关系是不能反过来的:

C(A)<C(B)\nRightarrow A\to B

比如上图 Q 中的事件 3 和 R 中的事件 1,虽然 3>1,但是它们之间没有因果关系,它们是并行 (concurrent) 的或者是独立的(independent)。

我们还可以知道,如果 C(A) <= C(B) ,那么事件 B 是绝对不可能发生在事件 A 之前:

C(A)<=C(B)\Rightarrow B\nrightarrow A

当然,如果事件 A 和 事件 B 的时间戳相同,则它们是并行独立的,即

C(A)=C(B)\Rightarrow A\nleftrightarrow B

3. 为什么要引入向量时钟(Vector Clock)?

但是 Lamport Timestamp 不能很好的满足分布式系统,比如你不能区分两个事件是否有关联,或者在一个多点读的 key-value 数据库中,你无法确定保存哪一份副本(通常保存最新的那份副本)。

如下图所示,你其实无法单纯的通过 logic clock 比较来判断 Process 1 中的事件 3 和 Process 2 中的事件 8 是否有关系。

如果事件 3 执行时间延迟几秒,这不会影响到事件 8。所以两个事件互不干涉,为了判断两个事件是否为这种情况,我们引入了 Vector Clock(向量逻辑时间)

4. 如何实现向量时钟(Vector Clock)?

Vector Clock 是通过向量(数组)包含了一组 Logic Clock,里面每一个元素都是一个 Logic Clock。如上图,我们有 3 台机器,那么 Vector Clock 就包含三个元素,每一个元素的索引(index)指向自己机器的索引。

我们遵循以下规则:

  • 每一台机器都初始化所有的 timestamp 为 0。例如上面的例子,每一台机器初始的 Vector Clock 均为 [0, 0, 0]
  • 当机器处理一个 event,它会在向量中将和自己索引相同的元素的 timestamp + 1。例如 1 号 机器处理了一个 event,那么 1 号机器的 Vector Clock 变为 [1, 0, 0]
  • 每当发送 message 时,它会将向量中自己的 timestamp + 1,并附带在 message 中进行发送。如 <message, vector> 。
  • 当一台机器接收到 message 时,它会把自己的 Vector Clock 和 message 中的 Vector Clock 进行逐一对比(每一个 timestamp 逐一对比),并将 timestamp 更新为更大的那个(类似于 Lamport Timestamp 的操作)。然后它会对代表自己的 timestamp + 1。

由此我们也可以知道,如果 A->B ,那么 A  的 Vector Clock 中的每一个元素都会小于 B  中的每一个元素。

判断两个事件是否并行或独立

回到刚刚判断两个事件是不是有关联,我们可以看到 Process 1 中的 [3, 0, 0] 和 Process 2 中的 [2, 4, 2] ,其中 3 > 2 而 0 < 4,0 < 2 。有些 timestamp 大于对方,而有些 timestamp 又小于对方,由此我们可以得知这两个事件是互不相干的。

以下是另一个例子:

5. 逻辑时钟和向量时钟的习题例子

请标出下图中各个事件的 Lamport 逻辑时钟和向量时钟。

逻辑时钟:

回顾 Lamport Timestamp 算法的实现规则:

  • 每一台机器内部都有一个时间戳(Timestamp),初始值为 0。
  • 机器执行一个事件(event)之后,该机器的 timestamp + 1。
  • 当机器发送信息(message)给另一台机器,它会附带上自己的时间戳,如 <message, timestamp> 。
  • 当机器接受到一条 message,它会将本机的 timestamp 和 message 的 timestamp 进行对比,选取大的 timestamp 并 +1。

向量时钟:

回顾向量时钟的实现规则:

我们有 n 台机器,那么 Vector Clock 就包含 n 个元素,每一个元素的索引(index)指向自己机器的索引。

  • 每一台机器都初始化所有的 timestamp 为 0。
  • 当机器处理一个 event,它会在向量中将和自己索引相同的元素的 timestamp + 1。
  • 每当发送 message 时,它会将向量中自己的 timestamp + 1,并附带在 message 中进行发送。如 <message, vector> 。
  • 当一台机器接收到 message 时,它会把自己的 Vector Clock 和 message 中的 Vector Clock 进行逐一对比(每一个 timestamp 逐一对比),并将 timestamp 更新为更大的那个(类似于 Lamport Timestamp 的操作)。然后它会对代表自己的 timestamp + 1。


参考链接:https://www.jianshu.com/p/081ccf63fe6
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值