概述
Lamport逻辑时钟无法捕获因果关系,使用向量时钟来捕获因果关系。
Lamport逻辑时钟导致分布式系统中所有事件都要经过排序以具有这样的性质:如果事件a在事件b之前发生,那么事件a也应该排在b之前,即C(a)<C(b)。但是经过Lamport逻辑时钟排序的先发生关系的事件可能无法说明他们之间的关系(在并发情况下)。
使用Lamport逻辑时间表示上图消息顺序:
C(m1)<C(m2)<C(m3)<C(m4)<C(m5),其中<表示Happen-before关系。
如果使用Lamport逻辑时钟我们可以得到消息m1先于消息m2和消息m3,但是使用Lamport逻辑时间我们只能得到这样的结论。实际情况是消息m3是因为进程P3发送了消息m2,进程P2才发送了消息m3给进程P3而和消息m1没有任何关系。
这是因为Lamport逻辑时间不能表示因果关系:消息m1的发送并不是消息m2接收的原因和消息m3发送的结果。
向量时钟-因果关系
因果关系是事件原因先于事件的结果。
向量时钟是使用向量并结合Lamport逻辑时钟来捕获因果关系。
假设我们分配事件a的向量时钟VC(a)这样的性质:对于一个事件b,VC(a)<VC(b)表示事件a在因果关系上先于事件b,换句话说就是事件a是事件b发生的原因,而事件b是事件a发生的结果。
向量时钟是通过让每个进程Pi维护一个向量VCi来完成的,向量时钟的有以下两个性质:
- VCi[i]是进程Pi截止到目前为止事件发生的数量(也就是自己进程发生的事件数量);
- 如果VCi[j]=K,那么进程Pi就知道进程Pj中已经发生了K个事件。因此,进程Pi知道了进程Pj的逻辑时间。
向量时钟-实现
- 每个进程初始化有一个Lamport逻辑时间的计数器使用VCi[i]来维护;
- 每个进程在发送的消息中携带向量来维护。
向量时钟-实现步骤
- 在执行一个事件之前,Pi执行VCi[i] = VCi[i] + 1;
- 当进程Pi发送一个消息m给Pj时,在执行第一步后,把m的时间戳ts(m)设置等于VCi;
- 在接收消息m时,进程Pj通过为每个k设置VCj[k]<-max{VCj, ts(m)[k]}来调整自己的向量。
向量时钟-演示
假设有三个进程P1、P2和P3
图描述
红线和绿线曲线表示消息有信道延迟,其中红线曲线表示消息乱序(可见向量时钟的顺序性弱)。
文字描述
-
进程P1在逻辑时间0并发向进程P2和P3发送消息,此时进程P2和P3的逻辑时间为0,收到消息后进程P2和P3更新P1的逻辑时间为1;
-
进程P2发送消息给进程P1和P3,但是消息传输有延迟,在P3接收到P1的消息后才接收到P2的消息
因果关系
因果关系(causality或causation)是一个事件(即“因”)和第二个事件(即“果”)之间的作用关系,其中后一事件被认为是前一事件的结果。一般来说,一个事件是很多原因综合产生的结果,而且原因都发生在较早时间点,而该事件又可以成为其他事件的原因。
参考
- 分布式原理与范型(第2版)
- 因果关系