分布式系统:时间、时钟和事件序列

在程序中,我们经常需要知道事件序列,在单体应用中,事件序列是较为简单的,最简单的办法就是用时间戳,但在分布式系统中,事件序列是很困难的,Leslie Lamport大神在论文Time, Clocks, and the Ordering of Events in a Distributed System讨论了在分布式系统中时间、时钟和事件序列的问题。

【1】分布式系统中物理时钟存在的问题

逻辑时钟是相对物理时钟这个概念的,为什么要提出逻辑时钟,因为物理时钟在分布式系统中存在一系列问题。在一台机器上的多个进程可以从一个物理时钟中获取时间戳,不管这个物理时钟是否准确,只要是从一个物理时钟获取时间戳,我们都能获得多个事件的相对时间顺序。但是在分布式系统中,我们无法从一个物理时钟获取时间戳,只能从各自机器上物理时钟获取时间戳,而各台机器的物理时钟是很难完全同步的,即使有NTP,精度也是有限的。所以在分布式系统中,是不能通过物理时钟决定事件序列的。

物理时钟在分布式系统中也不是毫无用处,至少它一定程度上可以判断在一台机器上的事件顺序,同时分布式系统中还是有必要让不同机器上的物理时钟在一定精度内同步时间的,只是不作为决定事件序列的方法。

【2】偏序(Partial Ordering)

事件序列有两种:偏序事件序列和全序事件序列。所谓的偏序指的是只能为系统中的部分事件定义先后顺序。这里的部分其实是有因果关系的事件。在论文Time, Clocks, and the Ordering of Events in a Distributed System中,偏序是由“happened before”引出的,我们先看一下"happened before"(表示为“->”)的定义:

Definition. The relation "->"on the set of events of a system is the smallest relation satisfying the following three conditions:

(1) If a and b are events in the same process, and a comes before b, then a->b.

(2) If a is the sending of a message by one process and b is the receipt of the same message by another process, then a->b.

(3) If a->b and b->c then a->c.

在分布式系统中,只有两个发生关联的事件(有因果关系),我们才会去关心两者的先来后到关系。对于并发事件,他们两个谁先发生,谁后发生,其实我们并不关心。偏序就是用来定义两个因果事件的发生次序,即‘happens before’。而对于并发事件(没有因果关系),并不能决定其先后,所以说这种‘happens before’的关系,是一种偏序关系。

If two entities do not exchange any messages, then they probably do not need to share a common clock; events occurring on those entities are termed as concurrent events.”

【3】逻辑时钟

论文原文中有这样一句:We begin with an abstract point of view in which a clock is just a way of assigning a number to an event, where the number is thought of as the time at which the event occurred. 这句话的意思是,可以把时间进行抽象,把时间值看成是事件发生顺序的一个序列号,这个值可以<20190515,20190516,20190517>,也可以是<1,2,3>。后面就有了逻辑时钟的概念。定义如下:
we define a clock Ci for each process Pi to be a function which assigns a number Ci(a) to any event a in that process.

Clock Condition. For any events a,b: if a->b then C(a) < C(b).
C1. If a and b are events in process Pi, and a comes before b, then Ci(a) < Ci(b).
C2. If a is the sending of a message by process Pi and b is the receipt of that message by process Pi, then Ci(a) < Ci(b).

具体的,根据上面的定义条件,我们做如下实现规则:

  • 每个事件对应一个Lamport时间戳,初始值为0
  • 如果事件在节点内发生,本地进程中的时间戳加1
  • 如果事件属于发送事件,本地进程中的时间戳加1并在消息中带上该时间戳
  • 如果事件属于接收事件,本地进程中的时间戳 = Max(本地时间戳,消息中的时间戳) + 1

根据上面的定义,我们知道a->bC(a)<C(b),但如果C(a)=C(b),那么a,b是什么顺序呢?它们肯定不是因果关系,所以它们之间的先后其实并不会影响结果,我们这里只需要给出一种确定的方式来定义它们之间的先后就能得到全序关系。

一种可行的方式是利用给进程编号,利用进程编号的大小来排序。假设a、b分别在节点P、Q上发生,Pi、Qj分别表示我们给P、Q的编号,如果 C(a)=C(b) 并且 Pi<Qj,同样定义为a发生在b之前,记作 a?b(全序关系)。假如我们上图的A、B、C分别编号Ai=1、Bj=2、Ck=3,因 C(B4)=C(C3) 并且 Bj<Ck,则 B4?C3

通过以上定义,我们可以对所有事件排序,获得事件的全序关系(total order)。上图例子,我们可以进行排序:C1?B1?B2?A1?B3?A2?C2?B4?C3?A3?B5?C4?C5?A4。观察上面的全序关系你可以发现,从时间轴来看B5是早于A3发生的,但是在全序关系里面我们根据上面的定义给出的却是A3早于B5,这是因为Lamport逻辑时钟只保证因果关系(偏序)的正确性,不保证绝对时序的正确性。

【4】尝试用逻辑时钟解决分布式锁的问题

单机多进程程序可由锁进行同步,那是因为这些进程都运行在操作系统上,有center为它们的请求排序,这个center知道所有需要进行同步的进程的所有信息。但是在分布式系统中,各个进程运行在各自的主机上,没有一个center的概念,那分布式系统中多进程该怎么进行同步呢?或者说分布式锁该怎么实现呢?论文中提出了解决这一问题的算法要满足下面三个条件:

(I) A process which has been granted the resource must release it before it can be granted to another process.

(II) Different requests for the resource must be granted in the order in which they are made.

(III) If every process which is granted the resource eventually releases it, then every request is eventually granted.
为了简化问题,我们做如下假设:

  • 任何两个进程PiPj它们之间接收到的消息的顺序与发送消息的顺序一致,并且每个消息一定能够被接收到。
  • 每个进程都维护一个不被其他进程所知的请求队列。并且请求队列初始化为包含一个T0:P0请求,P0用于该共享资源,T0是初始值小于任何时钟值

算法如下:

  1. To request the resource, process Pi sends the message Tm:Pi requests resource to every other process, and puts that message on its request queue, where Tm is the timestamp of the message.(请求资源,发送请求给其他进程,在自己的请求队列中添加该请求)
  2. When process Pj receives the message Tm:Pi requests resource, it places it on its request queue and sends a (timestamped) acknowledgment message to Pi.(收到其他进程的请求,放到请求队列中,回应发起请求的进程)
  3. To release the resource, process Pi removes any Tm:Pi requests resource message from its request queue and sends a (timestamped) Pi releases resource message to every other process.(释放资源,从请求队列中移除该资源请求,发送给其他进程,告诉它们我释放了该资源)
  4. When process Pj receives a Pi releases resource message, it removes any Tm:Pi requests resource message from its request queue.(收到其他进程释放资源的消息,从请求队列中移除该资源请求)
  5. Process Pi granted the resource when the following two conditions are satisfied:
    (i) There is a Tm:Pi requests resource message in its request queue which is ordered before any other request in its queue by the relation ? .
    (ii) Pi has received a message from every other process timestamped later than Tm.
    (判断自己是否可以获得该资源,有两个条件:其一,按全序排序后,Tm:Pi请求在请求队列的最前面;其二,自己Pi已经收到了所有其他进程的时戳大于Tm的消息)

下面我们举个例子说明上面的算法过程:
初始状态为P0拥有资源,请求队列中为0:0(T0:P0的简写),而后P1请求资源,将1:1添加到请求队列中,此时P0让占有资源,P1还无法获取资源,等到P0释放资源后,0:0从请求队列中移除(下图中没有画出),此时请求队列中1:1的请求在最前面,同时P1收到了其他两个进程的大于1的回应消息,满足了占有资源的条件,此时P1占有资源。

其实关键思想很简单,既然分布式系统中没有“center”的概念,那我请求共享资源时我就让其他所有进程都知道我要请求该资源,拥有资源的进程释放资源时也告诉所有进程,我要释放该资源,想请求该资源的你们可以按序(逻辑时钟的作用,这里再次说明一下,并不能保证在绝对物理时间上请求的排序)请求了。这样每个进程都知道其他进程的状态,就相当于有个“center”。

对于分布式锁问题,多个请求不一定是一定按照绝对物理时钟排序才可以,只要我们有这样一个算法,这个算法可以保证多个进程的请求按照这个算法总能得到同一个排序,就可以了,按照绝对物理时钟排序只是其中一个可行的算法。

到这里是否就万事大吉了呢,其实并没有,这个实现是很脆弱的,它要求所有进程都非常可靠,一旦一个进程挂了或出现网络分区的情况,是无法工作的,同时我们提出的网络要求也非常严格,要求发出的消息一定被接收到,这个在实用的系统中是很难做到的。所以这是一个理想状况下的算法实现,并不是一个可以工业级应用的算法实现。但它仍然是非常有意义的,给了我们关于分布式系统中解决一致性、共识算法等思想启迪。

参考文档:
大神论文:Time, Clocks, and the Ordering of Events in a Distributed System
Lamport timestamps
分布式系统:Lamport 逻辑时钟

关注微信公众号,每天进步一点点!

原文地址:https://www.cnblogs.com/s-lisheng/p/11307212.html

时间: 2024-10-06 17:18:36

分布式系统:时间、时钟和事件序列的相关文章

分布式系统的时钟和事件顺序

<Time, Clocks, and the Ordering of Events in a Distributed System>(分布式系统的时钟和事件顺序)是分布式领域非常重要的经典论文,由Leslie Lamport 在1978年发表. 我就这么简单理解:在分布式系统中,使用物理时钟对不同process进行时间同步与事件排序是非常困难的.Lamport提出逻辑时钟的概念.在同一process中,事件发生的顺序很容易定义与区分,不同process间,发送消息的事件在前,接收消息的事件在后

分布式系统理论基础 - 时间、时钟和事件顺序

十六号…… 四月十六号.一九六零年四月十六号下午三点之前的一分钟你和我在一起,因为你我会记住这一分钟.从现在开始我们就是一分钟的朋友,这是事实,你改变不了,因为已经过去了.我明天会再来. —— <阿飞正传> 现实生活中时间是很重要的概念,时间可以记录事情发生的时刻.比较事情发生的先后顺序.分布式系统的一些场景也需要记录和比较不同节点间事件发生的顺序,但不同于日常生活使用物理时钟记录时间,分布式系统使用逻辑时钟记录事件顺序关系,下面我们来看分布式系统中几种常见的逻辑时钟. 物理时钟 vs 逻辑时

分布式系统卫星时钟服务器(NTP服务器)架设与设计

分布式系统卫星时钟服务器(NTP服务器)架设与设计 分布式系统卫星时钟服务器(NTP服务器)架设与设计 本文由安徽京准科技提供支持和原资料——更多阐述可参考微♥ ahjzsz  分布式系统由Tanenbaum定义,“分布式系统是一组独立的计算机,在”分布式系统?—?原理和范例“中作为用户的单一,连贯的系统出现”. 区块链通过构建全球分布式系统,尝试实现分散的新数据存储和组织结构. 首先,定位到分布式系统的原因主要是可扩展性,位置和可用性.区块链也不例外.地理可扩展性,形成全球价值存储网络/信息保

在MFC中增加一个时间计时器消息事件

在MFC中增加一个时间计时器消息事件 利用this->SetTimer(1,1000,NULL);开启计时器 添加响应事件 void Csqllink1Dlg::OnTimer(UINT_PTR nIDEvent) { CTime tm; tm=CTime::GetCurrentTime(); CWnd* pWnd = (CWnd*)GetDlgItem(IDC_STATIC);switch(nIDEvent){ case 1: //MessageBox(_T("test"));

杂记b---jquery.siblings(),HTML页时间戳转化为正常的时间显示,ng-click事件的写法

jQuery siblings() 方法返回被选元素的所有同胞元素,并且可以使用可选参数来过滤对同胞元素的搜索. 实例演示:点击某个li标签后将其设置为rgb(248,198,173)橙色样式,而其所有同胞元素去除#FFFFFF(白色样式) <div id="each"> <span>标签:</span> <ul class="right-topfloat"> <li style="background

鼠标悬停(鼠标悬停一段时间后触发事件)一段时间后触发事件

<html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <script type="text/javascript"> var mytimer = null; function beginEvent(){ //window.setTimeout("alert('Hello, worl

Android异步框架RxJava 1.x系列(二) - 事件及事件序列转换原理

前言 在介绍 RxJava 1.x 线程调度器之前,首先引入一个重要的概念 - 事件序列转换.RxJava 提供了对事件序列进行转换的支持,这是它的核心功能之一. 正文 1. 事件序列转换定义 所谓转换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列,有点类似 Java 1.8 中的流处理. 2. 事件序列转换API 首先看一个 map() 的例子: Observable.just("images/logo.png") // 输入类型 String .map(

(DP)最大价值事件序列选取

题目: 有 T (小于10000)件事情,每件事件有一个开始时间(从1开始)一个结束时间(小于 10000),和一个正整数价值 . 求做这些事件所能得到的最大的价值 . 思考: 将事件由事件开始先后顺序排序,先开始的排在前面,后开始的排在后面.按这个顺序事件号记录在一个数组order中. 初始化数组 dp 为 0 , dp[w] 表示 选取了 结束时间为 w 的某事件后 所做事件的总价值. 初始化变量dpmax = 0 记录dp值的最大值. 设 end 为 第 i 件 事结束的时间. 做第 i

DICOM:剖析Orthanc中的Web Server,Mongoose之“连接请求触发的事件序列”(二)

背景: Orthanc是本专栏中介绍过的一款新型DICOM服务器,具有轻量级.支持REST的特性,可将任意运行Windows和Linux系统的计算机变成DICOM服务器,即miniPACS.Orthanc内嵌多种模块,数据库管理简单,且不依赖于第三方软件.因此通过剖析Orthanc源码可以学习到搭建DICOM系统中的各个环节,例如SQLite嵌入型数据库.GoogleLog日志库.DCMTK医学DICOM库,以及近期要介绍的开源Web Server,Mongoose. 题记: 近期计划参照官网剖