1、第六章 同步,时钟同步逻辑时钟全局状态选举算法互斥分布式事务 分布式系统中的死锁,时钟同步,分布式系统中,不存在公共时钟或精确的全局时间当每台机器都有自己的时钟时,一个发生较晚的时间可能被标上较早的时间例子:Unix中的make程序,物理时钟,平均太阳日的计算,太阳日:连续的两次日中天的时间太阳秒:solar-day/86400平均太阳秒:格林威治时间,现实时钟,铯原子钟:9192631770次跃迁=1秒TAI秒:国际原子时间UTC秒:统一协调时间(在TAI秒中加入闰秒)时间服务:WWV电台、GEOS卫星,时钟同步算法,当时钟以不同的速率滴答时,时钟时间与UTC之间的关系:当UTC时间为t时,
2、机器上的时间为Cp(t),理想情况是Cp(t)=t,即dC/dt=1.1-p=dC/dt=1+p为保证每两个时钟间的差值不超过a,则时钟必须至少每a/2p秒重新同步一次,Cristian算法,适合只有一台时间服务器的情况,可接收WWV的UTC时间,Cristian算法,不能简单接受CUTC时间不能倒退,须逐步修正假设:每秒产生100次中断,每次中断将时间加10毫秒若调慢时钟,中断服务程序每次只加9毫秒;若加快时钟,则加11毫秒。存在延迟,Berkeley 算法,time daemon 向所有其他机器发送自己的时间,并询问其时钟值其他机器应答time daemon计算出平均值,通知其他机器如何调
3、整时钟,平均值算法,非集中式算法时间间隔 T0+iR, T0+(i+1)R 在每次时间间隔开始,每台机器广播自己的当前时间之后启动本地计时器,搜集时间间隔S内到达的所有时间广播,计算时间值平均值去掉若干个最低值和最高值?给每个消息加上传输时间的估计值,逻辑时钟Lamport Timestamps,时间戳( Time-Stamping)的算法:网络上的每个系统(站点)维护一个计数器,起时钟的作用每个站点有一个数字型标识,消息的格式为(m,Ti,i),m为消息内容, Ti为时间戳, i为站点标识当系统发送消息时,将时钟加一当系统j接收消息时,将它的时钟设为当前值和到达的时间戳这两者的最大者加一在每
4、个站点,时间的排序遵循以下规则对来自站点i的消息x和站点j的消息y,如果TiTj或Ti=Tj,且i,通过正确地控制并发事务(同时对共享数据进行操作的事务)的执行基本上可以解决一致性和独立性问题事务管理器:保证事务的原子性调度管理器:正确地控制并发,决定哪个事务在何时被允许将读、写操作传给数据管理器数据管理器:数据的读写,并发控制 (2),分布式事务管理器组织,串行化,a) c) 三个事务 T1, T2, 和 T3d) 可能的调度,(d),串行化:多个事务同时执行并保持独立,最终的执行结果与事务以某种特定顺序一个接一个串行执行得到的结果相同。,并发控制算法,并发控制的思想:正确调度相冲突的操作(
5、读写和写写)按读写操作同步的方式分为共享数据上的互斥机制,如锁定显示地使用时间戳排序,并发控制算法-锁机制,T1读D的时候,T2不可以写D,但可以读D;T1写D的时候,T2既不可以写D,又不可以读D。一个事务可以对D实施读锁和写锁:不同的事务可以因读而同时封锁同一个D,所以,读锁又叫共享锁(Sharing Lock);不同的事务不能因写而同时封锁同一个D,所以,写锁又叫排它锁(Exclusive Lock);根据上述分析,我们可得如下锁协议:1、T ReadLock(D),T 也可以ReadLock(D),如果T WriteLock(D),则T 被挂起,直到 T UNLock(D);2、T W
6、riteLock(D),如果T ReadLock(D)或者WriteLock(D),则T 被挂起,直到 T UNLock(D);3、T使用完D之后,UNLock(D)。问题:不能保证可串行化。,两阶段锁定 (1),两阶段锁定:为了保证并发调度的可串行化,要求T在执行过程中,有一个时间点t,在t之前,T不执行UNLock操作,并且在t之后,T不再执行ReadLock(D)和WriteLock(D)操作。进程在增长阶段先请求它需要的所有锁,然后在收缩阶段释放它们。可以证明(Eswaran等,1976)如果所有的事务都使用两阶段加锁法,那么通过交错事务进行的所有调度都是串行的。这也是两阶段加锁法广泛
7、使用的原因。,两阶段锁定 (2),严格的两阶段锁定:UNLock操作仅在T提交的时候或者被中止的时候由服务器一并执行。严格两阶段锁定协议除了要求封锁是两阶段之外,还要求事务持有的所有排它锁必须在事务提交之后方可释放。这个要求保证未提交事务所写的任何数据,在该事务提交之前均以排它锁封锁,防止其他事务读取这些数据。 优点:事务总是读提交事务写入的值,不会看到中间状态数据锁的获得和释放由系统来处理而无需事务关心,死 锁,加锁,即使两阶段加锁,也可能会导致死锁。若两个进程都试图以相反的顺序请求同一对锁,那么就会发生死锁。这里可以采用诸如以某种规范顺序请求所有的锁之类的一般方法来防止保持-等待循环的出现
8、。通过对一张精确描述哪个进程可以拥有哪个锁,它还想请求哪个锁的图进行死锁扫描,以检查是否有环路出现,也可以防止死锁。如果事先知道一个锁的拥有时间不会超过T秒时,也可以采用一个超时方案:如果某个拥有者连续拥有同一个锁超过了T秒,那么一定是出现了死锁。,并发控制算法-悲观的时间戳排序Pessimistic Timestamp Ordering,思想:每个事务指定一个时间戳,文件都有相关的读时间戳和写时间戳如果事务的进程试图访问文件时,文件的读时间戳和写时间戳都比事务的时间戳更早(小),这种关系是正常的反之,说明当前事务提交太晚,应该终止。,需要中止,比 较,同加锁法相比,时间戳有着不同的特性当一个
9、事务碰到了更大(晚)的时间戳时,就要中止,加锁法在相同的情况下要么等待,要么立即执行。另一方面,时间戳方法不会出现死锁,这是极大的改进。,乐观的并发控制optimistic concurrency,处理同时运行多个事务的第二种方法是乐观并发控制法(Kung and Robinson,1981)。这种方法的思想惊人的简单:尽管放心去做你想做的,不用在意其他人正在做什么。如果有问题出现,那么以后再考虑吧。在实际情况中,冲突相对来说非常少,所以这个策略大部分时间都可以正常工作。,乐观的并发控制冲突的处理,尽管冲突会非常少,但存在的可能性还是有的,因此还需要一些处理冲突的方法。乐观并发控制算法所做的只
10、是记录下有哪些文件曾经被读写过。在提交时刻,检测其他的事务以判断在本事务开始后它的文件是否被其他事务修改过。如果被修改过,那么本事务将被中止。如果没有修改过,那么本事务就可以提交了。,乐观并发控制算法最适合于基于私有工作空间的情况。每个事务都独立地修改各自的文件,不会涉及其他的事务。在结束的时候,新的文件要么被提交要么被释放。乐观并发控制算法的最大优点在于避免了死锁,而且允许最大的并行度(进程不需要去等待一个锁)它的缺点是:有时可能会失效,这时所有事务都必须退回重新运行在重负载的情况下,算法失效的可能性将会直线上升,这使得乐观并发控制算法成了一个很糟糕的选择。,分布式系统中的死锁,分布式系统中
11、的死锁类似单处理机系统中的死锁,只是情况更糟。它们更难于避免、预防或者检测,即使在检测到以后也很难处理,因为所有的相关信息都分散在多台机器上。在某些系统中,如分布式数据库系统中,死锁的问题可能会相当严重,因此理解分布式系统中的死锁与一般的死锁有何不同,它们应该如何处理就显得非常重要了。,策略的分类,讨论死锁问题的策略有很多种。四个最著名的策略:鸵鸟算法(忽略问题)预防(静态的,使死锁在机制上是不可能发生的)避免(通过仔细的分配资源以避免死锁,需要(事先)知道每个进程最终到底需要多少资源。而这样的信息即使有,也非常的少。 )检测与恢复(允许死锁发生,在检测到后想办法恢复),分布式死锁预防,死锁预
12、防是由细致的系统设计构成的,因此死锁从机制上来说是不可能的。一些已有的办法在实践中都不太方便,例如在某一时刻只允许进程占有一个资源要求进程在初始阶段请求所有的资源当进程请求新资源时必须释放所有资源。或者要求进程必须预定资源,并以严格增序请求资源。即一个进程不可能既占有了一个高序资源又去请求一个低序资源,这就使得环路不可能出现了。,两种基于时间戳的算法,在拥有全局时间和原子事务的分布式系统中,另外两种实用的算法也是可能的。这两种算法都是基于在一个事务开始时给它分配一个全局时间戳的思想。同许多基于时间戳的算法一样,在这两种算法中保证不会有两个事务分配了完全一致的时间戳。Lamport的算法有效的保
13、证了时间戳是唯一的。,基本思想,这两种算法的基本思想是:当一个进程因等待一个正被其他进程占用的资源而要阻塞时,进行检查以判断哪个进程的时间戳更大(即更晚)。只有当等待进程的时间戳小于(早于)被等待进程的时间戳,才允许等待发生(只允许老进程等待),否则中止沿着等待进程链,时间戳递增,不可能发生环路或只有当等待进程拥有大于(晚于)被等待进程的时间戳时,才允许等待发生(只允许新进程等待),否则中止沿着等待进程链,时间戳递减,老进程?新进程?,尽管两种方法都能预防死锁,但是给予老的进程以优先权更明智些。?它们已经运行了较长时间,系统对它们的投入会更大一些,它们占有的资源也就更多一些。另外,这种选择消除
14、了饿死现象一个被中止的新进程最终成为系统中最老的进程,等-死算法(wait-die),由于使用了时间戳,当请求被占用的资源时,只可能有两种情况:老进程请求被新进程占用的资源,或者,新进程请求被老进程占用的资源一种情况应该允许进程等待,另一种情况应该中止进程。也即等-死算法,等-死算法(wait-die)举例,假设标记a为中止,b为等待。那么就应该中止掉老进程,但这样的效率较低(老进程只会变得更老)。所以应该以相反的方式进行标记,如下图在这种情况下,箭头总是指向事务编号增长的方向,使得环路不可能出现。,资源不可剥夺?,一旦我们假设了事务的存在,我们就可以做一些在以前是被禁止的事情:从运行进程中夺
15、走资源。当冲突发生的时候,我们不需要中止提出请求的进程,我们可以中止资源拥有者。如果没有事务,中止一个进程可能会有严重的后果,例如进程可能已经修改了文件。有了事务后,当事务死亡时这些效果会消失。,伤-等算法(wound-wait),伤-等算法允许抢占:假设只允许老进程抢占新进程,图a被标记为抢先,图b为等待。这种算法称为伤-等算法(wound-wait),因为一个事务可能会受到伤害(实际是被中止)。,伤-等算法举例,若一个老进程希望得到一个被新进程占用的资源,那么老进程将会抢占,于是新事务被中止,如a所示。随后新事务可能会立即重新开始,并试着请求资源,如b所示,然后被迫等待。,中止,再生,等-
16、死算法与伤-等算法比较,等-死算法中,若一个老事务想得到一个正被新事务占用的资源,那么它会很礼貌的等待。反之,若一个新事务想得到一个被老事务占用的资源,它将被中止。尽管它还会重新开始,但很可能又会立即被中止。在老事务释放资源之前,这个循环可能要重复多次。伤-等算法没有这么糟糕的特性。,分布式死锁检测,在分布式系统中找出一般的死锁预防和避免的解决方法是相当困难的,因此许多研究人员都只是尝试为更简单的死锁检测问题找出一种解决方法,而不是想办法去禁止死锁的发生。,在一些分布式系统中原子事务的提出使得在概念上有了极大的不同。在普通的操作系统中检测到死锁后,解决方法是中止掉一个或几个进程,但这必然会使一
17、些用户感到不满。在基于原子事务的系统中检测到死锁后,解决方法是中止掉一个或几个事务。但事务允许出现中止。,当一个事务因为产生死锁而被中止的时候,首先让系统恢复到事务开始前的状态,以后事务可以从这一点重新开始。若运气好,事务在第二次执行时就应该能成功。使用事务与不使用事务的差别在于使用事务时中止一个进程的后果要比不使用事务时的后果小的多得多。,集中式的死锁检测,作为第一个尝试,我们使用集中式的死锁检测算法来尽量模仿非分布式的算法。集中式的死锁检测算法每台机器都有一幅资源图以描述自己所拥有的进程和资源有一台中心机器拥有整个系统(所有资源图的集合)的资源图。当协调者检测到了环路时它就中止一个进程以解
18、决死锁。,全局资源图信息的维护,在分布式系统中需要精确维护全局资源图。每台机器的资源图中只包含它自己的进程和资源。需要适当的方法维护全局资源图信息。方法1:每当资源图中加入或删除一条弧时,相应的消息就发送给协调者以提供更新。方法2:每个进程周期性的把从上次更新后新添加的和删除的弧的列表发送给协调者。这种方法比第一种方法发送的消息要少。方法3:协调者在需要的时候主动去请求信息。,反 例,不幸的是上述方法的效果都不太好。例如有这样一种系统A和B运行在机器0上,C运行在机器1上。共有三种资源S,R和T。如图,一开始A拥有S并想请求R,但B正在使用R;C拥有T并想请求S。,反例(contd),协调者看
19、到的情况如图c所示。这种配置是安全的。一旦B结束运行,A就可以得到R然后结束,并释放C所等待的S。,反例(contd),过一会儿,B释放R并请求T,这是一个完全合法的安全操作。机器0向协调者发送一条消息声明它释放R机器1向协调者发送了一条消息声明进程B正在等待它的资源T。不幸的是,机器1的消息首先到达,这导致协调者生成了一幅如图d所示的资源图。,根据上图中的信息,协调者将错误的得出死锁存在的结论,并中止某个进程。这种情况称为假死锁。由于信息的不完整和延迟,使得分布式系统中的许多死锁算法产生了类似的假死锁问题。,假死锁问题,解决假死锁问题,一种可能的解决方法是使用Lamport算法以提供全局时间
20、。既然从机器1到协调者的消息是由机器0的请求发出的,那么从机器1到协调者的消息的时间戳就应该晚于从机器0到协调者的消息的时间戳。当协调者收到了从机器1发来的有导致死锁嫌疑的消息后,给每台机器发送一条消息“我刚刚收到一条会导致死锁的消息,带有时间戳T,若有任何小于T的消息要发给我,请立即发送。”,解决假死锁问题(contd),当每台机器或肯定或否定的响应之后,协调者就会看到从R到B已经消失了,因此系统仍然是安全的。尽管这种方法消除了假死锁,但它需要全局时间,而且开销很大。其他的一些消除假死锁的方法也很困难。,分布式的死锁检测,Chandy-Misra-Haas算法(Chandy等,1983)允许
21、进程一次请求多个资源(如锁)而不是一次一个。通过允许多个请求同时进行使得事务的增长阶段加速。这使得一个进程可以同时等待两个或多个进程。,资源图,下图是一种改进的资源图,图中只给出进程。每条弧穿过一个资源,为简单起见从图中删除了资源可以看到机器1上的进程3正在等待两个资源,一个由进程4占有,一个由进程5占有。一些进程正在等待本地资源,例如进程1。一些进程,如进程2在等待其他机器上的资源。,Chandy-Misra-Haas算法,当某个进程等待资源时,例如P0等待P1,将调用Chandy-Misra-Haas算法。生成一个探测消息并发送给占用资源的进程。消息由三个数字构成:阻塞的进程,发送消息的进
22、程,接受消息的进程。由P0到P1的初始消息包含三元组(0,0,1)。,Chandy-Misra-Haas算法(contd),消息到达后,接受者检查以确认它自己是否也在等待其他进程。若是,就更新消息,字段1保持不变,字段2改成当前进程号,字段3改为等待的进程号。然后消息接着被发送到等待的进程。若存在多个等待进程,就要发送多个不同的消息。,(0,0,1),(0,1,2),Chandy-Misra-Haas算法(contd),不论资源在本地还是在远程,该算法一直继续下去。图中(0,2,3),(0,4,6),(0,5,7)和(0,8,0)都是远程消息。若消息转了一圈后又回到最初的发送者,即字段1所列的
23、进程,就说明存在一个有死锁的环路系统。,打破死锁的方法(1),可以有不同的方法打破死锁:一种方法是使最初发送探测消息的进程自杀。如果有多个进程同时调用了此算法,那就会出现问题。例如在上例中假设进程06同时阻塞,而且都初始化了探测消息。那么每个进程最终都会发现死锁,并且因此而自杀,然而这是不必要的。中止掉一个进程就足够了。,打破死锁的方法(2),另一种算法是将每个进程的标识符添加到探测消息的末尾,这样当它返回到最初的发送者时完整的环路就可以列出来了。于是发送者就能看出哪个进程编号最大,可以将它中止或者发送一个消息给它请求其自杀。无论如何,如果多个进程同时发现了同一个环路,它们就一定会选择同一个牺牲者。,小 结,时钟同步逻辑时钟全局状态选举算法互斥分布式事务分布式系统中的死锁,习 题,分布式互斥算法中,建议所有的请求都被应答(同意或否定),这样可以检测出崩溃的进程,但是否还有其他问题?许多分布式算法需要协调者,与集中式协调者相比,分布性体现在哪里?,