分布式系统:向量时钟
Lamport时钟存在的问题
使用Lamport时间戳,只是比较事件\(a\)和\(b\)各自的时钟值\(C\{a\}\)和\(C\{b\}\),无法说明它们之间的关系。也就是说,\(C\{a\}<C\{b\}\)不能说明事件\(a\)在事件\(b\)之前发生。比如下面的事件\(C4\)与\(A3\),\(C\{A3\}<C\{C4\}\),但是在时间上事件\(A3\)在\(C4\)之后发生。
所以,Lamport时间戳的问题在于它不能捕获事件的因果关系,为了解决这个问题,有大神提出了向量时钟。
向量时钟
Vector clock是在Lamport时间戳基础上演进的另一种逻辑时钟方法,它通过vector结构不但记录本节点的Lamport时间戳,同时也记录了其他节点的Lamport时间戳。即,当系统有\(N\)个进程时,则存在\(N\)个逻辑时钟向量,一个进程对应一个时钟。具体如下:
- 初始时所有时钟都为0;
- 每一次处理内完内部事件,将本进程对应的逻辑时钟+1;
- 每一次发送一个消息的时候,需要将自己的向量时钟和消息一起发送;
- 每一次接收到一个消息,需要将自己的逻辑时钟+1,同时更新每一个逻辑时钟,更新规则为取本地逻辑时钟和收到的逻辑时钟的最大值。
假设分布式系统有A、B和C这3个进程,根据上述规则其各自对应的逻辑时钟随着时间演化情况如图所示,其数值变化规则遵循上述规则,时间线之间的边代表进程间发送的消息。标为cause的阴影部分代表导致[A:2,B:4,C:1]事件的原因,标为effect的阴影部分则代表[A:2,B:4,C:1]事件影响到的后续事件,而无阴影部分覆盖的事件则是和[ A:2,B:4,C:1]事件无逻辑上因果关系的事件。
事件关系判断方法:
- 正常情况下,向量时钟V1上的各个时间分量如果全部都小于等于V2上各个时间分量,则认为V1比V2早。举个例子说明,比如事件[A:1,B:2,C:1]以及[A:4,B:5,C5],通过和[A:2,B:4,C:1]对应位置比较可知其因果关系为:[A:1,B:2,C:1]为[A:2,B:4,C:1]之因,[A:4,B:5,C5] 为[A:2,B:4,C:1]之果。
- 向量时钟V1上的各个时间分量有的比V2上的时间分量大,有的比其小,则认为是同时发生。比如事件[A:2,B:4,C:1]与事件[ ,B:3,C:3]。
向量时钟的应用——冲突检测
可能有人会有疑问:向量时钟到底有什么用呢?举一个常见的工程应用:数据冲突检测。分布式系统中数据一般存在多个副本,多个副本可能被同时更新,这会引起副本间数据不一致,此时冲突检测就非常重要。基于向量时钟我们可以获得任意两个事件的顺序关系,结果要么是有因果关系(先后顺序),要么是没有因果关系(同时发生)。通过向量时钟,我们能够识别到如果两个数据更新操作是同时发生的关系,那么说明出现了数据冲突。注意是检测(发现问题),它并不能解决数据冲突。
下面我们举个向量时钟应用的例子,以一个例子来说明如何使用时钟向量,来维护一个分布式系统的一致性。
Alice, Ben, Cathy, Dave四个人准备下周聚餐,在时间安排上协调出现了问题。首先,Alice提出Wednesday聚餐,那么对提出这个提议的Alice来说,此时她的时钟向量就是这样的:
date = Wednesday
vclock = Alice:1
她将这个消息广播给其他三个人:
Ben在收到提议之后,提出自己的提议Tuesday,此时ben的时钟向量就是:
date = Tuesday
vclock = Alice:1, Ben:1
然后将消息发送给Dave:
Dave收到之后,回复Ben表示同意Tuesday,此时Dave的时钟向量是:
date = Tuesday
vclock = Alice:1, Ben:1, Dave:1
现在Cathy参与进来,建议Thursday,此时Cathy的时钟向量是:
date = Thursday
vclock = Alice:1, Cathy:1
然后将提议发送给了Dave:
Dave此时就有了两份有冲突的数据(冲突的原因是Ben和Cathy“同时”修改了最初Alice的数据):
date = Tuesday
vclock = Alice:1, Ben:1, Dave:1
和
date = Thursday
vclock = Alice:1, Cathy:1
根据时钟向量的关系判断规则,Dave发现了冲突,因为当前的向量时钟和新接收到的向量时钟上的各个逻辑时钟并不是全部小于或大于。幸运的是,Dave是个有理性的人,选择了Thursday(前面是发现冲突,这里相当于解决冲突,实际系统中解决冲突的方法不同,解决冲突不是向量时钟的内容)。Dave解决冲突并回复给Cathy,此时Dave的向量时钟为:
date = Thursday
vclock = Alice:1, Ben:1, Cathy:1, Dave:2
至此,当Alice问Ben和Cathy最新的决定,会收到来自Ben的:
date = Tuesday
vclock = Alice:1, Ben:1, Dave:1
和来自Cathy的:
date = Thursday
vclock = Alice:1, Ben:1, Cathy:1, Dave:2
这样,Alice她可以说Dava与Cathy一致修改了自己和Ben的提议,并将Cathy的消息给Ben,Ben就知道它的提议已经被修改。
现在,它们愉快的达成了一致。对于整个协商的过程,可以看到冲突的根源在于Ben和Cathy都“同时”修改了Alice的数据,Dave解决了数据冲突(不同问题,解决数据冲突的方法不同),最后它们达成一致。
参考文档:
Vector clock
Dynamo: Amazon’s Highly Available Key-value Store
分布式系统:向量时钟(部分内容翻译自上文)
Why Vector Clocks Are Hard
时钟向量在一致性问题中的应用(部分内容翻译自上文)
Timestamps in Message-Passing Systems That Preserve the Partial Ordering
公众号: