「分布式技术专题」时钟系列一:事件的因果和逻辑时钟

随着数据量的上升,传统单机架构存在的瓶颈已不能满足对性能和容量的要求,从而分布式系统变得越来越火热,但另一方面, 分布式也带来了很多相对于单机架构不同的问题。其中一个问题就是多节点的时间同步问题:不同节点上的物理时钟难以同步,导致无法区分在分布式系统中多个节点的事件顺序。

早在1978年,Lamport在《Time, Clocks and the Ordering of Events in a Distributed System》中,就提出了逻辑时钟的概念,就是用来解决分布式系统中事件发生的顺序问题。

事件的因果

“Time is an illusion.”爱因斯坦如是说。

逻辑时钟是Lamport在1978年提出的一种在分布式系统中对事件进行时间戳排序的方法,在其中定义了因果关系,称为before。

例如,before在航班满员,航班可预订。这里“事件预订”before“航班满员”,预订和满员就形成了因果关系。

现实世界中,确定事件预订发生在事件满员之前,需要预订发生在比满员更早的时间。 因果关系是一个事件(因)和第二个事件(果)之间的作用关系, 其中后一个事件被认为是前一个事件的结果。 一般来说,一个事件是很多原因综合产生的结果, 而且原因都发生在较早的时间点。

而在分布式系统中,有时不可能说两个事件中的一个首先发生。 关系“happened before”只是系统中事件的部分排序。

部分排序

在分布式系统中,事件A发生在事件B之前,如果A发生在比B更早的时间,需要系统正确的满足规范。 如果分布式系统以物理时间为单位,可能存在时钟不完全准确,没办法保持精确的物理时间的问题。 因此,在逻辑时钟论文里,定义了“before”关系,而不使用物理时钟。

“before”标记为=>,需要满足三个条件:

如果a和b是同一进程中发生的事件,且a先于b,则a->b

如果a是一个进程中的发送消息,b是另一个进程中接收此消息,那么a->b

如果a->b并且b->c,那么a->c。两个事件是并发的,如果a≠>b和b≠>a

对于任意事件a,定义a≠>a。

另一种说法是a->b意味着事件a是事件b的因。两个事件并发说明二者不能发生因果影响, 两个事件相互独立。这就意味着部分排序。

这样,在分布式系统中,事件的顺序可以根据发送的消息来定义,只考虑实际发送的消息。

逻辑时钟

由部分排序可知,问题的关键点在于节点间的交互要在事件发生顺序上达成一致, 而不是对于时间达成一致。所以,逻辑时钟指的是分布式系统中用于区分时间发生顺序的机制。 从某种意义上来讲,现实世界的物理时间其实是逻辑时钟的特例。

分布式系统中,按是否存在节点交互可分为三类事件,节点内部,发送事件,接收事件。

Lamport逻辑时钟的原理如下:

每个事件对应一个Lamport时间戳,初始值为0.

如果事件发生在节点内部,本地进程中的时间戳加1.

如果事件是发送事件,本地进程中的时间戳加1并在消息中带上该时间戳

如果事件属于接收事件,本地进程中的时间戳 = Max(本地时间戳,消息中的时间戳) + 1

下面详细说明逻辑时钟的原理。

单机多进程程序可以由锁进行同步,因为这些进程都运行在操作系统上, 可以由操作系统为它们进行排序,操作系统知道所有需要同步进程的所有信息。 但是在分布式系统中,各个进程运行在各个节点上, 那么分布式系统中多进程怎么进行同步呢?

把逻辑时钟引入到系统中,由一个抽象观点开始,在这个观点中时钟只是给事件分配数字的一种方式, 其中这个数字就是事件发生的时间。给每个进程Pi分配时钟Ci,时钟Ci是一个函数,负责分配数字, 例如为事件a分配时钟为Ci(a)。系统时间函数C为任意事件b分配时间C(b)=Cj(b),如果b是发生在进程Pj下。 这里的时钟是逻辑时钟不是物理时钟,C函数可以是与物理时钟无关的计数器实现。

这里由于论文时间较早,所以都是以线程为例,可以推广到分布式节点。

逻辑时钟的定义必须基于事件发生的顺序而不是物理时钟。如果事件a发生在事件b之前, 那么a应该发生在b的更早时间。表述如下:如果a->b,那么C(a)

logic_clock1

如图1,这里p1,p2,p3都与q3并发,这意味着它们都和q3同一时间发生,但这与时间条件相矛盾, 因为p2->p3。

对关系的定义中很容易看出,如果以下两个条件成立,则时钟条件是满足的。

• 条件1,如果a和b都是进程Pi中的事件,并且a->b,那么Ci(a)

• 条件2,如果a是Pi发送一个消息的事件,b是Pj中接收这个消息的事件,那么Ci(a)

考虑时空图,假设一个进程时钟ticks分配数字,发生在进程事件之间。 例如a和b是Pi的连续事件,Ci(a)=4,Ci(b)=7,时钟心跳5,6,7发生在两个事件之间。 这样可以在不同进程的所有相似的ticks之间画一条虚线形成图1空间图,如图2。

logic_clock1

条件1意味着同一进程上的任意事件之间必须要虚线,条件2意味着图中每个消息线都要跨越虚线。 从图中可以看出为什么这两个条件是时钟条件。

进程Pi的时钟用Ci表示,Ci(a)表示事件a的时钟。事件之间Ci的值会变化,改变Ci本身并不构成事件。

为了确保满足时钟条件1,2,需要遵守以下实现规则:

• IR1. 每个进程Pi在两个连续事件之间递增Ci.

• IR2. (a)如果a是进程Pi发送消息m的事件,则消息m包含时间戳Tm=Ci(a)

• IR2. (b)在收到消息m时,处理Pj设置Cj大于或等于现在Tm的值

进行全局事件排序,可以使用满足时钟条件的时钟系统在所有系统事件的集合上进行总排序。

能够对事件进行完全排序,对于实现分布式系统非常有用。 实现一个正确的逻辑时钟系统就是为了获得这样的总排序。 考虑共享资源的进程或节点固定的集合组成的系统,一次只能有一个进程或者节点使用资源, 因此进程必须同步自己,以避免发生冲突。

论文提到解决这一问题要满足三个条件:

Ⅰ 已被授予资源的进程必须先将其释放,然后才能将其授予另一个进程。

Ⅱ 对资源的不同请求必须按请求的顺序授予。

Ⅲ 如果每个被授予资源的进程最终都会释放,那么每个请求最终都会被接受。

为解决这些问题,并实现一个满足条件的时钟系统,满足规则IR1和IR2。 定义一个=>用来给全部事件排序。有了这个顺序,找到一个解决方案就变得简单了, 它只涉及确保每个进程或节点知道所有其他进程或节点的操作了。

为了简化问题,进行一些不是必须的假设,这些假设的引入是为了避免分散实现细节。 假设对于两个进程Pi和Pj,从Pi发送到Pj的消息时以相同的顺序接收的。 此外,我们假设每个消息最终都被接收。并且假设一个进程可以直接向每个其他进程发送消息。

每个进程都维护自己的请求队列,这是任何其他进程都看不到的。 假设请求队列最初包含单个消息T0:P0请求资源,其中P0是最初授予资源的进程, T0小于任何时钟的初始值。

通过五条规则定义算法,为了方便起见,假设每个规则定义的操作形成单个事件。

要请求资源,进程Pi发送消息Tm:Pi请求给每个其他进程,并将该消息放到其请求队列中, 其中Tm是消息的时间戳。

每个进程Pj接收请求资源消息Tm:Pi,它将其放置在请求队列中,并向Pi发送一个带有时间戳的确认消息。

为了释放资源,进程Pi从其请求队列中删除Tm:Pi请求西苑消息,并且发送Pi时间戳释放资源消息到其他进程。

当进程Pj接收一个Pi释放资源消息时,它从其请求队列中删除任一Tm:Pi请求资源。

当满足以下两个条件时,进程Pi被赋予资源:(1)在其队列中由一个Tm:Pi消息,它在队列中 =>其他请求。(为了定义=>,我们定义一个消息,使用发送消息的事件来识别。)

(2)Pi收到比Tm更晚的每一个其他进程的消息。

可以很容易的看到算法满足条件Ⅰ-Ⅲ。

举例说明,假设有3个进程,根据算法说明,初始化状态各个进程队列里面都是(0,0)状态, 此时锁属于P0。

logic_clock3

接着P1会发送请求资源的消息给所有其他进程,并且放到自己的请求队列里面, 根据算法,P1的时钟计数变为1,而接受消息的P0和P2的时钟为消息时间戳+1。

logic_clock4

收到P1的请求之后,P0和P2要发送确认消息给P1表示自己已经收到了。 由于目前请求队列里面第一个不是P1发出的请求,所以此时锁仍属于P0。 但是由于收到了确认消息,此时P1已经满足了获取资源的第一个条件: P1已经收到了其他所有进程时间戳大于1的消息。

logic_clock5

假设P0此时释放了锁,发送释放资源的消息给P1和P2,P1和P2收到消息后把请求(0,0) 从队列中删除。

logic_clock6

当P0释放了资源之后,P1满足了获取资源的两个条件,它的请求在队列最前面和P1 已经收到了其他所有进程时间戳大于1的消息。也就是此时P1获得了锁。

总结

在逻辑时钟的论文中描述的算法大致就像上面描述的一样,但显而易见,这个算法并不是容错的,只要有一个进程挂了或者响应很慢,都会影响到整个分布式系统。

但逻辑时钟的思路就如上面描述的那样,是整个分布式一致性算法的基石, 所有的分布式一致性算法都有逻辑时钟的影子在内。 逻辑时钟定义了分布式系统里面的时间概念,解决了分布式系统中区分时间发生的时序问题。

实际上后续产生的矢量时钟、全局时钟亦或者混合时钟,都是对逻辑时钟的增强, 其基础都是逻辑时钟。

以上为事件的因果和逻辑时钟,「分布式技术专题」是国产数据库hubble团队精心整编,专题会持续更新,欢迎大家保持关注。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容