从哪些方面去提高系统的高可用?

从哪些方面去提高系统的高可用?

1. 什么是高可用

可用性是一个可以量化的指标,计算的公式在维基百科中是这样描述的:根据系统损害、无法使用的时间,以及由无法运作恢复到可运作状况的时间,与系统总运作时间的比较。行业内一般用几个9表示可用性指标,对应用的可用性程度一般衡量标准有三个9到五个9;一般我们的系统至少要到 4 个 9(99.99%)的可用性才能谈得上高可用。

高可用(High Availability)的定义:(From 维基百科)是 IT 术语,指系统无中断地执行其功能的能力,代表系统的可用性程度,是进行系统设计时的准则之一。服务不可能 100% 可用,因此要提高我们的高可用设计,就要尽最大可能的去增加我们服务的可用性,提高可用性指标。

一句话来表述就是:高可用就是让我们的服务在任何情况下都尽最大可能能够对外提供服务。

2.如何提高系统可用性

从三个大的维度入手:

  • 开发
  • 部署
  • 运维

3. 开发

3.1. 首先技术架构方案选型很重要,切记避免过度设计。

比如我们常说的单体应用架构和微服务架构,两种架构单纯来对比,单体应用架构的可用率要比微服务架构高的。因为多服务之间的依赖一定会降低系统的可用率,比如一个依赖 10 个微服务的对外接口,假设每个服务的可用率是 99%,那么这个接口对外提供服务的整体可用率就直接降到了 90.4%,这中间还要考虑到服务之间的网络延迟,数据一致性的问题。

还有例子就是中间件选择,比如一个缓存业务场景,我可以用内存缓存,也可以使用 redis 分布式缓存,那么使用哪个呢?使用内存缓存系统可用率会高,因为如果引来 redis,系统的可用率又得乘以一个 redis 的可用率。当然如果我们的业务场景必须使用 redis,那么也是完全可以的,但这里切记系统的过度设计,也是设计复杂的系统,也需要更多的高可用相关的保证,所付出的资源代价和运维代价也是几何增长。

3.2. 其次就是代码质量。

其实这个可能是很多人忽略的一点,因为很多人更喜欢高谈阔论分布式,集群,压测,故障演练等等,但在我看来,一个代码开发质量的好坏,或者说一个程序员对代码的掌控力,对系统可用性起到至关重要的作用。

以下举几个代码维度的例子。第一个就是异常处理。一个代码质量的好坏,要看他对异常处理能力,一个本科生的课程设计代码,可能都是主业务逻辑,一条路写到黑,不考虑任何异常情况,

而一个毕业几年的程序员,经历过线上业务的拷打,可能会用在代码里找到很多的 try-catch,用于捕捉各种不确定逻辑,而一个资深程序员,反而他的代码里你看不到任何 try-catch, 因为他全部用 AOP 的方式实现了异常的捕捉。

这就是代码维度的考量,一个优秀的代码,一定是防御式编程,同时还会配合单元测试等。

第二个讲述一个什么是对代码的掌控力。在大厂里,你更多场景是接手别人的老代码。想必所有程序员都深有体会,接手别人的老代码是一件极其痛苦的经历,尤其是别人写了一半的代码。

老话前人种树后人乘凉,但在程序员圈,前人种树,后人只能凉凉了….. 调侃归调侃,但有些事情需要面对,前期你需要对业务场景和代码逻辑进行抽丝剥茧的梳理,这个很重要。

如果你无法对老代码进行充分熟悉,那么你就不敢去改写和重构它,如果在不熟悉的前提下贸然修改代码或者配置,然后上线,那么很大几率会带来线上系统问题,影响系统可用率。

换一个角度来说,我们写的代码未来也可能交接给别人,如何不让别人痛苦,也是我们的责任。所以合理使用设计模式,遵循代码规范,书写代码架构和设计文档,这些也是很重要的一点,他的重要可能会关乎系统未来的可用率。

具体措施:

  1. 执行代码规范
    • 工程的 layout 目录结构规范,团队内部保持统一,尽量简洁
    • 遵循团队内部的代码规范,一般公司都有对应语言的规范,如果没有则参考官方的规范,代码规范可以大大减少 bug 并且提高可用性。
  2. 单测覆盖率
    • 代码编写完需要有一定的单测来保证代码的健壮性,同时也能保障我们后续调整逻辑或者优化的时候可以保证代码的稳定
    • 包括增量覆盖率、全量覆盖率,具体的覆盖率要达到多少可以根据团队内部的实际情况来定。
  3. 日志规范
    • 不要随便打日志
    • 要接入远程日志
    • 要能够分布式链路追踪

提高代码质量的工具:

  • sonarqube :保证你写出更安全更干净的代码。
  • Alibaba 开源的 Java 诊断工具 Arthas 也是很不错的选择。
  • IDEA 自带的代码分析等工具进行代码扫描也是非常非常棒的。
3.3 服务保护设计(限流、熔断、降级)

系统无法高可用的另一个重要原因就在于,我们的系统经常会有突发的流量过来,导致我们的服务超载运行,这个时候,首先要做的当然是快速扩容,并且我们事先就要预留好一定的冗余。另外一个情况下,就算我们扩容了,但是还是会超载,比如超过了下游依赖的存储的最大容量、或者超过了下游依赖的三方服务的最大容量。那么这个时候,我们就需要执行我们的过载保护策略了,主要包括限流、熔断、降级,过载保护是为了保证服务部分可用从而不至于整个服务完全不可用。

  • 限流。限流是指对进入系统的请求进行限流处理,如果请求量超过了我们系统最大处理能力或者超过了我们指定的处理能力,那么直接拒绝请求,通过这种丢弃部分请求的方式可以保证整个系统有一定的可用性,从而不至于让整个系统完全不可用。怎么判别超过最大处理能力呢?一般就是针对 QPS 来判别,如果 QPS 超过阈值,那么就直接拒绝请求。限流有很多细节的策略,比如针对接口限流、针对服务限流、针对用户限流。

  • 熔断。熔断,断路(开路)的价值在于限制故障影响范围。我们希望控制、减少或中断和故障系统之间的通信,从而降低故障系统的负载,有利于系统的恢复。一般我们的服务都会有很多下游依赖,如果下游依赖的服务出现问题,比如开始超时甚至响应非常慢的情况下,如果我们不做任何处理,那么会导致我们的整个请求都被卡住从而超时,那么我们的业务服务对外就无法提供任何正常的功能了。为此,熔断策略就可以解决这个问题,熔断就是当我们依赖的下游服务出现问题的时候,可以快速对其进行熔断(不发起请求),这样我们的业务服务至少可以提供部分功能。熔断的设计至少需要包括 熔断请求判断机制算法、熔断恢复、熔断告警 三部分

  • 降级。降级是指我们划分好系统的核心功能和非核心功能,然后当我们的系统超过最大处理能力之后,直接关闭掉非核心的功能,从而包装核心功能的可用。关闭掉非核心的功能后可以使我们的系统释放部分资源,从而可以有资源来处理核心功能。熔断和降级这两个策略,看着比较像,字面的意思上来看都是要快速拒绝掉请求。但是他们是两个维度的设计,降级的目的是应对系统自身的故障,而熔断的目的是应对我们系统依赖的外部服务故障的情况。

4. 部署

4.1 冗余和备份

我们首先考虑的是冗余性和备份设计,这个可能是大家已经很熟悉的情况了,我们可以通过集群的方式,多个服务器、磁盘或者网络接口来减少故障点的数量。

说到集群,根据实现方式和目的不同,我帮大家梳理一下集中集群类型:

  1. 高可用集群。有多个独立服务器组成的系统,旨在提高系统可用性,当主节点出现故障时,通过失败转移(Failover)让备用节点自动接管服务。

这个我们常见的有 zookeeper 集群,etcd 集群等等,这类集群是基于共识算法实现的, 通过选举的方式,来保证当主节点故障时,可以有自动备份节点自动接管。

  1. 负载均衡集群。在负载均衡系统中,流量被分散到多个服务器中,每个服务器都独立地处理请求。当一个服务器负载过高或出现故障时,请求会自动被转移到其他可用的服务器上,从而保证系统的可用性和性能。

负载均衡可以在多个层面上实现,包括应用层、传输层和网络层。

在应用层负载均衡中,负载均衡器通常通过 HTTP 代理来分发请求,并根据请求的特定属性(例如 URL 或 Cookie)进行路由。

在传输层负载均衡中,负载均衡器通常在传输层(例如 TCP 或 UDP)上运行,并根据端口号或其他特定协议进行路由。

在网络层负载均衡中,负载均衡器通常是一个独立的网络设备,用于在不同的服务器之间分发网络流量。3. 数据库集群。这里的数据库可以理解为广义数据库,就是数据的存储媒介。对于数据库的的集群实现方式,

分为如下几个:主从复制,复制集,分区。

关于这几种实现方案,这里可以 elasticsearch 举例说明。ES 有分片和副本的概念,所谓的分片,就是将数据水平划分到多个节点,每个节点存储部分数据,当查询数据时,需要在多个节点上进行查询,最后将结果合并。分区可以实现数据的高可用性和可扩展性,但需要考虑数据一致性问题。同时 ES 的每个分片都可以配置多个副本,副本跟主从复制类似,或者说更像一个集群内的高可用子集,允许多个副本实例同时存在,并支持自动故障转移和成员选举,保证了数据的高可用性和负载均衡。

此外,对于集群方案来说,还要额外考虑多机房部署问题,异地多活。

换句话说,我所有服务实例,不能放在一个篮子里,因为网络的抖动和不稳定性,对系统可用性来说是很大的威胁。

4.2. 发布检测

第二个关键点是发布检测。有统计数据表明,我们大部分的稳定性问题来源于系统变更,也就是系统的发布上线。

5. 运维

5.1 系统全链路观测和监控

一般在监控系统这方面的开源解决方案包括但不限于这些:

  • ELK (Elasticsearch、Logstash、Kibana) 日志收集和分析 我们的日志记录不能都本地存储,因为微服务化后,日志散落在很多机器上,因此必须要有一个远程日志记录的系统,ELK 是不二人选

  • Prometheus 监控收集 可以监控各种系统层面的指标,包括自定义的一些业务指标

  • OpenTracing 分布式全链路追踪 一个请求的上下游这么多服务,怎么能够把一个请求的上下游全部串起来,那么就要依靠 OpenTracing,可以把一个请求下的所有链路都串起来并且有详细的记录

  • OpenTelemetry 可观测系统标准 最新的标准,大一统,集合了跟踪数据(Traces),指标数据(Metrics),日志数据(Logs)来观测分布式系统状态的能力 我们会依托开源系统进行自建或者扩展,甚至直接使用都行,然后我们的监控的指标一般会包括:

  • 基础设施层的监控:主要是针对网络、交换机、路由器等低层基础设备,这些设备如果出现问题,那么依托其运行的业务服务肯定就无法稳定的提供服务,我们常见的核心监控指标包括网络流量(入和出)、网络丢包情况、网络连接数等。

  • 操作系统层的监控:这里需要包含物理机和容器。常见的核心指标监控包括 CPU 使用率、内存占用率、磁盘 IO 和网络带宽等。

  • 应用服务层的监控:这里的指标会比较多,核心的比如主调请求量、被调请求量、接口成功率、接口失败率、响应时间(平均值、P99、P95 等)等。

  • 业务内部的自定义监控:每个业务服务自己的一些自定义的监控指标。比如电商系统这里的:浏览、支付、发货等各种情况的业务指标

  • 端用户层的监控:前面的监控更多的都是内部系统层面的,但是用户真正访问到页面,中间还有外网的情况,用户真正获取到数据的耗时、打开页面的耗时等这些信息也是非常重要的,但是这个一般就是需要客户端或者前端去进行统计了。

5.2 告警系统

这些系统接入完了之后,还只是做到监控和统计,当出现问题的时候,还需要进行实时告警,因此还要有一个实时告警系统,如果没有实时报警,系统运行异常后我们就无法快速感知,这样就无法快速处理,就会给我们的业务带来重大故障和灾难。告警设计需要包括:

  • 实时性:实现秒级监控;
  • 全面性:覆盖所有系统业务;
  • 实用性:预警分为多个级别,监控人员可以方便实用地根据预警严重程度做出精确的决策;
  • 多样性:预警方式提供推拉模式,包括短信,邮件,可视化界面,方便监控人员及时发现问题

6. 总结

高可用系统的设计,需要有一套比较科学的工程管理套路,要从开发、部署、运维,甚至产品和业务等全方位去考量和设计,是一个综合性考虑的事情。

原文始发于微信公众号(夏壹分享):从哪些方面去提高系统的高可用?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/155064.html

(1)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!