分布式系统概念和设计
协调和协定
分布式系统中的进程如何协调它们的动作和对共享值达成协议?
算法在分布式系统中的基本目的是:供一组进程来协调它们的动作或对一个或多个值达成协议
避免固定的主-从关系的主要原因是,经常需要系统即使在系统故障的情况下依然能够工作,避免单个节点的故障导致主控制器故障
- 在异步分布式系统中不做时序上的假设
- 在同步分布式系统中,我们假设消息传送的最大延迟,进程的每步运行时间以及时钟漂移都有约束。这些同步假设允许我们使用超时机制来检测进程是否崩溃。
另一个目的是考虑故障以及在设计算法时候如何处理故障的算法。
故障假设和故障检测器
一个可靠的通道最终将消息传递到接受者的输入缓冲区。在同步系统中,假设在需要的地方有硬件冗余,这使得尽管底层故障,可靠通道不仅能最终传递每个消息,而且能在指定的时间限制内完成
在任何特定的时间间隔内,一些进程之间的通信可能成功,而另一些进程之间的通信则被延迟。
分布式互斥
分布式进程经常需要协调它们的动作。
如果一组进程共享一组资源,那么访问资源时,常需要互斥来防止干扰和保证一致性。
操作系统领域中的临界区问题,共享资源进行资源互斥机制访问资源,避免资源陷入混乱的状态。
在分布式系统中,共享变量或者单个本地内核提供的设施不能用来解决这个问题。
分布式互斥的解决方案:一个基于消息传送的解决方案。
某些场景,管理共享资源的服务器也提供互斥机制。
考虑多个用户更新一个文本文件。保证他们更新一致的一个简单方法是,通过要求编辑器在更新之前锁住文件,一次允许一个用户访问文件。
NFS文件是无状态设计,不支持加锁
UNIX系统提供由守护进程lockd实现的一个单独的文件锁服务,用于处理客户的加锁请求
UNIX中lockd
lockd是Unix或类Unix系统中的守护进程,用于协调和管理NFS文件锁。它的设计机制基于在分布式系统中实现共享资源的需要。
当一个进程请求获取一个文件锁时,lockd会检查该锁是否已经被其他进程持有。如果锁已经被持有,则lockd会将该请求放入一个等待队列中,并将其挂起直到锁可用。
一旦锁变为可用状态,lockd会通知等待队列中的下一个进程来获取锁。获取到锁的进程可以在其执行操作时保证对文件的独占访问权限。
通过使用lockd,多个进程可以安全地并发地访问同一文件,而不会出现冲突或数据损坏的问题。这使得NFS应用程序可以在分布式系统中更加可靠地运行。
HDSF互斥方式
在分布式系统中,文件的写入互斥可以通过锁机制来实现。常见的锁包括读写锁和互斥锁等。读写锁允许多个读操作同时进行,但只允许一个写操作进行;而互斥锁则只允许一个线程访问共享资源。
HDFS(Hadoop分布式文件系统)中也采用了类似的锁机制来保证写入互斥。当一个客户端想要写入一个文件时,它会向NameNode发送请求并获得一个排它锁。此时,其他客户端将不能进行写操作,直到该客户端释放锁为止。当客户端完成写操作后,它会通知NameNode,并释放锁,使其他客户端继续访问文件。
需要注意的是,由于HDFS设计的目标是高吞吐量、高可靠性和可扩展性,因此它采用了一些优化策略,如数据块的复制、数据本地性等,这也影响了其写入互斥的实现方式。
互斥算法
应用层协议:
- enter() 进入临界区——如必要则阻塞
- resourceAccess() 在临界区访问共享数据
- exit() 离开临界区——其他进程现在可以进入
互斥的基本要求:
- ME1(安全性)
- 在临界区(CS)一次最多有一个进程可以执行
- ME2(活性)
- 进入和离开临界区的请求最终执行成功
- 无死锁也无饥饿。死锁涉及两个或多个进程,由于互相依赖而试图进入或离开临界区时被无期限的锁住
- 即使一个差的算法也可能引发饥饿问题,进程的进入请求被无限的推迟
- 没有饥饿问题是一个公平性条件。
- 另一个公平性问题是进程进入临界区的顺序。
- ME3(——>顺序)
- 如果一个进入CS的请求发生在先,那么进入CS仍按此顺序
- 如果一种解决方案用发生在先顺序来赋予临界区的进入,并且如果所有请求都按发生在先建立联系,那么在其他进程等待时,一个进程就不可能进入临界区多于一次。
- 这种顺序也允许进程协调它们对临界区的访问。
- 一个多线程的进程可以在一个线程等待被准入临界区。
- ME3指定第一个进程在第二个进程之前被准入临界区。
算法评价:
- 消耗的带宽,与在每个进入和退出操作中发送的消息数成比例。
- 每一次进入和退出操作由进程导致的客户延迟。
- 算法对系统吞吐量的影响,这是在假定后续进程间的通信是必要的条件下,进程整体访问临界区的比率。
- 用一个进程离开临界区和下一个进程进入临界区之间的同步延迟来衡量着这个影响,当同步延迟较短,吞吐量较大。
分布式系统中的互斥算法主要设计思路是通过协调多个进程之间的通讯和操作来实现对共享资源的互斥访问。其中,临界区是指程序的一部分,该部分需要互斥执行以保证程序正确性。
在分布式系统中实现临界区互斥访问的常用算法包括 Lamport 的分布式时间戳算法、Maekawa 的旋转标记算法等。这些算法通过消息传递和进程协作来达到目标,具体实现过程中,每个进程都会维护自己的状态信息,并通过消息传递与其他进程进行通信。当一个进程需要访问共享资源时,它会发送请求消息给其他进程,并等待其他进程的响应消息。如果其他进程没有正在访问共享资源,则它会授权该进程访问,并向其他进程广播释放资源的消息;如果其他进程正在访问共享资源,则该进程将等待直到可以访问为止。
通过这样的方式,分布式系统中的互斥算法可以保证多个进程对共享资源的互斥访问,从而确保系统的正确性和可靠性。
分布式系统中的互斥算法主要设计思路是通过协调不同节点之间的行为来实现对共享资源的互斥访问。以下是两种常见的互斥算法设计思路:
- 基于中心节点的算法:其中一个节点作为中心节点,其他节点需要向它发送请求并等待响应。中心节点负责协调所有请求,确保每个节点按照指定的顺序访问共享资源。这种算法的缺点是中心节点成为了单点故障,如果中心节点失效,则整个系统将无法工作。
- 基于分布式锁的算法:每个节点都可以申请获取分布式锁来访问共享资源,获取锁的节点可以独占资源并执行相应的操作。由于锁是分布式的,因此任何一个节点都可以释放锁。这种算法的优点是没有中心节点,系统具有良好的容错性能和可扩展性,但是在高负载情况下可能会出现竞争问题,从而导致性能下降。
中央服务器算法
实现互斥的最简单的方法是使用一个服务器来授权进入临界区的许可。
进入临界区——即使在当前没有进程占用它时——需要两个消息(请求和随后的授权)
请求进程被延迟了这一往返时间。
离开临界区需要一个释放消息。
假设采用异步消息传递,这不会对要离开临界区的进程造成延迟。
服务器可能会成为整个系统的一个性能瓶颈。
同步延迟是下面两个消息的一次往返要花费的时间:发送服务器的释放消息,和随后让下一个进程进入临界区的授权消息。
基于环的算法
在N个进程间安排互斥而不需要另外的进程的最简单的方法之一,是把这些进程安排在一个逻辑环里。
这只需要每个进程p1与环中下一个进程有一个信道。
该方法的思想是通过获得在进程间沿着环单向——顺时针——传递消息为形式的令牌赋予互斥。
环的拓扑结构可以与计算机之间的物理互联无关。
算法需求说明
如果一个进程在收到令牌时不需要进入临界区那么立即把令牌传递给下一个邻居。
需要权标的进程将一直等待,直到接收到令牌,保留令牌。
为了离开临界区,进程把令牌发送到近邻。
使用组播和逻辑时钟的算法
开发了一个基于组播的实现N个进程间互斥的算法
基本思想是需要进入临界区的进程组播一个请求消息,并且只有在所有其他进程都回答请求时才进入临界区。
如果一个进程请求进入,而所有其他进程的状态都是released,那么所有进程会立即应答,请求者准入。
如果某些进程在状态held,那么该进程在结束对临界区的访问全不会应答请求。
如果两个进程或多个进程同时进入,则发最早时间戳的请求将是第一个,可能无法继续应答,因为发送请求出去了
容错
当消息丢失时会发生什么?
当进程崩溃时会发生什么?
如果通道不可靠,已经介绍的算法都不能容忍消息的丢失。
选举
选择一个唯一的进程来扮演特定角色的算法成为选举算法。
一个基本的要求是所有进程都同意这个选择。
如果担任角色的进程退休,那么需要另一次选举代替者选择。
我们称一个进程召集选举,如果该进程采取行动启动了选举算法的一次运行。
一个进程每次最多召集一次选举,但原则上N个进程可以并发召集N个选举,
任何时间点,进程或者一个参与者——意指它参加选举算法的某次运行,或者非参加者——没有参加选举
重要的一个选择是对当前进程的选择是唯一的,即使若干进程并发召集选举。
- 例如两个进程可以独立判定一个协调进程已经失败,并且都召集选举
不失一般性:我们要求选择具有最大标识的进程为当选进程
标识可以是任何有用的值,只要标识唯一且可按全序排序。
算法设计需求
- 确定选举触发条件:通常,在以下情况下会启动选举算法:1)主节点崩溃或不可用;2)主节点与其他节点失去联系;3)新节点加入系统。确定何时启动选举对于设计选举算法至关重要。
- 设计选举算法:常见的选举算法包括Paxos、Raft和Zab等,每种算法都有其独特的优点和限制。选举算法应该考虑节点故障、消息延迟和网络分区等因素,并确保在系统范围内选择唯一的主节点。
- 实现选举算法:实现选举算法需要依赖于分布式系统的底层基础设施,例如消息传递、日志复制和节点状态机等。实现算法时需要注意错误处理、数据同步和系统各个组成部分之间的协调性。
- 测试选举算法:选举算法的正确性和效率是非常重要的。测试可以包括模拟节点故障、模拟消息延迟和模拟网络分区等方面。通过这些测试,可以验证选举算法的可靠性和性能。
组播通信
组或组播通信需要协调和协定。目的是使一组进程中的每一个都收到发到组中的,往往带有发送保证的消息的副本。
此保证包括对组中每个进程应当收到的消息集合以及在组成员间的发送顺序达成一致。
组通信系统将其复杂。即使是提供最小发送保证的IP组播,也需要很大的工程上的努力。
时间和带宽利用效率是主要考虑,即使对静态的进程组,也是有挑战。
当进程可以在任意时间加入或离开组,问题会成倍的增加。
基本组播
组播原语保证组播进程不崩溃,一个正确的进程最终会传递消息。
原语为B-multicst,对应的基本传递原语是B-deliver.
为了传递消息的总时间,利用多线程并发执行send操作。如果进程数很大,这样的实现很可能经受一种叫作确认爆炸的情况。
确认爆炸:作为可靠send操作的一部分发送的确认很可能从许多进程同时到达。进行组播的进程的缓冲区很快饱满,因此很可能丢失确认消息,于是进程会 从新发送消息,导致更多的确认和浪费更多的网络宽带。
可靠组播
共识和相关问题
系统模型和问题定义
系统模型包括一组通过消息传递进行通信的进程p(1,2)
一个重要的要求是即使故障之后也要能达成共识。
共识算法要求
- 终止性
- 每个正确进程最终设置它的决定变量
- 协定性
- 所有正确进程的决定值都相同
- 完整性
- 如果正确的进程都提议相同值,那么决定状态的任何正确进程已选择了该值
拜占庭将军问题
交互一致性
同步系统中的共识问题
为了达到共识,每个正确的进程从别的进程那里收集提倡值。
算法进行f+1个回合,在每个回合中,正确的进程组播值。
更具假设,最多f个进程可能崩溃。
最坏情况所有进程都崩溃。
但是算法保证在这些回合结束后,所有活下来的正确的进程都处于一致的状态。
共识算法
共识算法是分布式系统中实现一致性的关键算法之一。它的设计目标是在多个分布式节点之间达成一致性,确保各节点对数据状态的认知是一致的,从而保证系统的可靠性和正确性。
常见的共识算法包括Paxos、Raft、PBFT等,在设计中需要考虑以下几个方面:
- 状态复制:共识算法的核心就是将数据状态复制到所有的分布式节点上。在设计中需要考虑如何实现数据的复制,如何保证数据一致性和可靠性。
- 投票机制:共识算法通常采用投票机制来决定哪个节点具有更高的权威性。在设计中需要考虑如何实现投票机制,并且保证投票结果的正确性和可靠性。
- 容错性:在分布式系统中,节点之间的通信可能会出现故障,因此共识算法需要具备一定的容错性,在节点故障时能够保证系统的正确性和可靠性。
- 性能问题:共识算法的性能也是设计中需要考虑的一个关键问题。在高并发环境下,共识算法需要具备足够的性能和可扩展性,以保证系统的高效和稳定性。
总的来说,在设计分布式系统中的共识算法时,需要考虑数据复制、投票机制、容错性和性能等多个方面,同时需要根据具体的业务需求和系统规模进行合理的设计和优化。