打造高可用的系统

两年前曾经写过一篇《构建高可用系统的常用招数》,主要是从软件设计的角度来阐述,而自从自己从研发转到运维后,这两年来看到了更多的故障,同时更深刻的感受是要打造一个高可用的系统,不是仅仅在软件设计、研发、测试阶段保障质量就ok的,但基本事实是随着业务的发展,系统的复杂度、新加入人员的冲击都会对质量带来极大的影响,因此故障基本是不可避免的,这个时候故障的恢复能力就非常重要,而故障的恢复能力不仅仅是一个简单的操作,其涵盖的一整套体系,从系统的架构到变更到故障出现后的响应机制。

在故障应对这个领域,很容易犯的一个错误就是在故障的根源定位上投入非常大的精力,这个领域投入固然是有价值的,但更多的情况会发现这个领域投入产出比很低,因为真心太难做了,之所以很容易投入更大的精力在故障的根源定位上,是因为在传统的思维上,我们都认为只有定位到了故障的根源才能制定相应的策略来修复故障,但事实上随着系统架构的演变,完全可以有更好的办法。

首先我们看看故障发生时影响的范围大小,通常来说是以下几种:
1. 单实例
单台机器出问题,可能是各种原因,例如硬件故障,或应用出了个偶发故障。
2. 单应用集群
系统里的单个应用集群全体出现故障,出现的故障的原因同样可能多种多样,网络、应用软件bug等,都有可能。
3. 多应用集群
系统里的多个应用集群都出现故障,不过话说其实单应用集群出故障也很容易导致这种现象。
4. 单机房
单个机房整体出现故障,这种通常来说是网络或机房(例如雷击,:))出现故障。
5. 单地域
单个地域出现问题,可能大家觉得很罕见,但事实上有多种因素可能会造成,例如运营商在某片的故障等。
6. 全局
所有应用集群都出故障了,对于没有多个机房、多个地域的而言,单机房的就算全局故障了。

上面的几种故障范围出现后,是否一定要先查出原因才能恢复故障呢,那是不一定的,恢复故障和修复故障完全是两个概念,就上面几种故障范围而言,在恢复故障上可以采用这样的方法:
1. 单实例
对于单实例故障的快速恢复,可以通过改造为集群方式,对于无状态的比较容易搞定,集群+七层健康检查基本就非常有效了,可以做到在出问题时自动应对;
对于有状态的,比较复杂一点,通常需要做主备,或类似paxos的一主多备等结构来做到单个实例出问题时的自动应对。
因此通常来说,单实例的故障是完全不应该影响到业务的。
2. 单应用集群
对于单应用集群整体故障的现象,如果是非关键路径的应用,可通过自动降级或手工降级来快速恢复故障;
如为关键路径的应用,应用部署在多个机房,并且只有一个机房的有问题,那么可以通过快速的切掉这个机房的流量来恢复故障。
3. 多应用集群
和单应用集群采用同样的方法。
4. 单机房
对于单个机房出故障,如系统是多个机房部署的,那么可以采用切掉这个机房的流量来快速恢复故障,这要求系统部署在多个机房,并且具备快速切换能力。
5. 单地域
对于单地域出故障的情况,如系统能做到异地多点部署,那么同样可以采用切掉机房流量来快速恢复故障。
6. 全局
如为全局出故障,那基本上只能靠定位故障,然后来看看怎么快速恢复。

从上面这个简单的阐述可以看到,除了全局故障外,其他类型的故障在系统架构演变到一定阶段后,基本都可以做到在不定位故障的情况下快速恢复,当然要做到影响面越大的故障快速恢复,系统架构的复杂度和难度也会自然的要求更高,同时要确保不同影响范围情况下的故障快速恢复按钮能100%生效,则需要靠不断的演练来确保。

故障发生主要的一个因素是变更(对线上做的任何影响行为的动作都可以认为是变更),即使是在有强大的系统架构情况下,也需要通过靠控制变更范围来发挥出系统架构具备的故障恢复能力,例如系统已经做到了多机房部署和切换的能力,但变更时同时操作了所有机房(例如最典型的是推配置信息),那么这个时候如果出故障,就完全没办法,最多能依靠的是快速回滚等,因此在系统架构具备较强的故障快速恢复能力的情况下,也要相应的改变变更操作的流程,以控制每次的影响范围。

要发挥出这种大杀器级的故障快速恢复的能力,还有最后一点重要的就是在故障发生后要立刻尝试上面的恢复招数,而不是去分析和定位故障的原因,这需要改变习惯。

所以总的来说,要做到故障的快速恢复,其实是一个体系化的工作,非常不容易,而一旦能做到,那对系统的高可用可以起到极大的帮助,我的团队为阿里制定了一个这样的故障恢复体系的标准,感兴趣的同学可以看看QCon北京上的《分钟级故障恢复的高可用保障》的ppt。

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。