在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,遇到很多很重要的面试题:
请设计一个高可用性的软件架构,说明设计思路
最近有小伙伴在面试网易,又遇到了相关的面试题。小伙伴懵了,因为没有遇到过,所以支支吾吾的说了几句,面试官不满意,面试挂了。
所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。
当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V168版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。
《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请到文末公号【技术自由圈】获取
高可用,英文单词High Availability,缩写HA,它是分布式系统架构设计中一个重要的度量。
业界通常用多个9来衡量系统的可用性,如下表:
既然有可用率,有一定会存在不可用的情况。
不可用一般分为有计划的和无计划的,有计划的如日常维护、系统升级等,无计划的如设备故障、突发断电等。
我们对不可用的问题作如下分类:
设备故障:机房断电、硬盘损坏、交换机故障。
网络故障:网络带宽拥堵、网络连接中断。
安全问题:利用系统漏洞进行网络攻击。
性能问题:CPU利用率太高、内存不足、磁盘IO过载、数据库慢SQL。
升级维护:由于业务变更或技术改进而引起的系统升级。
系统问题:分布式系统中存在服务的依赖而导致数据的不一致性,或是核心服务出现异常。
云平台崩溃: 2023-11月左右,互联网P0级(宕机几个小时)故障频发:语雀一个月前崩了,接着阿里云崩,阿里云崩完、滴滴崩…而且都是宕机几个小时,影响面广,例如由于滴滴平台不能提供服务。 这些事故都是底层基础架构崩溃,比如云平台崩溃导致,问题非常难定
机房宕机:2023 年6 月 5 日,唯品会发布关于 329 机房宕机故障处理公告。官方在公告中称,南沙机房重大故障影响时间持续 12 个小时,导致公司业绩损失超亿元,影响客户达 800 多万。公司让对应部门的直接管理者承担此次事故责任,基础平台部负责人予以免职处理。
其他问题: 其他的引发线上故障的问题。
如何体系化、系统化、彻底化的解决 HA 问题。
在尼恩的 经典文章中, 一张图总结架构设计的40个黄金法则 ,给大家介绍了架构的本质:
典型架构分层设计如下:按照功能处理顺序划分应用,这是面向业务深度的划分。
每个公司的架构分层可能不一样,但是目的都是为了统一架构术语,方便团队内部沟通。
接入层:主要流量入口,经过简单
应用层:直接对外提供产品功能,例如网站、API接口等。应用层不包含复杂的业务逻辑,只做呈现和转换。
服务层:根据业务领域每个子域单独一个服务,分而治之。
数据层:数据库和NoSQL,文件存储等。
和 高并发/大数据的架构设计一样, HA 一般是分层进行, 有关 高并发/大数据的架构设计, 具体请参见尼恩的另一篇硬核文章:
阿里面试:设计一个大并发、大数据的系统架构,说说设计思路
HA 可以的架构设计 从下面的5大层来建设和分析:
主要流量入口
负责具体业务和视图展示;
网站首页、用户中心、商品中心、购物车、红包业务、活动中心等,
根据业务领域每个子域单独一个服务,分而治之。
服务层为应用层提供服务支持; 比如:订单服务、用户管理服务、红包服务、商品服务等
这个是我们重点要关注的架构设计,架构设计不合理,就很难抗住高并发,主要包括各种架构和模块的设计。
数据库和NoSQL,文件存储等。
关系数据库、nosql数据库等,提供数据存储查询服务。
这个是最基础的依赖,主要是一些服务的部署。
基础设施层一般包含了服务器、中间件、部署方式等等。
接入层 总的策略:动静分离,分而治之
接入层的HA架构方案,包括:
DNS高可用 应对措施如下:
LVS 高可用 + Nginx 高可用, 可以参见尼恩之前的文章:
10Wqps网关接入层,LVS+Keepalived(DR模式)如何搭建?
主要策略:采用keepalive 保证 nginx、lvs 的高可用避免单点瓶颈
原则1、可以水平扩展:
首先通过业务解耦、技术解耦, 把大单体架构解耦为 微服务架构。
然后对后端微服务,通过接入层的负载均衡,实现故障自动转移。
原则2、无状态设计:
无状态的系统更利于水平扩展,更利于做负载均衡。
状态是系统的吞吐量、易用性、可用性、性能和可扩展性的大敌,要尽最大可能避免。
原则3、监控预警(可监控):
至少包括三个维度的监控预警: Logging(日志) 的监控 、Tracing(调用链)监控、Metrics(指标)监控。
原则4、灰度发布(可灰度):
结合接入层设计A/B 功能,实现灰度发布,比如按ip,请求参数等分发流量。
原则5、回滚设计(可回滚) :
确保系统可以向后兼容,如果应用服务上线后出现bug,可以紧急回滚。
可以水平扩展 的前提,就是先业务解耦
对一个复杂的业务,需要分割成不同的模块单元,分而治之
一个大的问题域,需要分解为很多小的问题域,分而治之
就是是微服务划分、微服务架构
微服务架构解决大单体架构的的很多问题,比如扩展性、弹性伸缩能力、小规模团队的敏捷开发等等。
如何进行微服务架构,如何划分微服务:
如何进行业务解耦,如何划分微服务?
在实操过程中, 建议使用DDD的建模方法进行建模。
具体请参见尼恩的系列文章
《字节面试:微服务一定要DDD,为什么?TDD和DDD 有何关系?》
《美团面试:微服务如何拆分?原则是什么?》
横向扩展设计,包括:应用集群、服务集群
应对高并发系统,单节点模式都不可能搞定,因此都需要搭建应用集群、服务集群,
常见的微服务Provider的自动伸缩策略有以下两种:
1)通过Kubernetes HPA组件实现自动伸缩。
2)通过微服务Provider自动伸缩伺服组件实现自动伸缩。
具体请参见尼恩的卷3:
服务层冗余设计最主要原则:服务分级管理
不同的服务,可用性要求不一样,我们需要先这些服务做分级。
或者说:不同的链路,可用性要求不一样,我们需要先这些链路做分级。 有些是黄金链路, 有的是非核链路。
1、各级服务的HA部署原则:
黄金链路上的核心服务:进行链路隔离, 独立服务器,且N+1部署。
非核链路上的普通服务:集中部署,可以共享服务器部署。
2、各级服务HA上线发布原则:
核黄金链路上的核心服务:晚上12点上线。
非核链路上的普通服务:随时可上线
原则3、监控预警(可监控):
至少包括三个维度的监控预警: Logging(日志) 的监控 、Tracing(调用链)监控、Metrics(指标)监控。
服务要能接入 elk、 Skywalking 、metric 三大监控底座
有关elk的原理和实操, 请参见尼恩的
- 《视频第14章:横扫全网,elasticsearch底层原理与高可用架构实操,40岁老架构师细致解读,处处透着原理和精髓》
- 《视频第23章:100W级别QPS日志平台实操》
Skywalking原理和实操 请参考 尼恩的 《视频第24章:资深架构必备,彻底穿透Skywalking链路跟踪源码、JavaAgent探针技术》
metric原理和实操 请参见尼恩的《视频第33章:10Wqps 高并发 Netty网关架构与实操》
原则4、灰度发布(可灰度):
结合接入层设计A/B 功能,实现灰度发布,比如按ip,请求参数等分发流量。
请参见尼恩的 《视频第28章:穿透云原生K8S+Jenkins+SpringCloud底层原理和实操》
原则5、回滚设计(可回滚) :
确保系统可以向后兼容,如果应用服务上线后出现bug,可以紧急回滚。
请参见尼恩的 《视频第28章:穿透云原生K8S+Jenkins+SpringCloud底层原理和实操》
数据库的HA架构设计旨在提供高可用性、高性能和可扩展性的数据库服务。
数据层HA架构方案包括主从复制、自动切换和负载均衡等关键技术,以确保数据的持久性、可靠性和可用性。
一、主从复制
主从复制是一种常见的数据库同步技术,通过将主数据库的数据,实时同步到多个从数据库来实现的。
在该架构中,主库负责处理写入操作,而从库则负责处理读取操作。
主从复制的工作原理是,主库接收到写入请求后,将数据变更记录在二进制日志(Binlog)中,并将其同步到从库。从库通过读取主库的Binlog,并将其中的数据变更应用到自身的数据库中。
通过这样的复制机制,从库能够实现与主库的数据同步,从而保证了数据的一致性。
二、自动切换
自动切换是数据库HA架构设计中的另一个关键技术。
当主库发生故障或不可用时,自动切换机制能够快速将从库切换为主库,以确保系统的持续可用性。
在自动切换机制中,通常会采用心跳检测的方式来监测主库的状态。
当主库无法正常响应时,自动切换机制会立即启动,并将系统切换到可用的从库上。同时,还需要确保新的主库能够接收和处理写入请求,以保证系统的正常运行。
三、负载均衡
负载均衡是数据库HA架构设计中不可或缺的一环。
通过负载均衡技术,可以将用户的请求均匀地分发到不同的数据库节点上,以实现请求的并行处理和数据的平衡负载。
在负载均衡的实现中,通常会采用多个数据库节点来共同处理用户的请求。
通过将用户请求导入到不同的节点上,并根据节点的负载情况进行动态调整,可以实现对数据库系统的优化和提升。
四、容灾备份
容灾备份是云数据库HA架构设计中的重要环节。
通过将数据进行备份,并将备份数据存储在不同的地理位置,可以在发生灾难性故障时,尽快恢复数据库的可用性。
容灾备份通常会采用异地备份的方式,即将数据备份复制到不同的数据中心或服务器上。
这样一来,即使某个数据中心或服务器发生故障,备份数据仍然可用,从而实现了对数据库系统的灾难恢复能力。
基础设施层架构 包含:
具体,请参见尼恩的文章
网易面试:亿级用户,如何做微服务底层架构?
除了以上五层,每一层的方案, 需要一些综合性的措施和机制,包括但不限于:
在高可用服务设计章节提到,核心服务可以监控:服务流量预警、端口存活、进程占用的资源、服务接口功能逻辑是否正常,应用FGC等情况,需要一个完善监控告警机制,并在告警后,通过一定的策略进行处理,以致服务可以快速恢复。例如,监控FGC,如果在一分钟内存出现10次FGC,自动重启服务。
360度全方位的监控告警机制,包括但不限于:
网络流量监控 。
系统监控:服务器资源和网络相关监控(CPU、内存等)
日志监控:统一日志收集(各个服务)监控,跟踪(log2) 。
应用监控:端口存活、进程占用的资源,应用FGC等情况
业务监控 :服务接口功能逻辑是否正常
立体监控 监控数据采集后,除了用作系统性能评估、集群规模伸缩性预测等, 最终目标是还可以根据实时监控数据进行风险预警,并对服务器进行失效转移,自动负载调整,最大化利用集群所有机器的资源。
备份:数据备份(热备,冷备(冗余),异地)
过载保护:熔断,限流,降级
重试,防雪崩(概率很小,成本很高)
单元化+异地多活设计,既是高并发的核武器,也是高可用的核武器
在一些极端场景下,有可能所有服务器都出现故障,例如机房断电、机房火灾、地震等这些不卡抗拒因素会导致系统所有服务器都故障从而导致业务整体瘫痪,而且即使有其他地区的备份,把备份业务系统全部恢复到能够正常提供业务,花费的时间也比较长。
为了满足中心业务连续性,增强抗风险能力,多活作为一种可靠的高可用部署架构,成为各大互联网公司的首要选择。
一个服务对外的使用方可能有 A 业务、B 业务,那么如何保证 AB 业务不会相互影响,那么就是单元化(Set化)设计。
所谓单元,是指一个能完成所有业务操作的自包含集合,在这个集合中包含了所有业务所需的所有服务,以及单元的数据分片。
单元化架构就是把单元作为系统部署的基本单位,在全站所有idc机房中部署数个单元.
每个idc机房里的单元数目不定,任意一个单元都部署了系统所需的所有的服务。
任意一个单元的数据是首先拥有分片数据,但是为了切流的方便, 最终需要拥有全量数据。
传统意义上的 SOA 化(服务化)架构,服务是分层的,每层的节点数量不尽相同,上层调用下层时,随机选择节点。
单元化架构下,服务仍然是分层的,
不同的是每一层中的任意一个节点都属于且仅属于某一个单元,上层调用下层时,仅会选择本单元内的节点。
而要做到单元化,必须要满足以下要求:
业务必须是可分片的,如 淘宝按照用户分片, 饿了么按照地理位置分片
单元内的业务是自包含的,调用尽量封闭
单元化署就是把业务系统分为多个可扩展的逻辑分区,每个 SET 的逻辑分区都可以独立部署并提供服务,SET 也可以理解为 ”逻辑机房“ ,主要目的就是为了进行独立部署并且做到业务上的逻辑隔离。
关于 单元化SET 的具体例子:
微信红包用户发一个红包时,微信红包系统生成一个ID作为这个红包的唯一标识。
接下来这个红包的所有发红包、抢红包、拆红包、查询红包详情等操作,都根据这个ID关联。
红包系统根据这个红包ID,按一定的规则(如按ID尾号取模等),垂直上下切分。
切分后,一个垂直链条上的逻辑Server服务器、DB统称为一个SET。
单元化SET 部署之后,系统将所有红包请求这个巨大的洪流分散为多股小流,互不影响,分而治之。
现在稍微有点体量的公司都在做单元化,单元化的好处
1. 多AZ(可用区) 容灾、异地多活。
2. 服务器体量太大,单一IDC没有足够的机器。
3. 提升用户请求访问速度。
基础设施层一般包含了服务器、IDC、部署方式等等。
多 IDC 部署。比如服务同时在广州、上海两地部署。这个依赖我们的服务是无状态的;
其他的参考下异地多活架构等相关部署。
在接入层之上,再部署一个「路由层」(通常部署在云服务器上),自己可以配置路由规则,把用户「分流」到不同的机房内。
但这个路由规则,具体怎么定呢?有很多种实现方式,最常见的总结了 3 类:
1.按地理位置分片
非常适合与地理位置密切相关的业务,例如打车、外卖服务就非常适合这种方案。
拿外卖服务举例,你要点外卖肯定是「就近」点餐,整个业务范围相关的有商家、用户、骑手,它们都是在相同的地理位置内的。举例:北京、河北地区的用户点餐,请求只会打到北京机房,而上海、浙江地区的用户,请求则只会打到上海机房。这样的分片规则,也能避免数据冲突。
但是,上海机房和 北京机房进行数据复制, 当一个机房发生故障时,路由层把流量切换到 另一个机房。
2.按业务类型分片
假设一共有 4 个应用,北京和上海机房都部署这些应用。但应用 1、2 只在北京机房接入流量,在上海机房只是热备。应用 3、4 只在上海机房接入流量,在北京机房是热备。
这样一来,应用 1、2 的所有业务请求,只读写北京机房存储,应用 3、4 的所有请求,只会读写上海机房存储。
但是,上海机房和 北京机房进行数据复制, 当一个机房发生故障时,路由层 把流量切换到 另一个机房。
3.直接哈希分片
会根据用户 ID 计算「哈希」取模,然后从路由表中找到对应的机房,之后把请求转发到指定机房内。
举例:一共 200 个用户,根据用户 ID 计算哈希值,然后根据路由规则,把用户 1 - 100 路由到北京机房,101 - 200 用户路由到上海机房,这样,就避免了同一个用户修改同一条数据的情况发生。
但是,上海机房和 北京机房进行数据复制, 当一个机房发生故障时,路由层 把流量切换到 另一个机房。
分片的核心思路在于,让同一个用户的相关请求,只在一个机房内完成所有业务「闭环」,不再出现「跨机房」访问。正因为如此,阿里在实施这种方案时,给它起了个名字,叫做「单元化」。
异地多活方案复杂, 尼恩之前积累过一系列的问题,可供参考:
高可用包括 去掉IDC机房内部的 single of failure, 也包括 去掉 IDC机房之间的 single of failure,
去掉IDC机房内部的 single of failure,参见下面的案例
《大家都崩,美团不崩:其高可用架构,巧夺天工!》
《美团面试:ES+Redis+MySQL高可用,如何实现?》
去掉 IDC机房之间的 single of failure,主要是异地多活
《单元化、异地多活,大厂如何实现?》
《B站刚崩,唯品会又崩:亿级用户网站的架构硬伤与解决方案》
《100Wqps异地多活,得物是怎么架构的?》
以上的内容,如果大家能对答如流,如数家珍,基本上 面试官会被你 震惊到、吸引到。
最终,让面试官爱到 “不能自已、口水直流”。offer, 也就来了。
在面试之前,建议大家系统化的刷一波 5000页《尼恩Java面试宝典PDF》,里边有大量的大厂真题、面试难题、架构难题。很多小伙伴刷完后, 吊打面试官, 大厂横着走。
在刷题过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩交流。
另外,如果没有面试机会,可以找尼恩来改简历、做帮扶。
遇到职业难题,找老架构取经, 可以省去太多的折腾,省去太多的弯路。
尼恩指导了大量的小伙伴上岸,前段时间,刚指导一个40岁+被裁小伙伴,拿到了一个年薪100W的offer。
狠狠卷,实现 “offer自由” 很容易的, 前段时间一个武汉的跟着尼恩卷了2年的小伙伴, 在极度严寒/痛苦被裁的环境下, offer拿到手软, 实现真正的 “offer自由” 。
……完整版尼恩技术圣经PDF集群,请找尼恩领取
《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》PDF,请到下面公号【技术自由圈】取↓↓↓