👉腾小云导读
在系统的开发过程中,很多开发者都为了实现系统的高可用性而发愁。本文从研发规范层面、应用服务层面、存储层面、产品层面、运维部署层面、异常应急层面这六大层面去剖析一个高可用系统的架构设计需要有哪些关键的设计和考虑。希望腾讯的经验方法,能够给广大开发者提供参考。内容较长,您可以收藏后持续阅读。
👉看目录点收藏,随时涨技术
1 高可用系统的架构设计思想
1.1 可用性和高可用概念
1.2 高可用系统设计思想
2 研发规范层面
2.1 方案设计和编码规范
2.2 容量规划和评估
2.3 QPS 预估(漏斗型)
3 应用服务层面
3.1 无状态和负载均衡设计
3.2 弹性扩缩容设计
3.3 异步解耦和削峰设计(消息队列)
3.4 故障和容错设计
3.5 过载保护设计(限流、熔断、降级)
4 存储层面
4.1 集群存储(集中式存储)
4.2 分布式存储
5 产品层面
6 运维部署层面
6.1 开发阶段-灰度发布、接口测试设计
6.2 开发阶段-监控告警设计
6.3 开发阶段-安全性、防攻击设计
6.4 部署阶段-多机房部署(容灾设计)
6.5 线上运行阶段-故障演练(混沌实验)
6.6 线上运行阶段-接口拨测系列设计
7 异常应急层面
01、高可用系统的架构设计思想
1.1 可用性和高可用概念
可用性是一个可以量化的指标,是指在某个考察时间,系统能够正常运行的概率或时间占有率期望值。行业内一般用几个 9 表示可用性指标,对应用的可用性程度一般衡量标准有三个 9 到五个 9。一般我们的系统至少要到 4 个 9(99.99%)的可用性才能谈得上高可用。
高可用 High Availability 的定义(From 维基百科):
高可用是 IT 术语,指系统无中断地执行其功能的能力,代表系统的可用性程度,是进行系统设计时的准则之一。服务不可能 100% 可用,因此要提高我们的高可用,就要尽最大可能的去增加我们服务的可用性,提高可用性指标。
一句话来表述就是:高可用就是让我们的服务在任何情况下,都尽最大可能地能够对外提供服务。
2.2 高可用系统设计思想
高可用系统的架构设计,需要有一套比较科学的工程管理套路。要从产品、开发、运维、基建等全方位去考量和设计。高可用系统的架构设计思想包括但不限于:
- 做好研发规范。系统都是研发人员设计和编码写出来的,因此首先要对研发层面有一个规范和标准。
- 做好容量规划和评估。主要是让开发人员对系统要抗住的量级有一个基本认知,方便进行合理的架构设计和演进。
- 做好服务层面的高可用。主要是负载均衡、弹性扩缩容、异步解耦、故障容错、过载保护等。
- 做好存储层面的高可用。主要是冗余备份(热备,冷备)、失效转移(确认,转移,恢复)等。
- 做好运维层面的高可用。主要是发布测试、监控告警、容灾、故障演练等。
- 做好产品层面的高可用。主要是兜底策略等。
- 做好应急预案。主要是要思考在出现问题后怎样快速恢复,不至于让我们的异常事态扩大。
02、研发规范层面
2.1 方案设计和编码规范
研发规范层面是大家容易忽视的一个点。但是我们所有的设计,都是研发人员来完成的,包括从设计文档到编码再到发布上线。因此,研发层面也要有一个规范流程和套路,以让我们更好地去研发和维护一个高可用的系统:
2.2 容量规划和评估
- 容量评估:
是指需要评估好在做的这个系统是为了应对一个什么体量的业务、这个业务请求量的平均值、高峰的峰值大概都在一个什么级别。
如果是新系统,那么就需要先搜集产品和运营同事对业务的大体预估,开发者根据他们给的数据再进行详细评估。如果是老系统,那么就可以根据历史数据来评估。评估的时候,要从一个整体角度来看全局的量级,然后再细化到每个子业务模块要承载的量级。
- 容量规划:
是指系统在设计的时候,就要能够初步规划好系统大致能够维持的量级,比如是十万级还是百万级别的请求量,或者更多。不同量级对应的系统架构设计完全不一样。尤其到了千万、亿级别的量级的时候,架构设计会有更多的考量。
这里值得注意的是,不需要在一开始就设计出远超当前业务真实流量的系统,要根据业务实际情况来设计。同时,容量规划还涉及到:系统上下游的各个模块、依赖的存储、依赖的三方服务分别需要多少资源,需要有一个相对可量化的数据。容量规划阶段更多是要依靠自身和团队的经验,比如要了解系统的 log 的性能、redis 的性能、rpc 接口的性能、服务化框架的性能等等,然后根据各种组件的性能来综合评估已经设计的系统的整体性能情况。
容量评估和容量规划之后,还需要做就是性能压测。最好是能够做到全链路压测。
性能压测的目的是确保系统的容量规划是否准确。假设设计的这个系统,规划的是能够抗千万级别的请求。那么实际上,真的能够抗住吗 ?在上线之前首先要根据经验来判断,其次是一定要经过性能压测得出准确结论。性能压测要关注的指标很多,但是重点要关注的是两个指标:一个是 QPS,一个是响应耗时要确保压测的结果符合预期。
压测的步骤:可以先分模块单独压测。最后如果情况允许,那么最好执行全链路压测。
2.3 QPS 预估(漏斗型)
QPS 预估(漏斗型)指的是:一个真实的请求过来后,从接入层开始分别经过了整个系统的哪些层级、哪些模块,每一个层级的 QPS 的量级分别有多少。
从请求链路上来看,层级越往下,下游层级的量级就会越少。因为每经过一个层级,都有可能会被各种条件过滤掉一部分请求。例如进入活动页后查看商品详情然后下单这个例子,首先进入活动页,所有的请求都会进入访问。然后只会有部分用户查询商品详情。最后查看商品详情的这些用户又只会有部分用户会下单。这里就会有一个漏斗,所以从上层模块到下层模块的量级一定是逐步减少的。
QPS 预估(漏斗型)需要开发者按照请求的层面和模块,来构建预估漏斗模型,然后预估好每一个层级的量级。包括但不限于从服务、接口、分布式缓存等各个层面来预估,最后构成完整的 QPS 漏斗模型。
03、应用服务层面
3.1 无状态和负载均衡设计
要做到系统的高可用,一般应用服务的常规设计都是无状态的。这也就意味着,开发者可以部署多个实例来提高系统的可用性。而这多个实例之间的流量分配,就需要依赖系统的负载均衡能力。「无状态 + 负载均衡」既可以让系统提高并发能力,也可以提高系统的可用性。
如果开发者的业务服务使用的是各种微服务框架,那么大概率在这个微服务框架里面就包含了服务发现和负载均衡的能力。这一整套流程包括:服务注册和发现、负载均衡、健康状态检查和自动剔除。当系统的任何一个服务实例出现故障后,它会被自动剔除掉。当系统有新增一个服务实例后,它会被会自动添加进来提供服务。
如果大家不是使用的微服务框架来开发的,那么就需要依赖负载均衡的代理服务,例如 LVS、Nginx 来帮系统实现负载均衡。当然,腾讯云的 CLB 负载均衡也支持亿级连接和千万级并发,各位感兴趣的话可自行搜索了解。
3.2 弹性扩缩容设计
弹性扩缩容设计是应对突峰流量的非常有效的手段之一,同时也是保障系统服务可用性的必要手段。弹性扩缩容针对的是系统无状态的应用服务而言的。服务是无状态的,因此可以随时根据请求量的大小来进行扩缩容,流量大就扩容来应对大量请求,流量小的时候就缩容减少资源占用。
怎么实现弹性扩缩容呢? 现阶段都是云原生时代,大部分的公司都是采用容器化(K8s)部署,那么基于这个情况的话,弹性扩缩容就非常容易了,只需要配置好 K8s 的弹性条件就能自动根据 CPU 的使用率来实现。
如果不是容器化部署,是物理机部署的方式,那么要做到弹性扩缩容,必须要有一个公司内部的基础建设能力、能够在运营平台上针对服务的 CPU 或者 QPS 进行监控。如果超过一定的比例就自动扩缩容,就和 K8s 的弹性原理是一样的,只是需要自行实现。
3.3 异步解耦和削峰设计(消息队列)
要想系统能够高可用? 从架构层面来说,要做到分层、分模块来设计。而分层分模块之后各个模块之间,还可以进行异步处理、解耦处理。目的是为了不相互影响,通过异步和解耦可以使系统的架构大大的提升可用性。
架构层面的异步解耦方式就是采用消息队列(比如常见的 Kafka),并且同时消息队列还有削峰的作用,这两者都可以提高系统的架构可用性:
采用消息队列之后,可以把同步的流程转换为异步的流程,消息生成者和消费者都只需要和消息队列进行交互。这样不仅做了异步处理,还将消息生成者和消费者进行了隔离。
3.4 故障和容错设计
任何服务,一定会存在失败的情况,不可能有 100% 的可用性。服务在线上运行过程中,总会遇到各种各样意想不到的问题会让服务出现状况,因此业界来评价可用性 SLA 都是说多少个 9,例如 4 个 9(99.99%)的可用性。
为此,一般设计建议遵循「design for failure」的设计原则,设计出一套可容错的系统。需要做到尽早返回、自动修复,细节如下:
3.5 过载保护设计(限流、熔断、降级)
系统无法高可用的一个重要原因就在于:系统经常会有突发的流量到来,导致服务超载运行。这个时候首先要做的是快速扩容,并且开发者事先就要预留好一定的冗余。另外一个情况下,就算扩容了,但是还是会超载。例如超过了下游依赖的存储的最大容量、或者超过了下游依赖的三方服务的最大容量。
那么这个时候,系统就需要执行过载保护策略了,主要包括限流、熔断、降级,过载保护是为了保证服务部分可用,不至于导致整个服务完全不可用。
熔断和降级这两个策略虽有些相似,字面的意思都是要快速拒绝请求。但是却是两个维度的设计:降级的目的是应对系统自身的故障,而熔断的目的是应对系统依赖的外部服务故障。
04、存储层面
当前的互联网时代,应用服务基本都是无状态的。因此应用服务的高可用相对来说会比较简单。但是数据存储的高可用相对来说,会复杂很多。因为数据是有状态的,那具体开发者要怎样保障数据存储的高可用。下文一起来分析下。
存储层面的高可用方案本质是通过数据的冗余来实现,将数据复制到多个存储介质里面,可以有效的避免数据丢失,同时还可以提高并发能力。因为数据是有状态的,这里会比服务的高可用要复杂很多。
常见的解决存储高可用的方案有两种:集群存储和分布式存储。业界大多是围绕这些来构建,或者是做相关衍生和扩展。下面展开讲解。
4.1 集群存储(集中式存储)
集群存储是指由若干个「通用存储设备」组成的用于存储的集群。组成集群存储的每个存储系统的性能和容量均可通过「集群」的方式得以叠加和扩展。
集群存储适合业务存储量规模一般的场景,常规的业务数据存储一般都是集群存储方式就足够了。现在一般业务数据存储的使用默认都是集群方式。比如 Redis、MySQL 等存储类型。一般中大型互联网公司默认是集群存储的方式。
集群存储就是常说的「 1 主多备」或者「 1 主多从」的架构。写数据通过主机,读数据一般通过从机。集群存储主要需要考虑如下几个问题:
4.2 分布式存储
分布式是指将不同的业务分布在不同的节点。分布式中的每一个节点,都可以做集群。
「分布式存储系统」是将数据分散存储在多台独立的设备上。传统的网络存储系统采用集中的存储服务器存放所有数据,存储服务器成为系统性能的瓶颈,也是可靠性和安全性的焦点,不能满足大规模存储应用的需要。
分布式网络存储系统采用可扩展的系统结构,利用多台存储服务器分担存储负荷,利用位置服务器定位存储信息。它不但提高了系统的可靠性、可用性和存取效率,还易于扩展。
分布式存储适合非常大规模的数据存储,业务数据量巨大的场景可以采用这种方式。常见的分布式存储比如 COS、GooseFS、Hadoop(HDFS)、HBase、Elasticsearch 等。
05、产品层面
产品层面的高可用架构解决方案,基本上就是指兜底产品策略。降级/限流的策略,更多的是从后端的业务服务和架构上的设计来考虑相关解决方案。这里说的兜底策略也可叫做「柔性降级策略」,更多的则是通过产品层面上来考虑。下面举几个例子:
06、运维部署层面
6.1 开发阶段-灰度发布、接口测试设计
灰度发布、接口测试、接口拨测系列设计包括但不限于:
- 灰度发布:
服务发布上线的时候,要有一个灰度的过程。先灰度 1-2 个服务实例,然后逐步放量观察。如果一切 ok,再逐步灰度,直到所有实例发布完毕。
- 接口测试:
每次服务发布上线的时候,服务提供的各种接口,都要有接口测试用例。接口测试用例测试通过后,服务才能发布上线。这样目的是为了查看系统对外提供的接口是否能够正常运行,避免服务发布后才发现有问题。
灰度发布和接口测试,一般在大公司里面会有相关的 DevOps 流程来保证。
6.2 开发阶段-监控告警设计
监控告警的设计,对部分大公司来说不是问题。因为一定会有一些比较专门的人去做这种基础能力的建设,会有对应的配套系统,业务开发者只需要配置或使用即可。
那如果公司内部没有相关基础建设,就需要开发者分别来接入对应的系统,或者直接接入一些指标、链路、日志、事件等多数据支持、更加一体化的监控平台,比如腾讯云可观测平台。
6.3 开发阶段-安全性、防攻击设计
安全性、防攻击设计的目的是为了防刷、防黑产、防黑客,避免被外部恶意攻击。一般有两个策略:
在公司级别的流量入口做好统一的防刷和鉴权的能力,例如在统一接入层做好封装。
在业务服务内部,做好相关的业务鉴权,比如登录态信息、例如增加业务鉴权的逻辑。
6.4 部署阶段-多机房部署(容灾设计)
一般的高可用策略,都是针对一个机房内的服务层面来设计的,但是如果整个机房都不可用了,例如地震、火灾、光纤挖断等情况怎么办?这就需要系统的服务和存储能够进行容灾了。容灾的常见方案就是多机房部署。
条件不允许的情况下,保证多机房部署业务服务就可以了。
6.5 线上运行阶段-故障演练(混沌实验)
故障演练在大公司是一个常见的手段。在业界,Netflix 早在 2010 年就构建了混沌实验工具 Chaos Monkey。混沌实验工程对于提升复杂分布式系统的健壮性和可靠性发挥了重要作用。
简单的故障演练就是模拟机房断电、断网、服务挂掉等场景,然后看整个系统运行是否正常。系统就要参考混沌实验工程来进行详细的规划和设计,这个是一个相对较大的工程、效果较好,但是需要有大量人力去开发这种基础建设。
6.6 线上运行阶段-接口拨测系列设计
接口拨测和巡检类似,就是服务上线后,每隔一个固定时间(比如 5s)调用后端的各种接口,如果接口异常则进行告警。
针对接口拨测,一般也会有相关配套设施来提供相关的能力去实现。如果没有提供,那么开发者可以写一个接口拨测(巡检)的服务,定期去调用重要的接口。
07、异常应急层面
即使前面做了很多保障,也不一定招架住线上的各种异常情况。如果真出问题让系统的服务异常、无法提供服务,开发者还有最后一根救命稻草——那就是应急预案,将服务异常的损失降低到最小。
应急预案是需要开发者事先规划好,业务系统在各个层级出现问题后第一时间怎么恢复,并制定好相关规则和流程。当出现异常状况后可以按照既有的流程去执行。这样避免出现问题后手忙脚乱导致事态扩大。
最后,我们整理出本文的思维导图如上,供各位参考。总体来说,我们从研发规范层面、应用服务层面、存储层面、产品层面、运维部署层面、异常应急层面这六大层面,剖析了一个高可用系统的架构设计需要有哪些关键的设计和考虑。
以上便是本次分享的全部内容,如果您觉得内容有用,欢迎点赞、收藏,把内容分享给更多开发者。
-End-
原创作者|吴德宝
技术责编|吴德宝
腾小云福利来也💐
扫码一键领取 「腾讯云开发者-春季限定红包封面」
最近微信改版啦,有粉丝反馈收不到小云的文章🥹。
请关注「腾讯云开发者」并点亮星标,
周一三晚8点 和小云一起涨(领)技(福)术(利)!
你可能感兴趣的腾讯工程师作品
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。