[分布式系统学习]阅读笔记 Distributed systems for fun and profit 之三 时间和顺序

这是阅读 http://book.mixu.net/distsys/time.html 的笔记,是该系列的第三章。

为什么时间和顺序很重要呢?为什么我们关系事件A发生在事件B之前?

因为分布式系统要解决的问题是把单机上的问题通过多机来解决。然而传统单机的程序总是假设确定的顺序。对于分布式程序来说,正确性最简单的定义就是,跑起来像一台单机上运行的程序。

全序和偏序

具体的定义大家可以去翻离散书。简单地说,全序就是在集合里任何两个元素都可以比较,分出大小。偏序中,某些元素是没办法比较大小的。

在单节点系统中,全序是必然的。因为单机上指令顺序执行。程序运行可预测。这个性质在分布式系统上不是不能实现,但是要付出代价。通信非常昂贵,时间同步困难且脆弱。

什么是时间

时间是顺序的来源。有了时间,我们才可以定义谁先谁后。分秒时只不过为了让人理解恰好出现的记号。

假设时间以同样的速率推进,(这是一个非常强的假设),时间和时间戳有下面解释:

  • 顺序(Order)例如,通过时间戳对事件进行排序
  • 持续时间(Duration)计算某事件持续时间,用于算法判断条件(例如监控心跳,判断是否出现网络分割)
  • 解读(Interpretaion)时间作为日期,本身包含一定意义,例如判断下周日是否下雨。

分布式系统中每个节点都有独立的本地时间和时间戳,于是事件的发生有本地的顺序。但是该顺序和其他节点完全独立。给决定分布式系统中的全局顺序造成一定困难。

不可假设时间匀速流逝

分布式系统中应该尽量避免假设时间在不同节点上都以同样的速率流逝,否则系统实现会比较脆弱。

那是否可以做到不同节点事件,一致而顺序发生呢?有三个设计(假设)选择。

  • 全局时钟(Global Clock):是
  • 本地时钟(Local Clock):不全是
  • 没有时钟存在(No Clock):没有

同步系统模型有全局时钟,部分同步模型有本地时钟,而异步系统模型没有时钟。

全局时钟假设

全局时钟是全序的源泉。

完美的时钟,走时同步,存在于所有节点。这是分布式系统的理想假设。实际上,时钟同步只能保证有限的精度。用户可能随机地改变本机时间,新节点加入,都有可能破坏全局时钟的假设。

当然,现实系统也有做出这个假设的。FB的Cassandra,就是使用时间戳来解决write的冲突的。时间戳较大的write会赢。那么,如果时间不同步,那么旧的write有可能覆盖新的。

本地时钟假设

假设,可能是目前比较合理的假设,本地有时钟,但是不存在一个全局时钟。两个节点的本地时间戳是不能比较的。

这和真实世界比较接近。事件在本地是可以排序的,但是在多节点分布式系统里不行。不过可以在单机上计算timeout。

没有时钟假设

完全不使用”时钟”这个概念,取而代之,“逻辑时间”。因为时间戳么,只不过是当前世界状态的一个快照,那我们用一个计数器(Counter),并和节点之间交流就可以做到了。

这样,我们可以在不同的节点之间决定事件顺序。不过有个坏处,因为缺乏时钟,没办法决定timeout。

“没有时钟”的假设的一个实现是“Vector clocks”。后面会详细讲到。Cassandra的cousin Riak 和 Vodemort(LinkedIn)是它的应用。这些系统避免了全局or本地时钟漂移带来的不确定性。

那么事件的顺序的准确性,完全是由通信的延时来决定了。

向量时钟 (Vector clocks)

Lamport时钟向量时钟通过计数器和通信来决定分布式系统中事件发生顺序的。计数器可以在不同节点之前进行比较。

Lamport时钟

每个进程都维护一个计时器。

  • 当进程做了任意一件事,增加计时器计数。
  • 进程发送的消息中包含计时器计数。
  • 当收到消息以后,计数器设置如下:max(local_counter, received_counter) + 1

Lamport时钟定义了一个偏序,如果 timestamp(a) < timestamp(b):

  • a 可能发生在b之前
  • a和b压根没法比较

第二种情况发生在a和b所在的Partition没有发送通信。

Vector clocks

向量时钟是Lamport时钟的一种扩展。它维护大小为N的数列[t1, t2, ....],N为节点数。每个节点都更新自己的时钟。

  • 每当进程做了事情,更新该node的时钟。
  • 进程发送的消息,包含上面提到的数组。
  • 当收到消息以后,更新本地的数组里面的每个元素max(local, received);为当前节点的counter加1。

如下图:

向量时钟潜在的问题是每个节点都有个时钟计数,对于大型的系统来说,向量本身可能变得很大。

失灵检测

对于一个节点上的程序,它怎么知道远程某个节点失效了呢?在缺乏有效准确的全局信息下,我们可以通过一个合理的timeout值来确定。

但是合理的timeout值该怎么确定呢?

失灵检测器可以通过使用心跳消息来实现timeout。节点之间交换心跳消息。如果消息在timeout之前没有收到响应,就可以认为出现失效。

这种检测要么太冲动(把正常的节点算成失效),要么太保守,很长时间才能检测出错误。

论文 http://www.google.com/search?q=Unreliable%20Failure%20Detectors%20for%20Reliable%20Distributed%20Systems 讨论了失灵检测在解决一致性问题中的两大属性: 完整性和精准性。

时间,顺序和性能

我们知道在分布式系统中应假设偏序而不是全序。而要承诺全序也是可能的,但是代价非常大。通常的做法是告诉某一个master节点顺序,让它去执行。(GFS的control path做法)。这可能造成性能瓶颈。

时间,顺序和同步真的必要么?看情况。有时候可能你只不过需要最后的结果而不关系中间事件发生的顺序。(Map Reduce)

时间: 2024-10-19 05:12:26

[分布式系统学习]阅读笔记 Distributed systems for fun and profit 之三 时间和顺序的相关文章

[分布式系统学习]阅读笔记 Distributed systems for fun and profit 之四 Replication 拷贝

阅读http://book.mixu.net/distsys/replication.html的笔记,是本系列的第四章 拷贝其实是一组通信问题,为一些子问题,例如选举,失灵检测,一致性和原子广播提供了上下文. 同步拷贝 可以看到三个不同阶段,首先client发送请求.然后同步拷贝,同步意味着这时候client还在等待着请求返回.最后,服务器返回. 这就是N-of-N write,只有等所有N个节点成功写,才返回写成功给client.系统不容忍任何服务器下线.从性能上说,最慢的服务器决定了写的速度

[分布式系统学习]阅读笔记 Distributed systems for fun and profit 抽象 之二

本文是阅读 http://book.mixu.net/distsys/abstractions.html 的笔记. 第二章的题目是"Up and down the level of abstraction".这一章里面,作者主要介绍了分布式系统里面的一个重要概念:CAP理论. 什么是CAP理论呢?就是说在任何情况下,分布式系统只能满足下面三项中的两个: 一致性(Consistency),这里指的强一致性. 可用性(Availability). 对网络分割容错(Partition tol

深度学习论文阅读笔记--Deep Learning Face Representation from Predicting 10,000 Classes

来自:CVPR 2014   作者:Yi Sun ,Xiaogang Wang,Xiaoao Tang 题目:Deep Learning Face Representation from Predicting 10,000 Classes 主要内容:通过深度学习来进行图像高级特征表示(DeepID),进而进行人脸的分类. 优点:在人脸验证上面做,可以很好的扩展到其他的应用,并且夸数据库有效性:在数据库中的类别越多时,其泛化能力越强,特征比较少,不像其他特征好几K甚至上M,好的泛化能力+不过拟合于

面对软件错误构建可靠的分布式系统(阅读笔记)

阅读笔记 joe Armstrong 段先德 译 核心问题:如何在存在软件错误的情况下编写具有合理行为的软件 ,如何避免像死锁.死循环等问题 ERLANG的世界观,一切皆进程.将任务分离成层次化的一系列任务,强隔离的进程负责来执行每个具体化的任务,进程之间不共享状态(实际上ETS跨越了这个准则). 只能通过消息传递来通信,必须注意进程消息的堵塞问题 工作者和监督者构成一个完整的系统,监督者的作用就是监控整个系统的运行状况.并对突发情况进行可靠的处理. behaviour库的设计思想就是将程序的并

可扩展的Web系统和分布式系统(Scalable Web Architecture and Distributed Systems)

Open source software has become a fundamental building block for some of the biggest websites. And as those websites have grown, best practices and guiding principles around their architectures have emerged. This chapter seeks to cover some of the ke

Google File System 论文阅读笔记

核心目标:Google File System是一个面向密集应用的,可伸缩的大规模分布式文件系统.GFS运行在廉价的设备上,提供给了灾难冗余的能力,为大量客户机提供了高性能的服务. 1.一系列前提 GFS的系统构建针对其自身使用的特点在传统的分布式系统的基础上又进行了一些创新,基于的前提假设主要包括以下方面: 1.由于系统由廉价的商用机构成,组件失效被认为是一种常态,系统必须可以持续监控自身的状态. 2.系统存储以大文件为主,小文件也支持,但是没有进行特别的优化处理. 3.系统的工作负载主要包含

《STL源码剖析》---stl_alloc.h阅读笔记

这一节是讲空间的配置与释放,但不涉及对象的构造和析构,只是讲解对象构造前空前的申请以及对象析构后空间怎么释放. SGI版本的STL对空间的的申请和释放做了如下考虑: 1.向堆申请空间 2.考虑了多线程.但是这节目的只是讲解空间配置与释放,因此忽略了多线程,集中学习空间的申请和释放. 3.内存不足时的应变措施 4.考虑到了内存碎片的问题.多次申请释放小块内存可能会造成内存碎片. 在C++中,内存的申请和释放是通过operator new函数和operator delete函数,这两个函数相当于C语

《STL源码剖析》---stl_algobase.h阅读笔记

STL标准中没有区分基本算法或复杂算法,单SGI把常用的一些算法定义在<stl_algobase.h>只中,其他算法定义在<stl_algo.h>中. stl_algobase.h中的算法,比较值得学习的是copy(),它"无所不用其极"的改善效率.copy的目的是复制一段元素到指定区间,复制操作最容易想到赋值操作符=,但是有的赋值操作符=是trivial的,可以直接拷贝.关于赋值操作符=是不是trivial的,可以参考"Memberwise copy

《STL源码剖析》---stl_vector.h阅读笔记

在STL中,最常用的就是容器,最常用的容器就是vector了.vector类似内置数组.但是数组是静态的,一旦配置就不能再变大小,而容器的大小事容器本身自己调整的.在实现容器的代码中可以看到,容器可以动态增大,但是不能动态减小. 容器有已用空间和可用空间,已用空间就是容器已经使用了的空间,可用空间就是指vector的大小capacity. 容器是占用一段连续线性空间,所以容器的迭代器就等价于原生态的指针(这是造成我一直以为迭代器就是指针的原因),vector迭代器类型是RandomAccessI