什么是高可用?

高可用性 (High Availability – HA) 指的是系统具备较高的无故障运行的能力, 大白话的说, 就是你的系统在提供服务过程中, 不遇到或者几乎很少遇到影响服务质量的事件(诸如服务器宕机、一段时间内提供的数据都是错误的这种).

怎样才算是高可用?

对于可用性的度量, 有着两个相关度量参数:

  1. MTBF(Mean Time Between Failure) 平均故障间隔: 两次故障的间隔时间. 时间越长, 系统稳定性越高.
  2. MTTR(Mean Time To Repair) 平均故障时间。值越小,故障对于用户的影响越小。

一般用 MTBF / (MTBF + MTTR) 来代表系统的可用性, 表达式可以理解为: 系统正常运行的时间, 在系统总运行时间中的占比.

系统可用性 年故障时间 日故障时间
90%(1个9) 36.5天 2.4小时
99%(2个9) 3.65天 14.4小时
99.9%(3个9) 8小时 1.44分
99.99%(4个9) 52分钟 8.6秒
99.999%(5个9) 5分钟 0.86秒
99.9999%(6个9) 32秒 86毫秒

在不同的可用性百分比要求下, 对应着不同的处理方式:

  • 1/2个9的时候:

人肉管理, 人肉监控即可.

  • 3个9开始:
  1. 运维值班体系: 设置监控、报警等, 出现问题时快速响应, 快速定位;
  2. 故障处理流程: 根据问题严重级别提升上线/修改的效率;
  3. 业务变更流程: 服务包的直接更替往往会出现服务的不可用, 考虑是否要考虑热部署来保障服务上线的平稳过度;
  • 4/5个9的时候:

依赖机器的自动容灾处理(等到人发现、通知、上线, 远大于这个时间).

综上所述, 一般来讲, 对于核心系统的可用性要 >= 4个9, 非核心系统可用性 >= 3个9.

互联网应用, 提供服务的正确性收到的影响来自方方面面, 单纯的要求不出错是不现实的. 高可用是一个抽象概念, 是在对比中产生. 比如说: 日活用户1000的系统, 在衡量一分钟的故障时间时, 远没有日活用户1000w的系统来的严峻.

要怎么做到高可用?

系统设计

"Design for failure", 在设计系统的时候, 就要把故障的时候如何将影响降到最低考虑进去. 在成型的互联网应用中, 一个集群的机器经常可以达到三位数, 甚至四位数, 如此大的基数, 单机故障几乎是常态, 所以在设计系统之初就要提前考虑好故障的发现和解决, 包括但不限于:

  1. 故障转移:
    a. 完全相同服务节点之间做替换, 比如Nginx可以配置在某一个Tomcat的返回code为500时自动重试其他的Tomcat节点;
    b. 主备服务节点之间切换: 通常来讲, 由代码去检测提供服务的主节点是否能够继续提供服务, 比如心跳监测机制, 当监控者一段时间没有收到主节点的心跳信息, 视为主节点down, 开始重新选主(这里需要保证所有的备份节点在提供服务状态上保持一致, 通常会使用分布式一致性算法, 例如Paxos, Raft等).
  2. 超时控制:
    a. 复杂的业务中往往需要较多的RPC接口调用来组装数据, 如果没有对应的超时控制, 大量的慢请求就会把服务夯死;
    b. 系统超时时间的制定, 通常以一个系统的普遍响应时间为准, 同时也要在系统的维护中不断修改;
    c. 超时控制本身是通过牺牲少量超时请求来保证系统的整体可用性.
  3. 降级: 通过减少某些服务流程来保证主流程的畅通, 比如发帖时的垃圾帖检测, 当可遇见的发帖高峰到来时, 就可以降低垃圾帖的检测标准, 甚至暂时去掉这一检测, 来保证主流程不会被这个非核心业务拖垮;
  4. 限流: 通过计算和故障演练后, 单个节点能够承受的Qps为100, 那么超过100Qps的时候, 多出来的并发请求就被丢弃掉, 虽然对于多出来的用户体验很糟糕, 但是在大量请求的场景下只能如此.

系统运维体系

  1. 灰度发布

代码是具有固定逻辑和运转条件的, 错误的代码轻易无法正常运行, 换言之正常运行的代码, 在正常的业务请求下也不会经常出现问题. 但是在版本更迭的时候, 由于存在较多的环境变化, 所以是问题多发期. 那么除了出现问题时的上线回滚外, 常见的运维手段就是 "灰度发布".

常见的灰度发布是指, 代码版本的变更不是一次性被推到线上的, 而是以机器节点为纬度, 按照一定的百分比逐渐推送到线上. 在这一过程中就可以通过各种看板对变动的系统进行监控, 如果运行了一段时间之后没有出现大量报错, 就可以推动全量升级.

  1. 故障演练

不打无准备之仗, 是我中华儿女自古而来就具备的战略思想, 灰度发布让我们有机会来减少故障发生的影响, 那么故障发生时我们又该怎么办? 有哪些故障会发生? 这些问题只通过代码review通常无法得到答案, 这个时候我们就需要故障演练来保证, 大多数问题我们是已经见到过的, 可以有组织有几率的处理问题.

故障演练不一定非要在线上进行, 因为某些系统的故障在业务场景是不被允许的(比如说一共就三台节点, 那么进行一台节点的down掉演练显然是不合适的). 可以通过环境隔离在线下模拟一套完全相同的环境和数据, 以此来模拟故障发生.

题外话

系统的可用性通常和性能是要做出取舍的, 追求极致的性能势必要舍弃一些可用性, 反之亦然.