系统设计学习(二)系统怎样做到高可用

系统设计学习(二)系统怎样做到高可用

写在前面

​ 这篇文章主要分享再系统设计中怎样设计高可用系统,整体偏理论,up也会根据自己的项目来写一些自己如何改造成高可用的列子。

高可用性(High Availability, HA)是我们经常听到的名字,无论是再平时的工作还是面试中,都是一个热点词汇,up再面试各种大厂中都会问就是了解系统的高可用嘛? 怎么保证高可用?你做过那些高可用? 这些问题真的是很常见。所以才有了这一系列文章的诞生。言归正传,我们在很多开源组件的文档中都会看到HA的方案,它可以有限性的避免系统宕机后无法服务的问题。大部分方案都是所谓的一拖几,也就说一个主节点,多个备用节点,当主节点出现问题的时候,备用节点无状态转移,使问题及时和用户无感知解决。

通常来讲,一个高并发大流量的系统,系统出现故障比系统性能低更损伤用户的使用体验。 想象一下,一个日活用户过百万的系统,一分钟的故障可能会影响到上千的用户。而且随着 系统日活的增加,一分钟的故障时间影响到的用户数也随之增加,系统对于可用性的要求也 会更高。所以高并发下的高可用显得尤为重要,我们如何来保证系统的高可用性,以便 给你的系统设计提供一些思路。

可用性度量

​ 做到高可用的第一步就是要知道什么是高可用,然后还需要知道怎么判断高可用,也就说怎么度量可用性。其中最主要的两个概念就是:MTBFMTTR

MTBF(Mean Time Between Failure) 是平均故障间隔的意思,代表两次故障的间隔时间,也就是系统正常运转的平均时间。这个时间越长,系统稳定性越高。

MTTR(Mean Time to Repair) 表示故障的平均恢复时间,也可以理解为平均故障时间。这个值越小,故障对用户的影响越小。

可用性与 MTBF 和 MTTR 的值息息相关,我们可以用下面的公式表示它们之间的关系:

Availability = MTBF / (MTBF + MTTR)

这个公式计算出的结果是一个比例,而这个比例代表着系统的可用性。一般来说,我们会使 用几个九来描述系统的可用性。

系统可用性年故障时间日故障时间
90%(一个九)36.5天2.4小时
99%(两个九)3.65天14.4分
99.9%(三个九)8小时1.44分
99.99%(四个九)52分钟8.6秒
99.999%(五个九)5分钟0.86秒
99.9999%(六个九)32秒85毫秒

其实通过这张图你可以发现,一个九和两个九的可用性是很容易达到的,基本上可以通过人肉运维的方式实现。

三个九之后,系统的年故障时间从 3 天锐减到 8 小时。到了四个九之后,年故障时间缩减 到 1 小时之内。在这个级别的可用性下,你可能需要建立完善的运维值班体系、故障处理 流程和业务变更流程。你可能还需要在系统设计上有更多的考虑。比如,在开发中你要考 虑,如果发生故障,是否不用人工介入就能自动恢复。当然了,在工具建设方面,你也需要 多加完善,以便快速排查故障原因,让系统快速恢复。
到达五个九之后,故障就不能靠人力恢复了。想象一下,从故障发生到你接收报警,再到你 打开电脑登录服务器处理问题,时间可能早就过了十分钟了。所以这个级别的可用性考察的 是系统的容灾和自动恢复的能力,让机器来处理故障,才会让可用性指标提升一个档次。

一般来说,我们的核心业务系统的可用性,需要达到四个九非核心系统的可用性多容忍 到三个九。在实际工作中,你可能听到过类似的说法,只是不同级别,不同业务场景的系 统对于可用性要求是不一样的。

高可用系统的设计思路

一个成熟系统的可用性需要从系统设计系统运维两方面来做保障,两者共同作用,缺一不 可。那么如何从这两方面入手,解决系统高可用的问题呢?

如果你是一个开发主要关注系统设计方向,如果你是一个架构师两方面都要考虑。因为up在面试福报厂的时候,说了一些运维方向的高可用,就被怼了,让我多说一点开发的,我就一脸wtf。

1、系统设计

“Design for failure”是我们做高可用系统设计时秉持的第一原则。在承担百万 QPS 的高 并发系统中,集群中机器的数量成百上千台,单机的故障是常态,几乎每一天都有发生故障 的可能。

未雨绸缪才能决胜千里。我们在做系统设计的时候,要把发生故障作为一个重要的考虑点, 预先考虑如何自动化地发现故障,发生故障之后要如何解决。当然了,除了要有未雨绸缪的 思维之外,我们还需要掌握一些具体的优化方法,比如failover(故障转移)超时控制以 及降级限流

故障转移

一般来说,发生 failover 的节点可能有两种情况:

  1. 是在完全对等的节点之间做 failover。
  2. 是在不对等的节点之间,即系统中存在主节点也存在备节点。

在对等节点之间做 failover 相对来说简单些。在这类系统中所有节点都承担读写流量,并 且节点中不保存状态,每个节点都可以作为另一个节点的镜像。在这种情况下,如果访问某 一个节点失败,那么简单地随机访问另一个节点就好了。
举个例子,Nginx 可以配置当某一个 Tomcat 出现大于 500 的请求的时候,重试请求另一 个 Tomcat 节点,就像下面这样:

在这里插入图片描述

针对不对等节点的 failover 机制会复杂很多。比方说我们有一个主节点,有多台备用节 点,这些备用节点可以是热备(同样在线提供服务的备用节点),也可以是冷备(只作为备 份使用),那么我们就需要在代码中控制如何检测主备机器是否故障,以及如何做主备切 换。

使用广泛的故障检测机制是“心跳”。你可以在客户端上定期地向主节点发送心跳包,也 可以从备份节点上定期发送心跳包。当一段时间内未收到心跳包,就可以认为主节点已经发 生故障,可以触发选主的操作。(feign负载)

选主的结果需要在多个备份节点上达成一致,所以会使用某一种分布式一致性算法,比方说 Paxos,Raft。

超时控制

复杂的高并发系统通常会有很多的系统模块组成,同时也会依赖很多的组件和服务,比如说 缓存组件,队列服务等等。它们之间的调用怕的就是延迟而非失败,因为失败通常是瞬时 的,可以通过重试的方式解决。而一旦调用某一个模块或者服务发生比较大的延迟,调用方 就会阻塞在这次调用上,它已经占用的资源得不到释放。当存在大量这种阻塞请求时,调用 方就会因为用尽资源而挂掉

比如你的远程调用客户端的默认超时时间是30s, 如果你的远程服务端出现故障,而你的客户端在故障期间接收了大量的请求,这些请求全部阻塞在了远程调用链路,导致该链路的资源无法释放,可能导致你的服务因为资源耗竭而崩溃。这是就需要控制超时时间,当超时后马上终止这次调用,防止资源被长时间占用。

那么这里就有一个问题,超时时间设置多少合适?

超时时间短了,会造成大量的超时错误,对用户体验产生影响;超时时间长了,又起不到作 用。我建议你通过收集系统之间的调用日志,统计比如说 99% 的响应时间是怎样的,然后 依据这个时间来指定超时时间。如果没有调用的日志,那么你只能按照经验值来指定超时时 间。不过,无论你使用哪种方式,超时时间都不是一成不变的,需要在后面的系统维护过程 中不断地修改。所以这里可以把超时时间设置成可以修改的配置文件值。

超时控制实际上就是不让请求一直保持,而是在经过一定时间之后让请求失败,释放资源给 接下来的请求使用。这对于用户来说是有损的,但是却是必要的,因为它牺牲了少量的请求 却保证了整体系统的可用性。而我们还有另外两种有损的方案能保证系统的高可用,它们就 是降级和限流。

降级

**降级是为了保证核心服务的稳定而牺牲非核心服务的做法。**比方说我们发一条微博会先经过 反垃圾服务检测,检测内容是否是广告,通过后才会完成诸如写数据库等逻辑。

反垃圾的检测是一个相对比较重的操作,因为涉及到非常多的策略匹配,在日常流量下虽然 会比较耗时却还能正常响应。但是当并发较高的情况下,它就有可能成为瓶颈,而且它也不 是发布微博的主体流程,所以我们可以暂时关闭反垃圾服务检测,这样就可以保证主体的流 程更加稳定。

限流

限流完全是另外一种思路,它通过对并发的请求进行限速来保护系统。
比如对于 Web 应用,我限制单机只能处理每秒 1000 次的请求,超过的部分直接返回错误 给客户端。虽然这种做法损害了用户的使用体验,但是它是在极端并发下的无奈之举,是短 暂的行为,因此是可以接受的。(Facebook常常也会应用这种策略,但是它的策略很人性化,比如它限流是1000次,如果有2000个请求,他会放行1000个请求,其余的人都会显示再试一次的提示语,让用户以为是自己的网络问题导致,用户再次刷新的时候就避免了同时触发2000次请求)

2、系统运维

我们可以从灰度发布故障演练两个方面来考虑如何提升系统的可用 性。

你应该知道,在业务平稳运行过程中,系统是很少发生故障的,90% 的故障是发生在上线 变更阶段的。比方说,你上了一个新的功能,由于设计方案的问题,数据库的慢请求数翻了 一倍,导致系统请求被拖慢而产生故障。

如果没有变更,数据库怎么会无缘无故地产生那么多的慢请求呢?因此,为了提升系统的可 用性,重视变更管理尤为重要。而除了提供必要回滚方案,以便在出现问题时快速回滚恢复 之外,另一个主要的手段就是灰度发布。

**灰度发布指的是系统的变更不是一次性地推到线上的,而是按照一定比例逐步推进的。**一般 情况下,灰度发布是以机器维度进行的。比方说,我们先在 10% 的机器上进行变更,同时 观察 Dashboard 上的系统性能指标以及错误日志。如果运行了一段时间之后系统指标比较 平稳并且没有出现大量的错误日志,那么再推动全量变更。
灰度发布给了开发和运维同学绝佳的机会,让他们能在线上流量上观察变更带来的影响,是 保证系统高可用的重要关卡。

灰度发布是在系统正常运行条件下,保证系统高可用的运维手段,那么我们如何知道发生故 障时系统的表现呢?这里就要依靠另外一个手段:故障演练

故障演练指的是对系统进行一些破坏性的手段,观察在出现局部故障时,整体的系统表现是 怎样的,从而发现系统中存在的,潜在的可用性问题。
一个复杂的高并发系统依赖了太多的组件,比方说磁盘,数据库,网卡等,这些组件随时随 地都可能会发生故障,而一旦它们发生故障,会不会如蝴蝶效应一般造成整体服务不可用 呢?我们并不知道,因此,故障演练尤为重要。

在我来看,故障演练和时下比较流行的“混沌工程”的思路如出一辙,作为混沌工程的鼻 祖,Netfix 在 2010 年推出的“Chaos Monkey”工具就是故障演练绝佳的工具。它通过 在线上系统上随机地关闭线上节点来模拟故障,让工程师可以了解,在出现此类故障时会有 什么样的影响。

当然,这一切是以你的系统可以抵御一些异常情况为前提的。如果你的系统还没有做到这一 点,那么我建议你另外搭建一套和线上部署结构一模一样的线下系统,然后在这套系统上做 故障演练,从而避免对生产系统造成影响。

高可用的一些实践方案

1、对等节点的故障转移,Nginx和服务智力框架均支持一个节点失败访问另一个节点。

2、非对等节点的故障转移,通过心跳检测并实施主备切换(比如redis的哨兵模式或者集群模式、MySQL的主从切换等)。

3、接口层面的超时设置、重试策略和幂等设计。

4、降级处理:保证核心服务,牺牲非核心服务,必要时进行熔断;或者核心链路出问题时,有备选链路。

5、限流处理:对超过系统处理能力的请求直接拒绝或者返回错误码。

6、MQ场景的消息可靠性保证,包括producer端的重试机制、broker侧的持久化、consumer端的ack机制等。

7、灰度发布,能支持按机器维度进行小流量部署,观察系统日志和业务指标,等运行平稳后再推全量。

8、监控报警:全方位的监控体系,包括最基础的CPU、内存、磁盘、网络的监控,以及Web服务器、JVM、数据库、各类中间件的监控和业务指标的监控。

9、灾备演练:类似当前的“混沌工程”,对系统进行一些破坏性手段,观察局部故障是否会引起可用性问题。

总结

本文带你了解了如何度量系统的可用性,以及在做高并发系统设计时如何来保证高可 用。

说了这么多,你可以看到从开发运维角度上来看,提升可用性的方法是不同的:

两者结合起来才能组成一套完善的高可用体系。

你还需要注意的是,提高系统的可用性有时候是以牺牲用户体验或者是牺牲系统性能为前提 的,也需要大量人力来建设相应的系统,完善机制。所以我们要把握一个度,不该做过度的 优化。就像我在文中提到的,核心系统四个九的可用性已经可以满足需求,就没有必要一味 地追求五个九甚至六个九的可用性。

的是,提高系统的可用性有时候是以牺牲用户体验或者是牺牲系统性能为前提 的,也需要大量人力来建设相应的系统,完善机制。所以我们要把握一个度,不该做过度的 优化。就像我在文中提到的,核心系统四个九的可用性已经可以满足需求,就没有必要一味 地追求五个九甚至六个九的可用性。

另外,一般的系统或者组件都是追求极致的性能的,那么有没有不追求性能,只追求极致的 可用性的呢?答案是有的。比如配置下发的系统,它只需要在其它系统启动时提供一份配置 即可,所以秒级返回也可,十秒钟也 OK,无非就是增加了其它系统的启动速度而已。但 是,它对可用性的要求是极高的,甚至会到六个九,原因是配置可以获取的慢,但是不能获 取不到。我给你举这个例子是想让你了解,可用性和性能有时候是需要做取舍的,但如何取 舍就要视不同的系统而定,不能一概而论了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值