高可用高性能系统(三)故障管理

     高可用系统必须对故障具备很高的容错能力,而这核心问题就是对故障的管理。从系统组成来看,故障可能是整个系统的,或者某个组件、某个服务甚至某个进程中发生。对故障的管理可以分为几个过程:检测、定位、隔离、恢复、报告。如果继续强化的话,还应该加入预测功能。

    故障的检测主要工作是检测系统中在某个单元是有故障发生。故障的定位主要是判断这个故障发生在哪个单元以及这个单元具体在哪个位置。故障隔离是将发生故障单元从系统中摘除,使得故障不会在系统中继续传播。故障恢复是故障发生单元在处理故障之后,继续恢复服务。故障报告是将发生故障的类型、位置、结果报告给监测人员。
    故障预测是比较高级的功能,他需要对一个系统有比较深入地认识,对一些非通用的系统需要建立专家规则。但依然存在许多可以被通用化的预测规则,比如网络拥塞在一个单元上被监测,那么相关单元发生网络拥塞就可以被预测的。

一、故障区域单元划分
    检测、定位、隔离故障,首先将整个系统划分为相互独立的单元,这个单元可以是一台机器,一个进程,或者一段代码。这些依赖于控制粒度。我们将整个系统视为一棵树的根,每个单元可以包含更小粒度的子单元,每深入一个层次,都要提供更小的粒度。对于故障检测系统来说,可能处于这颗树的某个层,负责监控这个层某些兄弟单元的故障情况。对于某个单元的子单元如果发生故障,最好由该单元负责检测,再报告给更高层次的监控系统,或者该单元中负责检测的子单元来负责。我们将整个系统树化为不同粒度的单元,对检测故障、定位、隔离故障是有效的。

二、故障检测的方法
    在故障检测的方法中,心跳是最常用的方法。如果在一定时间内,一个单元没有和监控单元交互心跳,则认定该单元已经失效。但这个方法由一个很大的问题,就是心跳时间无法把握。如果太长了,就可能无法及时发生问题;如果心跳时间太短,对系统是个负担,而且对大型处理任务可能无法作出有效判断。
    比如,有个查询需要耗费DBMS时间,而这个期间,单元必须继续等待,直到查询结果。这个过程可能导致无法回应心跳,而可能被系统判定为失效,而将查询转发到其他单元,让DBMS性能继续恶化,而导致最终崩溃。阻塞可能导致心跳失效,但系统本身并没有失效,但处理结束后,系统会自动恢复正常,这时候就可能发生冲突问题。但实际上,现有的解决方案中,都是以心跳为基础,或者加入多路心跳线。
    心跳是最核心的方法,但他无法应对阻塞的情况,包括网络、机器、进程。我们并不否认心跳的有效性,我们需要在心跳的基础上,加入拥塞的检测办法来作为补充,比如判断cpu,IO,网络通讯等辅助手段。我们通过心跳来检验单元失效问题,但我们同样必须预防假失效的发生,因为阻塞的存在,所以假失效发生的可能性还是相当大的。避免假失效问题,很难使用统一的办法,必须针对不同情况,采用不同的策略。但心跳检测依然是检测单元失效最重要的方法。对于比较常见的网络失效问题,我们认为通过ping等更低层次的方法来检测比较合适。因为如果继续通过套接字来检测,依然会阻塞在套接字发送和接收过程中。
    故障类型不单是失效,而且还包含其他类型的故障,比如网络故障、数据库故障、存储故障等,是无法通过心跳检测来完成。我们会通过另外的文档来更详细的讨论这个问题。
    心跳的作用等价于轮询,她不停地询问对方地近况,在对方没有应答的时候推断对方失效。在正常情况下,这个没有问题,但在故障发生的时候,就显得延时过大。我们需要一些更加主动的措施来触发检测,比如,当对方网络断开连接的时候,这时发送和接收报文显然会发生问题,这样可以马上触发检测,而不是继续等待到心跳周期的到来。主动和被动两种检测触发方式,可以互相补充。另外,我们可以将大型的任务划分为更加细小的子任务,每个子任务的执行时间比较短,这时,我们可以在每个子任务执行间隔进行心跳检测,这样可以避免大型任务无法及时检测造成的假失效。

三、心跳检测服务
    心跳检测如果在多个单元之间互相守护,给心跳检测的管理带来巨大的复杂度。一个服务单元需要管理多个其他的服务单元,这个对系统没有什么好处。我们可以设计一个心跳检测服务,将这个功能独立出来。服务单元之间的网状心跳检测就转化为服务单元和心跳检测单元之间的线性过程。不幸的是,心跳检测服务之间依然需要互相守护,这样可能构成一个无限递归的过程。但是我们只需要对心跳服务设计互相守护的双机检测机制,就可以终止这个无限递归过程。
    有个思路解决多个单元互相守护问题比较有趣,类似于选举机制。构成一个系统的多个服务单元通过选举算法推举出一个单元作为主服务,当该单元时,新一轮的选举再次发生。这是个动态的过程,和建立一个特定心跳检测服务的静态方法不同,具备更大的灵活性,当然复杂度也更高了。我还没有仔细研究他有什么好和不好,显然他们的内部自治度更高,不过向哪个单元查询他们内部状态是个头疼的问题。

四、故障定位
    故障定位是通过故障检测发现某个单元发生了故障。我们已经将整个系统分割成互相独立的若干单元,并且每个单元还可以继续细化为更小的单元。故障定位实际上仍然可以被看成为另外一个故障检测的过程。如果故障在网络单元之间发生,我们通常可以利用ping来确认和定位,这已经是比较成熟的技术了。在进程中的定位,同样需要依赖于软件方式,参考《返回码的设计》一文中,提供了这样的一个思路。树型结构比网络拓扑要简单地多,我们在故障定位时,主要借助树型区域来逐渐细化故障区域。

五、故障隔离
    故障隔离就是将失效或者发生故障的单元从服务单元列表中摘除。软件和硬件有所不同,硬件可能是需要更换,但软件只需要做状态重置就可以了,速度要快多了,硬件更换的处理在逻辑上却简单。隔离的另外一个需要注意的是,必须控制导致故障的请求不能继续传播,需要采用一定的规则来限制畸形请求在系统中的传播。故障隔离原则可以参考硬件采用“失效即停”的规则。
    故障检测、故障定位、故障隔离是一个连续的过程。隔离依赖于定位、定位依赖于检测。隔离需要把握一个单元粒度问题,如果是一个进程发生了故障,应该没有必要将整个机器隔离掉,我们只要简单地将这个进程从服务列表中摘除就可以,这台机器上的其他服务进程依然继续提供服务。

六、故障恢复
    将故障隔离后,需要尽快的恢复系统。故障恢复需要将故障恢复到可以继续服务的状态。故障恢复需要解决几个问题,从什么地方开始恢复,需要恢复什么内容,这在设计时是需要注意的。为了便于设置恢复点,我们需要将一个连续的过程分解成多个子过程。以便耗费最小的代价来恢复。恢复内容一般都从外存中读入内存。
    日志型文件系统的设计为我们提供很好的思路,DBMS的事务也是为故障恢复提供很好的借鉴。一般来说,我们将一个操作划分2个步骤,一个是实际业务操作,一个是状态设置。实际业务操作由于需要大量的时间和资源,而状态设置相对简单,发生错误的概率要小得多,耗费资源也少的多。当实际业务操作完毕,那么状态设置为成功。如果状态没有设置成功,就可以将故障恢复到之前。故障恢复主要涉及的问题就是恢复点,恢复的内容和业务相关。

七、故障报告
    故障报告没啥好说的,只要将故障的内容、位置报告给合适的人就行了。

    故障管理是高可用的一个核心方案。我们现在主要讨论的是通过心跳来对失效进行管理,但问题远不止于此,我们需要更复杂的机制来讨论这个问题。在以后的章节中继续论述。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值