分布式互斥算法

概述

互斥算法主要是在并发的情况下确保同一时刻只有一个进程访问共享资源。在非分布式系统中,互斥可以通过锁(locks)和信号量(semaphores)等机制来实现。但是这些机制都不适用于分布式环境,因此我们需要一个算法来保证在分布式环境中多个进程对一个资源进行并发访问的时候,各个进程都能访问到资源,并且同一时刻有且只有一个进程能访问资源。资源是一种抽象概念,它可以是临界代码、文件、数据库中的字段、物理设备或某些网络服务。互斥算法的目标是让多个进程能对其进行互斥访问。

互斥算法有几个重要特性:

  • 安全性(safety):算法需要保证在同一时刻只能有一个进程访问资源
  • 活性(liveness): 算法不应让任何进程陷入无限等待而永远访问不到资源(饿死)
  • 公平性(fairness):算法应尽可能的保证每个算法有平等的机会访问资源

分布式互斥算法分为三类:

  1. 基于中心节点的算法:存在中心协调节点负责资源访问授权,所有进程访问临界资源前需要获得中心节点的授权
  2. 令牌环算法:每个资源关联唯一token,每个进程只有获取到相应的token才能访问资源,所有进程组成一个逻辑环,token在环上顺时针流转。
  3. 基于竞争的算法:进程间通过通信协调达成一致决定在某一时刻哪个进程可以访问临界资源

基于中心节点的算法

基于中心节点的算法中,存在一个中心协调节点进程,该进程负责资源访问授权,当有进程需要访问资源时候,首先向中心节点提出请求,中心节点首先会将请求放入FIFO队列中,然后检查资源当前有没有被占用,如果资源没有被占用中心节点会向请求进程发送授权访问响应,否则不予响应。当进程使用资源完毕,会向中心节点发送释放请求,中心节点收到释放请求后,会从FIFO队列中移除该进程对应的请求并向FIFO队列中下一个请求进程发送授权响应(如果存在)。

image.png

基于中心节点的算法能保证公平,并且容易实现,但是其最大的问题就是单点故障。

令牌环算法

令牌环算法在竞争的进程组间创建一个逻辑环,如下图所示,每个进程只与它的邻接点通信。每个资源关联唯一token,每个进程只有获取到相应的token才能访问资源,并且token在进程逻辑环上按顺时针(或逆时针)传递。当一个进程收到token,就可以访问资源并在访问完后将token按照约定的顺序传递到下一个进程,如果没有访问需求,直接传递token到下个进程。

image.png

令牌环算法能有效保证公平性和活性,但是需要token不断的在环上传递,如果中途token丢失或进程死亡都会影响算法的执行。

基于竞争的算法

如前所述,基于竞争的算法是依靠所有进程通过相互通信协调达成一致决定在某一时刻哪个进程可以访问临界资源。

Lamport 互斥算法

Lamport互斥算法基于消息可靠传输和lamport逻辑时钟来实现的。想访问某一资源的进程,会向进程组中的所有进程发送请求,请求格式为(资源唯一标识,请求进程唯一标识,请求进程lamport时间戳)。每一个收到请求的进程会以时间戳来应答,并将请求放入按照lamport时间戳排序的本地队列(发送进程同样这样处理)。 所有进程会拥有一样的请求队列,如果进程发现自己的请求位于对头头部(时间戳最小),则可以访问资源。当进程访问完后,进程向进程组中的所有进程发送释放请求,收到释放请求后,进程会将相关请求移除本地队列(发送进程同样处理)。

image.png

在Lamport互斥算法中,通过基于lamport时间戳的全序关系来确保在多个进程请求访问同一共享资源时,以公平、确定的方式解决冲突,并且能防止出现死锁问题。 Lamport互斥算法不具有容错性,任何一个进程的失败都会导致整个算法停止运行,并且比较大的通信开销,但是它表明了完全分布式算法是可行的。

Ricart&Agrawala算法

Ricart&Agrawala算法是对lamport算法的一种优化。与lamport算法一样,进程如果要访问临界资源,需要向进程组中的所有进程发送请求,请求格式与lamport算法相同,进程在收到所有进程的响应后才能访问临界资源。对于收到请求的进程,如果进程正在使用临界资源则会将回复响应请求推迟到自己释放临界资源后,否则立即响应。

如果进程在发送请求的时候正好收到其它进程的请求时会进行以下处理:如果进程A从进程B收到的请求比它发送的请求早(时间戳较小),那么进程A将向进程B发送回复消息,让进程B优先访问该资源。否则,如果进程A的时间戳较早,它将把来自B的请求排入队列,并继续等待所有回复的到来,并且在使用完资源后才会向进程B发送回复。

相较于lamport算法,RA算法没有release请求,有相对少的通信开销,但是仍然存在节点失效导致的问题。