Lamport's Logical Clocks
为了同步logical clocks,Lamport 定义了一个关系叫做happens-before.记作 ->
a->b意味着所有的进程都agree事件a发生在事件b之前。
在两种情况下,可以很容易的得到这个关系:
1 如果事件a和事件b是同一个进程中的并且事件a发生在事件b前面,那么a->b
2 如果进程A发送一条消息m给进程B,a代表进程A发送消息m的事件,b代表进程B接收消息m的事件,那么a->b(由于消息的传递需要时间)
happens-before 关系满足传递性:即(a->b && b->c)->(a->c)
如果事件a和事件b发生在不同的进程,并且这两个进程没有传递消息,那么既不能推到a->b也不能推到b->a,这样的两个事件叫做并发事件
现在需要定义一个事件的函数C,使得[a->b]->[C(a)<C(b)],并且由于是作为一种对时间的衡量,所以C也必须是只增不减的。
Lamport 算法
三个机器上各自跑着一个进程,分别为P1,P2,P3,由于不同的机器上的quartz crystal不一样,所以不同的机器上的时钟速率可能是不同的,例如当P1所在
的机器tick了6次,P2所在的机器tick了8次。
图中,P1给P2发送了消息m1,m1上附带了发送m1时的时钟6,随后P2收到了m1,根据P2接收到m1时的时钟,认为传输消息花了16-6=10个tick
随后,P3给P2发送消息m3,m3附带的发送时钟是60,由于P2的时钟走的比P3的慢,所以接收到m3时,本机的时钟56比发送时钟60小。这是不合理的,需要调整时钟,
如图中,将P2的56调整为61,即m3的发送时钟加1
Lamport logical clocks的实现:
每个进程Pi维护一个本地计数器Ci,相当于logical clocks,按照以下的规则更新Ci
1 每次执行一个事件(例如通过网络发送消息,或者将消息交给应用层,或者其它的一些内部事件)之前,将Ci加1
2 当Pi发送消息m给Pj的时候,在消息m上附着上Ci
3 当接收进程Pj接收到Pi的发送的消息时,更新自己的Cj = max{Cj,Ci}
Vector Clocks
Lamport logical clocks可以保证(a->b)->( C(a)<C(b) ),但是不能保证( C(a)<C(b) )->(a->b)
也就是说,Lamport logical clocks的问题是:事件a和事件b实际发生的先后顺序不能仅仅通过比较C(a)和C(b)来决定。
这是因为Lamport logical clocks没有capture causality(因果关系),而causality可以通过Vector Clocks来capture,用VC(a)来表示事件a的Vector Clock,
有如下性质:VC(a) < VC(b)可以推出事件a causally 发生在事件b之前(也就是事件a发生在事件b之前)
为每个进程Pi维护一个向量VC,也就是Pi的Vector Clock,这个向量VC有如下属性:
1 VCi[i] 是到目前为止进程Pi上发生的事件的个数
2 VCi[k] 是进程Pi知道的进程Pk发生的事件的个数(即Pi对Pj的知识)
每个进程的VC可以通过以下规则进行维护(和Lamport logical clocks算法类似):
1 进程Pi每次执行一个事件之前,将VCi[i]加1
2 当Pi发送消息m给Pj的时候,在消息m上附着上VCi(进程Pi的向量时钟)
3 当接收进程Pj接收到Pi的发送的消息时,更新自己的VCj[k] = max{VCj[k],VCi[k]} ,对于所有的k
causally-ordered multicasting
一个进程组中,每个进程需要广播消息给其它进程(相当于一个并发更新问题),一个消息被delivered到应用层,仅当所有的causally发生之前的消息都被收到
假设:Pi给Pj发送消息m,那么Pj可以将消息m交给应用层必须首先满足上面两个条件:
1 VCj[i] = VCi[i] - 1
2 VCi[k] <= VCj[k] for all k≠i
第一个条件的意思是指Pj看到了Pi发生的所有的事件(不包括本次发送消息m的时间)
第二个条件意味着,Pj看到了其它的所有的进程看到的事件。
以上两个条件说明,对消息m做下一步动作(比如本例中的将消息m交给应用层)之前,所有的m依赖的消息都收到了。
例子:
首先P0给P1和P2广播消息m,P1很快收到了消息m,然后P1马上给P0和P2广播消息m*,P2也很快收到了消息m*,但是不能将m* delivered给应用程序,
因为VC1[0] > VC2[0](违反了条件2,因为P2还没有收到P0广播的消息m),随后在P2收到了m后,两个条件都满足了,就可以把消息delivered给应用层了。
Dynamo也用了Vector Clock来capture causality,解决冲突,具体需要再看论文。