第六章 分布式系统中的容错技术
分布式计算系统区别与单机系统的一个特点就是在分布式系统中存在部分失效的情况,虽然部分失效对整个分布系统的性能有一定的影响,但是不会影响分布系统的整个应用程序的执行。
分布式系统的容错是指系统在面对部分故障时依然能够继续正常运行的能力。
文章目录
1分布式系统中的故障模型
一、可信系统的基本概念
分布计算系统是一个可信系统,分布计算系统的可信性包括以下几个方面:
- 可用性:反应系统随时可被用户使用的特性
- 可靠性:在错误存在的情况下,系统持续服务的能力
- 安全性:系统出现暂时错误的情况下,不出现灾难性后果的能力
- 可维护性:系统一旦出现故障,系统易于修复的能力
- 保密性:要求系统资源不被非法用户访问
从错误的时间特性来看,错误可分为:暂时性的、间歇性的、永久性的
二、基本的故障类型
个人理解从 服务员的接受信息 处理任务 返还信息 几个方面思考。
三、故障处理的基本方法
容错是建立在冗余的基础之上的,冗余是设置超过正常系统操作所需要的信息、资源或时间(也就是系统中的组件或者功能有额外的备份)。
下面是四种冗余类型:
- 硬件冗余:附加额外的处理器、I/O设备 等
- 软件冗余:附加额外的软件版本,主版本失效的时候可以用冗余的版本
- 信息冗余:增加额外的信息来检测和纠正错误
- 时间冗余:为完成任务提供额外的时间,即在关键操作中留出时间冗余,以便在失败发生时可以重试或回滚到以前的状态。
如果把硬件冗余和软件冗余归为一类,冗余又可分为三类:物理冗余、信息冗余、时间冗余
故障处理的基本方法有以下三种:
- 主动复制:所有的副本(复制模块)同时运行,状态紧密同步,任何一个副本发生故障,其他副本可以立刻接管。
- 被动复制:只有一个主副本处于运行状态,其他副本不直接运行,而是定期从主副本更新状态。如果主副本失败,一个从副本会被提升为新的主副本。
- 半主动复制:主动复制和被动复制的混合方法。
失效的检测是为了即使识别系统中故障的节点,分为以下两类:
- 外部检测:将故障检测的任务赋予被检测节点的外部附件
- 内部检测:节点本身检测其自身的故障
所以思考一个问题?冗余、故障处理、失效检测之间有什么联系呢?
在我认为 失效检测是第一步 找到失效的节点然后去进行故障处理 而冗余则是一种预防措施,保证出现故障的时候,分布式系统仍然能运行和服务 这三个共同组成了分布式系统的核心容错策略
2容错系统的基本构件
容错系统的基本构建有三种:坚固存储器、故障-停止处理器、原子操作
一、坚固存储器
坚固存储器是一个对可以经受系统失效的特定存储器的逻辑抽象,可以安全的存储信息,以便需要的时候能够恢复信息。
1、磁盘镜像
坚固存储器可以用一对普通磁盘来实现,分别位于不同的驱动器上,使得他们同时由于硬件故障收到损坏的机会最小。
2、RAID
坚固存储器的另一种实现方法是使用廉价磁盘冗余阵列,RAID就是通过运用位交错技术将数据分不到多个磁盘当中,从而提高I/O性能,可以用一个或者多个磁盘来检测或屏蔽错误,并可承受多个失效。
二、故障-停止处理器
故障-停止处理器:当一个处理器失效的时候,最可能的是它不进行任何不正确的操作,并且简单的停止运行,一个故障停止处理器由多个处理器组成
当出现一个故障的时候,故障-停止处理器会有以下的效果
-
处理器停止运行;
-
易失性存储器的内容丢失,而坚固存储器不受影响;
-
任何其他处理器均可以检测到故障—停止处理器的失效状态。
三、原子操作
一个原子操作就是由硬件独立执行的一系列动作。每一个动作或者被完全彻底的执行,或者所有的动作根本没有执行 ,系统的状态保持不变。
原子操作中的每一个动作都是孤立的,当执行这一动作时,在进程中感觉不到外界活动的存在,也意识不到外界状态的变化。与此相似,任何外界的进程均感觉不到一个孤立的原子操作的内在状态的变化。这就是所谓的原子操作的“全有或全无”的性质,即一个原子操作要么全部完成,要么在执行过程中出现错误的时候相当于根本没有执行。
原子操作失效时,可以通过简单地重做来恢复。
3节点故障的处理
在被动复制中可以使用向前式恢复和向后式恢复。(两者的假设不同,向前式恢复假定可以准确知道系统故障和损失的性质,而向后式恢复则是假定不知道)
在向前式恢复中,假定可以完全准确地得到系统中的故障和损失的性质,这样就有可能去掉这些故障从而使得系统继续向前执行。向前式恢复也可以回卷
向后式恢复适用于系统的故障无法预知和去掉的情况,在这种情况下,要定时的存储系统的状态,这样当失效导致系统处于不一致的状态的时候,系统可以恢复到从前没有发生故障的状态,在此状态下重新执行。
一、向后式恢复
检查点:在向后式恢复中进程被恢复到一个先前的正确的状态,进程执行中的一些点被称为检查点。在以后发生错误的情况下,进程可以恢复到这些点,在检查点的实现过程中需要考虑检查点的存储和检查点的更新两个问题。向后式恢复除了使用检查点方案之外,还有一个基于基于影像页面的恢复技术
1、检查点的存储
有两种存储方式
- 每一个检查点被组播到每一个备份模块
- 每一个检查点被存储在它的本地坚固存储器中
2、检查点的更新
当进程正确地从一个旧的检查点运行到一个新的检查点时,旧的检查点就要被新的检查点替换。当进程执行到两个检查点之间时发生错误,那么进程应该卷回到旧的检查点处重新执行。
检查点的原子更新:当使用新的检查点替换旧的检查点的过程中,系统也会发生失效。这可以通过检查点的原子更新过程来解决,也就是说,在检查点的更新中,要么旧的检查点被新的检查点替换,要么旧的检查点被完整地保留。
检查点的原子更新的实现:假设库A和库B现在保存的检查点是C1,现在要用检查点C2取代库A和库B的内容。在取代前,假设Ta1=Ta2=Tb1=Tb2=1,检查点的更新过程如下:(1) 为了更新库A,先置Ta1=2;(2) 将库A的内容用检查点C2取代;(3) 库A更新完毕,置Ta2=2;(4) 为了更新库B,先置Tb1=2;(5) 将库B的内容用检查点C2取代;(6) 库B更新完毕,置Tb2=2;
3、基于影像页面的恢复技术
在基于影像页面技术的方案中,当进程需要修改一个页面时,系统复制该页并保留在坚固存储器中。系统中每个页面都有两个拷贝,当进程在执行的过程中,只有其中的一个拷贝被进程修改,另一个拷贝就作为影像页面。如果进程失效,则丢弃被修改的拷贝,系统根据影像页面进行恢复。如果进程成功运行,则每一份影像页面被相应的修改后的页面替换。
二、向前式恢复
一个向前式恢复策略式一种回卷的前瞻性运行。
在这个过程中,系统首先尝试通过比较和验证来确定正确的结果,这是向前式恢复的关键特征。只有在无法通过这种方式确定正确结果时,才会进行回卷操作。这与传统的向后式恢复不同,后者在检测到错误时通常直接回卷到之前的检查点。向前式恢复试图减少回卷的频率,从而节省时间和资源。
- 没有并发重试:
- 如果在间隔Ii中,X和Y的结果都是正确的,且相同,那么没有必要进行重试。这意味着这个阶段的操作是成功的。
- 有非回卷的并发重试:
- 如果在间隔Ii中出现错误,但在随后的间隔Ii+1和Ii+2中没有错误,那么可以通过比较X和Y的结果来确定正确的进程,而不需要回到起点重新开始。
- 例如,如果X在Ii中是正确的(1),而Y是错误的(0),且S验证X是正确的(1),系统就知道X是正确的,不需要回卷。
- 在一次并发重试的间隔后进行回卷:
- 这种情况发生在Ii中两个进程(X、Y或S)出现错误的情况。
- 根据(Xi, Yi, Si)的状态,如果出现(1,0,0),(0,1,0),(0,0,d)等情况,系统需要回卷到Ii的开始处,重新执行这一阶段的操作。
- 在并发重试的两次间隔之后回卷:
- 这种情况发生在检查点间隔Ii+1处出现了额外的错误。
- 如果无法确定Ii+1中哪个进程是正确的,如(1,0,1,d,d,0),(1,0,1,0,d,d),(0,1,1,d,d,0),(0,1,1,d,0,d)等情况,系统需要回卷到Ii+1的起始处,重新执行这一阶段的操作。
4分布式检查点算法
一、一致性检查点
假定每个进程定期地在坚固存储器中对状态设置检查点,而且每个进程设置检查点的过程是独立的。
全局状态:一种全局状态的定义是一系列局部状态的集合,这里的局部状态就是每一个进程的检查点,每个局部进程都有一个局部状态。
但是局部检查点可能因为检查点设置不合理可能会组成两种不一致的全局状态:
- 丢失报文:进程A的检查点状态显示给进程B发送了报文m,但是进程B没有关于该报文的记录
- 孤儿报文:进程B的检查点状态显示收到了来自进程A的报文m,但是进程A的状态显示他没有向进程B发送过报文m
多米诺效应:由于一个进程的回卷导致另外一个或多个进程的回卷的效应
进程A向B发送了一个报文,但是在下一个检查点之前A由于某些故障被回卷了,而B已经接受了这个报文,而且可能对该报文处理后又传给了其他进程,但是此时对于A而言,这个报文是未来的报文,所以B必须回卷才能与A保持一致性,其他进程也必须回卷,成多米诺了。
一个一致的检查点集合是由一系列没有孤儿报文的局部检查点组成。
一个强一致(strongly consistent)的检查点集合是由一系列的没有孤儿报文和没有丢失报文局部检查点组成。
显然一个强一致的检查点集合包括一系列局部检查点,在这些检查点之间,进程之间没有报文传送。如果每个进程都在发送一个报文之后生成一个检查点,那么最近的检查点集合将永远是一致的。
恢复线和切割线:当一个进程或系统失效的时候要求利用这些局部状态重新构造一个全局一致的状态。一个分布式快照对应一个全局一致的状态,这个分布式快照可以作为一个恢复线(recovery line)用于恢复。一个恢复线对应于最近的一个一致性切割线。
检查点的设置可以是同步的、异步的,也可以是二者的混合。另一个选择就是要给一个进程发送和接受的报文做日志
二、异步检查点
异步检查点算法程序中检查点状态的保存过程较为简单,程序中各进程周期性、相互独立的保存自己的运行状态,程序各进程之间不需要相互协商。
在恢复过程中,各进程之间则需要相互协商通过复杂的回卷算法各自回卷到合适的检查点时刻以使整个程序的各个进程恢复到最近的一个一致的全局状态。
一致检查点的检测方法:
-
比较发送的和接收的报文数量来检测孤儿报文的存在。如果接收到的报文数目和任何发送报文的进程发送的报文的数目是一致的,那么就可以认为找到了一个局部检查点的一致集合。
-
使用间隔依赖图来进行检测。如果每个进程i的向量时钟是LCi,一个检查点集合是一致的,当且仅当不存在i和j满足LCi<LCj。
异步检查点算法的优缺点:优点是允许分布式程序的各个进程拥有最大程度的自治性,因而算法的延迟较小。缺点之一是由于每个进程需要保存若干时刻的检查点信息,空间开销较大;缺点之二是在恢复过程中可能会重复回卷,甚至出现多米诺效应,使程序一直回卷到初始状态。
三、同步检查点
在同步检查点算法中,各相关的进程协调它们的局部检查点的建立行为,以保证所有的最近的检查点都是一致的。在同步检查点中,只有最近的一致的检查点集合才需要被维护和保存。
同步检查点算法的优缺点:由于使用同步检查点算法,各进程的局部检查点组成的集合是一个全局一致的状态,所以在恢复时各个进程只需要简单地从检查点处重新开始执行。同步检查点算法的优点是每个进程只需保存最近时刻的检查点信息,空间开销较小,且在恢复的时候没有多米诺效应。其缺点是,在建立检查点时,各进程间的同步使程序运行中止时间较长,且牺牲了分布式程序的自治性
同步检查点是目前在实际系统中较为常用的算法,典型算法有 SNS算法和CL算法
1、SNS算法
SNS算法中有一个进程PC负责管理全局检查点建立过程,各进程的检查点建立过程如下:
a)pc向所有进程广播检查点开始报文Mb(第一次同步开始);
b)任一个进程接收到报文Mb后停止运行,并在自己所发送的报文全部到达接收者后向pc进程发送报文Ms1;
c)pc接收到所有进程发送的报文Ms1后,即意味着第一次同步结束。pc向各进程广播报文Mchk,第二次同步开始;
d)任一个进程接收到报文Mchk后,立即作局部检查点,检查点建立完成之后向pc发送报文Ms2;
e)pc接收到所有进程发送的报文Ms2后,意味着第二次同步结束。pc向所有进程广播报文Me;
f)各进程接收到报文Me后,删除旧的检查点,仅保留新的检查点,然后继续执行。SNS算法的恢复过程十分简单,只需回卷到检查点处继续执行。
经过第一次同步之后,任何进程所发送的报文都已经被对应的接收进程接收到,任何进程之间不会存在孤儿报文,满足一致性的要求。
2、CL算法
每两个机器之间通过通道 直接相连 mc与机器m1相连 m1与m2相连
a)建立检查点的过程可由任一个进程pc发起,pc进程停止运行,并向与其所在机器直接相连的机器上的进程广播报文Mb,然后进程pc建立局部检查点;
b)进程p接收到报文Mb后,若进程p还未开始建立检查点,则进程p停止运行并立即向与其所在机器直接相连的机器上的进程广播报文Mb,然后进程p建立局部检查点;
c)进程p开始建立检查点后,若接收到其他进程发送的非检查点控制报文m,则保存报文m;
d)当进程p完成局部检查点的建立,并且接收到与其所在机器直接相连的机器上的所有进程发送的报文Mb后,进程p向pc进程发送报文Ms;
e)当进程pc接收到所有进程发送的报文Ms后,pc进程向所有进程发送报文Me,并删除本进程旧的检查点,进程pc继续执行;
f)其他进程p接收到报文Me后,删除本进程旧的检查点,继续执行。
在恢复过程中,CL算法在回卷到当前检查点重新执行的同时还必须重发过程c)中保存的报文m。与SNS算法相比,CL算法减少了两次全局同步的开销。CL算法的缺点是其控制报文的数目与机器间的拓扑结构有关。
四、混合检查点
混合检查点结合了同步检查点算法和异步检查点算法的优点
其基本思想是在一个较长的时间段中使用同步检查点,而在较短的时间段内使用异步检查点。也就是说,在一个同步时间段里,会有若干个异步时间段。因此,我们可以有一个可以控制的回卷,从而保证不会在建立检查点的过程中引入过多的开销。
五、报文日志
如果进程Pj记录了报文m的接收者日志,那么Pi和Pj的当前检查点集合就可以看作是一致的。一旦由于Pj由于失效回卷到当前检查点重新执行的时候,报文m就可以通过Pj的接收者日志重新发送给进程Pj,不会引起进程Pi的任何回卷。
如果Pi在发送完报文m后失效,那么当进程Pi恢复到当前检查点后,它会根据发送者日志的纪录知道曾经发送过报文m,这样就没有必要再发送一次了。如果接收者Pj失效,而且没有接收者日志,它仍然可以根据从发送者日志中得到的报文正确恢复。
5可靠的组通信
所谓的可靠的组播通信,就是要求发送给某个进程组的报文必须确保传送到进程组中的每一个成员。
一、基本的可靠组播方案
接收者收到组播报文之后不向发送者发送应答报文,只有在接受者发现丢失一个报文之后,才向发送者发送一个反馈报文,指出某个报文丢失了。
需要考虑一个问题,如果丢失了好几个报文,那么就会出现反馈报文拥塞的情况
需要考虑一个问题,发送者必须在历史缓冲区中长时间保存它发送的每一个广播报文
1、非层级式反馈控制
非层级式反馈控制采取了反馈抑制的方式减少返回给发送者的反馈报文数目,在该方式中,只有接收者发现有报文丢失的时候才会发送反馈报文,但是这个反馈报文不仅会返还给发送者还会发送给组播给当前组的所有成员,以达到阻止其他未接受成员重复发送反馈报文的作用。
但是需要注意的是如果多个进程丢失了报文,他们中的两个或多个同时组播了反馈报文,也会导致发送者的重复组播,所以为了阻止这种现象,如果一个接受者发现丢失了报文,它并不立即组播反馈保温,而是延迟一段时间,所以必须要精确设置每一个接收者的延迟时间。初次之外,已接受报文的进程会重复接收到没用的报文。
2、层级式反馈控制
在层级式可靠的组播方案中,进程组被划分成多个子进程组,这些子进程组被组织成树型结构,包含有发送者的子进程组是树的根。在一个子进程组内,可以采用任何一种可靠的组播技术。
每个子进程组任命一个本地协调者,负责处理该子进程组内的接收者的重发请求。本地协调者有自己的历史缓冲区。如果协调者本身丢失了报文m,它会要求它的父亲子进程组的协调者重发报文m。
二、原子组播(考虑组播进程组中有进程失效的问题)
原子组播:必须保证一个组播报文要么被进程组内所有的进程接收,要么没有一个进程接收该报文。另外,还要求所有的组播报文应该以同样的顺序被进程组中所有的进程接收。
**组视图:**原子组播的实质是一个组播报文m唯一地和需要收到这个报文的一组进程相联系。需要收到这个报文的进程表是包含在这个进程组中所有进程的集合的一个视图,这个视图成为组视图(group view)。当有进程离开或者加入这个进程组的时候,进程组的组视图就被改变。
虚同步:一个进程在发送报文m的时候某个进程失效的时候,进程组的其他进程要么都收到报文m,要么所有的其他进程都忽略报文m,具有这种性质的可靠的组播被称为是虚同步的组播。
虚同步的原理其实就是每一个组播通信发生在视图改变之间。也就是说,一个视图改变扮演者一个栅栏的作用,组播不能跨越栅栏。任何一个组播通信都是发生在一个视图改变之后,并且在下一个视图改变起效之前完成。
按照组播报文的排序规则,组播可以分为以下四类:
- 无序组播:可靠的无序组播是一个虚同步组播,它不保证不同的接收进程对不同的组播报文的接收顺序。
- FIFO顺序组播:通信层保证同一个进程发送的不同的组播报文,不同接收进程会按报文的发送顺序接收。但是不同的进程发送的不同组播报文,不同的接收进程可能会有不同的接收顺序。
- 因果关系顺序组播:所有接收进程必须按报文固有的因果关系顺序接收。例如报文m1按因果关系排在报文m2之前,那么所有的接收进程必须先接收报文m1后接收报文m2,不管m1和m2是否是由同一个发送者发送的。如果报文之间不具有因果关系的先后顺序,不同的接收进程可以有不同的接收顺序。
- 全局顺序组播:不同的接收者必须按完全相同的顺序接收所有的报文。无论是无序组播、FIFO顺序组播还是因果关系顺序组播都可以附加一个全局顺序的约束条件。