分布式系统 逻辑时钟和向量时钟

文章目录

    • 概述
    • 逻辑时钟
      • 什么是逻辑时钟
      • 为什么要有逻辑时钟
      • 逻辑时钟的原理
    • 向量时钟
      • 为什么需要向量时钟
      • 向量时钟的原理
      • 利用向量时钟判断因果关系
      • 向量时钟的应用——冲突检测
    • 逻辑时钟和向量时钟的应用场景

概述

分布式系统解决了传统单体架构的单点问题和性能容量问题,另一方面也带来了很多的问题,其中一个问题就是多节点的时间同步问题:不同机器上的物理时钟难以同步,导致无法区分在分布式系统中多个节点的事件时序。

逻辑时钟

什么是逻辑时钟

逻辑时钟指的是分布式系统中用于区分事件的发生顺序的时间机制。 从某种意义上讲,现实世界中的物理时间其实是逻辑时钟的特例。

为什么要有逻辑时钟

时间是在现实生活中是很重要的概念,有了时间我们就能比较事情发生的先后顺序。如果是单个计算机内执行的事务,由于它们共享一个计时器,所以能够很容易通过时间戳来区分先后。而在分布式系统中的不同节点间保持它们的时钟一致是一件不容易的事情。因为每个节点的CPU都有自己的计时器,而不同计时器之间会产生时间偏移,最终导致不同节点上面的时间不一致

NTP是常用的物理时钟时间同步算法,但是即使通过算法进行同步,总会有误差,这种误差在某些场景下(金融分布式事务)是不能接受的。

因此,Lamport提出逻辑时钟就是为了解决分布式系统中的时序问题,即如何定义a在b之前发生。 值得注意的是,并不是说分布式系统只能用逻辑时钟来解决这个问题,如果以后有某种技术能够让不同节点的时钟完全保持一致,那么使用物理时钟来区分先后是一个更简单有效的方式。

逻辑时钟的原理

在分布式系统中,网络是不可靠的,所以我们去掉可以和速度的约束,可以得到两个事件可以建立因果(时序)关系的前提是:两个事件之间是否发生过信息传递。 在分布式系统中,进程间通信的手段(共享内存、消息发送等)都属于信息传递,如果两个进程间没有任何交互,实际上他们之间内部事件的时序也无关紧要。但是有交互的情况下,特别是多个节点的要保持同一副本的情况下,事件的时序非常重要。

Lamport 定义了一个关系叫做happens-before.记作 ->
a->b意味着所有的进程都agree事件a发生在事件b之前。
在两种情况下,可以很容易的得到这个关系:

  • 如果事件a和事件b是同一个进程中的并且事件a发生在事件b前面,那么a->b
  • 如果进程A发送一条消息m给进程B,a代表进程A发送消息m的事件,b代表进程B接收消息m的事件,那么a->b(由于消息的传递需要时间)

happens-before具有两个特点:

  • happens-before 关系满足传递性:即(a->b && b->c)->(a->c)。如果事件a和事件b发生在不同的进程,并且这两个进程没有传递消息,那么既不能推到a->b也不能推到b->a,这样的两个事件叫做并发事件
  • 假设有事件a、b,C(a)、C(b)分别表示事件对应的Lamport时间戳,如果a发生在b之前(happened before),记作a->b ,则有C(a)如果C(a)b,即C(a)b的必要不充分条件。

Lamport logical clocks的实现:
每个进程Pi维护一个本地计数器Ci,相当于logical clocks,按照以下的规则更新Ci

  1. 每次执行一个事件(例如通过网络发送消息,或者将消息交给应用层,或者其它的一些内部事件)之前,将Ci加1
  2. 当Pi发送消息m给Pj的时候,在消息m上附着上Ci
  3. 当接收进程Pj接收到Pi的发送的消息时,更新自己的Cj = max{Cj,Ci}+1
    分布式系统 逻辑时钟和向量时钟_第1张图片

向量时钟

为什么需要向量时钟

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

Lamport 逻辑时钟算法中每个进程只拥有自己的本地时间,没有其他进程的时间,导致无法描述事件的因果关系。如果每个进程都能够知道其他所有进程的时间,是否就能够得到事件的因果关系了呢?为此,有人提出了向量时钟算法,在 Lamport 逻辑时钟的基础上进行了改良,提出了一种在分布式系统中描述事件因果关系的算法。

向量时钟的原理

用VC(a)来表示事件a的Vector Clock,有如下性质:VC(a) < VC(b)可以推出事件a causally 发生在事件b之前(也就是事件a发生在事件b之前)。
假设有N个进程,每个进程Pi维护一个向量VC,也就是Pi的Vector Clock,这个向量VC有如下属性:

  • VCi[i] 是到目前为止进程Pi上发生的事件的个数
  • VCi[k] 是进程Pi知道的进程Pk发生的事件的个数(即Pi对Pj的知识)

每个进程的VC可以通过以下规则进行维护:

  1. 进程Pi每次执行一个事件之前,将VCi[i]加1
  2. 当Pi发送消息m给Pj的时候,在消息m上附着上VCi(进程Pi的向量时钟)
  3. 当接收进程Pj接收到Pi的发送的消息时,先将自己的逻辑时钟VCj[j]加1,再更新自己的VCj[k] = max{VCj[k],VCi[k]} for k = 1 to N
    分布式系统 逻辑时钟和向量时钟_第2张图片

利用向量时钟判断因果关系

分布式系统中的事件要么是有因果关系(先后顺序),要么是没有因果关系(同时发生)。向量时钟V1上的各个时间分量如果全部都小于等于V2上各个时间分量,则认为V1比V2早。向量时钟V1上的各个时间分量有的比V2上的时间分量大,有的比其小,则认为是同时发生。

向量时钟的应用——冲突检测

分布式系统中数据一般存在多个副本,多个副本可能被同时更新,这会引起副本间数据不一致,此时冲突检测就非常重要。基于向量时钟我们可以获得任意两个事件的顺序关系,结果要么是有因果关系(先后顺序),要么是没有因果关系(同时发生)。通过向量时钟,我们能够识别到如果两个数据更新操作是同时发生的关系,那么说明出现了数据冲突。注意是检测(发现问题),它并不能解决数据冲突。

逻辑时钟和向量时钟的应用场景

逻辑时钟可以保证因果一致性,但是无法检测和解决并发冲突的问题。但是在某些场景下,不需要检测并发冲突,或者可以使用很简单的方法进行并发合并,参考:https://blog.csdn.net/qq_41775852/article/details/114398738,则可以使用逻辑时钟。

向量时钟可以明确的检测出因果关系和并发冲突,对于需要检测并发冲突的场景,可以使用向量时钟。

参考博客:
https://www.cnblogs.com/ningskyer/articles/7446273.html
https://www.cnblogs.com/s-lisheng/p/11329601.html
https://juejin.im/post/5c54103b51882562c0494cc0
https://blog.csdn.net/weixin_33910385/article/details/88022056

你可能感兴趣的:(分布式系统)