高可用架构设计

前言

我的架构设计专栏:https://www.nowcoder.com/creation/manager/columnDetail/0ybvLm

我的java八股专栏: https://www.nowcoder.com/creation/manager/columnDetail/j8ZZk0

欢迎订阅和点赞!

一、高可用系统架构设计思想

1、 可用性和高可用概念

如何理解高可用?通常用 2 个指标来衡量:

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

故障恢复时间 MTTR:(Mean Time To Repair):表示系统发生故障后恢复的时间,这个值越小,故障对用户的影响越小。

可用性与这两者的关系:可用性(Availability)= MTBF / (MTBF + MTTR) * 100%只有故障的出现间隔越长,故障恢复的越快,整个系统的可用性才会越高

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

2. 高可用架构设计思想

高可用系统的设计,需要有一套比较科学的工程管理套路,要从产品、开发、运维、基建等全方位去考量和设计,高可用系统的设计思想包括但不限于:

● 做好研发规范,系统都是研发人员设计和编码写出来的,因此首先要对研发层面有一个规范和标准

● 做好容量规划和评估,主要是让开发人员对系统要抗住的量级有一个基本认知,方便进行合理的架构设计和演进。

● 做好服务层面的高可用,主要是负载均衡、弹性扩缩容、异步解耦、故障容错、过载保护等。

● 做好存储层面的高可用,主要是冗余备份(热备、冷备)、失效转移(确认,转移,恢复)等。

● 做好运维层面的高可用,主要是发布测试、监控告警、容灾、故障演练等。

● 做好产品层面的高可用,主要是兜底策略。

● 做好应急预案,主要是在出现问题后怎么快速恢复,不至于让我们的异常事态扩大。

二、研发规范层面

方案设计和编码规范

研发规范层面这个是大家容易忽视的一个点,但是,我们所有的设计,都是研发人员来完成的,包括从设计文档到编码到发布上线,因此,研发层面也是有一个规范流程和套路,来让我们更好的去研发和维护一个高可用的系统:

● 设计阶段

○ 规范好相关方案设计文档的模板和提纲,让团队内部保持统一

○ 方案设计后一定要进行评审,在我们团队中,新项目一定要评审,重构项目一定要评审,大的系统优化或者升级一定要评审,其他的一般研发工作量超过一周的建议要评审的。

● 编码阶段

○ 执行代码规范

■ 工程的 layout 目录结构规范,团队内部保持统一,尽量简洁

■ 遵循团队内部的代码规范,一般公司都有对应语言的规范,如果没有则参考官方的规范,代码规范可以大大减少 bug 并且提高可用性。

○ 单测覆盖率

■ 代码编写完需要有一定的单测来保证代码的健壮性,同时也能保障我们后续调整逻辑或者优化的时候可以保证代码的稳定

■ 包括增量覆盖率、全量覆盖率,具体的覆盖率要达到多少可以根据团队内部的实际情况来定,在我们团队,定的规则是 50% 的覆盖率。

○ 日志规范

■ 不要随便打日志

■ 要接入远程日志

■ 要能够分布式链路追踪

● 发布上线阶段,参考下面运维部署层面那一章节的灰度发布和接口测试相关说明

容量规划和评估

容量评估,是指我们需要评估好,我们这个系统,是为了应对一个什么体量的业务,这个业务请求量的平均值、高峰的峰值大概都在一个什么级别。如果是新系统,那么就需要根据产品和运营同学对业务有一个大体的预估,然后开发同学根据产品给的数据再进行详细的评估。如果是老系统,那么就可以根据历史数据来评估。评估的时候,要从一个整体角度来看全局的量级,然后再细化到每个子业务模块要承载的量级。

容量规划,是指我们系统在设计的时候,就要能够初步规划好我们的系统大致能够抗多少的量级,比如是十万还是百万级别的请求量,或者更多。不同的量级对应的系统架构的设计会完全不一样,尤其到了千万、亿级别的量级的时候,架构的设计会有很多的考量。当然这里需要注意的是,我们不需要一上来就设计出远超于我们当前业务真实流量的系统,要根据业务实际情况来设计。同时,容量规划还涉及到,我们系统上下游的各个模块、依赖的存储、依赖的三方服务,分别需要多少资源,需要有一个相对可以量化的数据出来。容量规划阶段,更多是要依靠自身和团队的经验,比如要了解我们的 log 的性能、redis 的性能、rpc 接口的性能、服务化框架的性能等等,然后根据各种组件的性能来综合评估自己设计的系统的整体性能情况。

容量评估和容量规划之后,我们还需要做一件事情,就是性能压测,最好是能够做到全链路压测。性能压测的目的是为了确保你的容量规划是准确的,比如我设计的这个系统,我规划的是能够抗千万级别的请求,那么实际上,真的能够抗住吗 ?这个在上线之前,首先要根据经验来判断,然后是一定要经过性能压测得出准确结论的。性能压测要关注的指标很多,但是重点要关注是两个指标,一个是 QPS、一个是响应耗时,要确保压测的结果符合预期。压测的步骤可以先分模块单独压测,最后如果情况允许,那么最好执行全链路压测。

QPS 预估(漏斗型)

QPS 预估(漏斗型),指的是一个真实的请求过来后,从接入层开始,分别经过了我们整个系统的哪些层级、哪些模块,然后每一个层级的 QPS 的量级分别有多少,从请求链路上来看,层级越往下,那么下游层级的量级应该会逐步减少的,因为每经过一个层级,都有可能会被各种条件过滤掉的一部分请求。比如说进入活动页后查看商品详情然后下单这个例子,首先进入活动页,所有的请求都会进入访问;然后只会有部分用户查询商品详情;最后查看商品详情的这些用户又只会有部分用户会下单,因此这里就会有一个漏斗,从上层模块到下层模块的量级一定是逐步减少的。

QPS 预估(漏斗型)就是需要我们按照请求的层面和模块来构建我们的预估漏斗模型,然后预估好每一个层级的量级,包括但不限于从服务、接口、分布式缓存等各个层面来预估,最后构成我们完整的 QPS 漏斗模型。

三、应用服务层面

无状态和负载均衡设计

无状态:由于服务器不需保存客户端的状态信息,可以动态地添加或减少服务器节点来应对不同的流量需求。

一般要做到系统的高可用,我们的应用服务的常规设计都是无状态的,这也就意味着,我们可以部署多个实例来提高我们系统的可用性,而这多个实例之间的流量分配,就需要依赖我们的负载均衡能力。无状态 + 负载均衡 既可以让我们的系统提高并发能力,也可以提高我们系统的可用性。

如果我们的业务服务使用的是各种微服务框架来开发的,那么大概率在这个微服务框架里面就会包含了服务发现和负载均衡的能力。这是一整套流程,包括服务注册和发现、负载均衡、健康状态检查和自动剔除。当我们的任何一个服务实例出现故障后会被自动剔除掉,当我们有新增一个服务实例后会自动添加进来提供服务。

如果我们不是使用的微服务框架来开发的,那么就需要依赖负载均衡的代理服务,比如 LVS、Nginx 来帮我们实现负载均衡。

弹性扩缩容设计

弹性扩缩容设计是应对突峰流量的非常有效的手段之一,同时也是保障我们服务可用性的必要手段。弹性扩缩容针对的是我们的无状态的应用服务而言的,因为服务是无状态的,因此可以随时根据请求量的大小来进行扩缩容,流量大就扩容来应对大量请求,流量小的时候就缩容减少资源占用。

怎么实现弹性扩缩容呢?现阶段都是云原生时代,大部分的公司都是采用容器化(K8s)部署,那么基于这个情况的话,弹性扩缩容就非常容易了,只需要配置好 K8s 的弹性条件就能自动根据 CPU 的使用率来实现。

如果不是容器化部署,是物理机部署的方式,那么要做到弹性扩缩容,必须要有一个公司内部的基础建设能力,能够在运营平台上针对服务的 CPU 或者 QPS 进行监控,如果超过一定的比例就自动扩缩容,和 K8s 的弹性原理是一样的,只是需要自行实现。

异步解耦和削峰设计(消息队列)

要想我们的系统能够高可用,那么从架构层面来说,要做到分层、分模块来设计,而分层分模块之后,那么各个模块之间,还可以进行异步处理、解耦处理。目的是为了不相互影响,通过异步和解耦可以使我们的架构大大的提升可用性。

架构层面的异步解耦的方式就是采用消息队列(比如常见的 Kafka),并且同时消息队列还有削峰的作用,这两者都可以提高我们的架构可用性:

● 异步解耦:采用消息队列之后,可以把同步的流程转换为异步的流程,消息生成者和消费者都只需要和消息队列进行交互,这样不仅做了异步处理,还讲

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

架构设计学习专栏 文章被收录于专栏

不想当架构师的后端开发工程师不是好码农! 此专栏用于存放我的架构设计学习笔记,内容一部分源于网上资料,一部分源于gpt和我自己的理解。建议喜欢本专栏的盆友尽早订阅。欢迎给本专栏的文章点赞、评论!

全部评论

相关推荐

08-27 23:31
陇东学院 Java
想来想去还是发个面经吧,给大家做个参考,已经证实被刷 KPI 了。面试问题如下:1. 介绍一下你在应用中使用了那些技术手段,例如 spring aop, linux 去做的一些优化,具体使用的是 spring 那种机制去做的?2. 你将才说到了 spring aop 和 starter,你能详细说一下 aop 是怎么实现的吗?starter 的机制是什么?spring 如何管理 bean?3. 看你的简历在网关公司实习过,你了解网关鉴权吗,如何防止 token 水平越权的?如果要你设计一下防止水平越权,你怎么设计?token 有效期过了怎么办?4. 我看你用到了 mybaties 你能说一下在我们写了 mapper 接口之后,mapper 接口是如何处理业务(数据处理和数据库链接?5. 你能说一下用到 JDK 自身的一些特性去做的项目优化吗,而不用 spring 框架做的?6. 你用没有用过 jdk 15 之后的新特性?用过那些?7. 线程池的概念,参数,拒绝策略?8. Synchronized 和 lock 的原理和对比?9. 你有没有用过 spring boot 3 元数据的配置方式,用来代替 spring.factoies.10. 你这个项目里面用到了 resttemplate,openfeign,webclient 的适配,你是怎么实现的通用适配的?11. 你们应用里面用的响应式编程多吗(webflux12. 你觉得同步请求的处理和异步请求的处理有没有什么不同,在编程方式,处理请求流程上13. 你们业务用异步编程是在什么场景,什么应用?你们用了异步编程之后,数据库是怎么做的?14. 你觉得同步和响应式模型的区别是?15. 你知道 jdk8 里面 stream 流吗,是怎么实现的,怎么工作的?16. 简历里面有前端一些技术栈?会那些?17. 你对 Vue3 里面的继承是怎么理解的,他和后端 java 的继承有什么区别?18. MVVM 的数据绑定是什么?怎么做的?19. 看你熟悉 React,你知道 Vue 和 React 的数据绑定有什么不同吗?20. ReentrantLock 的实现?21. 在应用代码层面,你是怎么防止资源竞争的?22. 你有没有使用 AI 工具,在那些方面使用了?其中 22 个题目,只有 3 个没回答上来,2个回答的比较模糊。没回答上来的是:1. stream 原理(splitIterator2. 网关水平越权(没回答上来,之后面试官:你自己设计一个,如何设计?3. 应用代码层面防止资源竞争(回答的是锁,但是面试官好像不是要听锁的回答回答模糊的是:1. mybaties 的执行流程,动态代理增强......2. Vue3 里面的继承和后端继承的区别....
查看22道真题和解析
点赞 评论 收藏
分享
4 5 评论
分享
牛客网
牛客企业服务