如何设计一个高可用的分布式系统?
作者:沉默王二 发布时间:2023-03-12T21:59:59.966+0800
前置说明
一个非常考察个人能力的一个问题,基本上面资深、架构或多或少都会遇到类似的问题;
主要考察个人的整体架构设计能力、技术广度、严谨程度
通常来说,不太会强求再短短的一两个小时的面试时间内,给出一个完美的答复,一个听上去行至可行,逻辑自洽的回答,基本上就可以得到高分了; 下面的回答,算是一个抛砖引玉,给大家提供一个可以怎么去回答这种问题的思路
问题拆解
将抽象问题具体化
对于这种问题,说实话有点大,直接回答会有点虚,所以比较好的是先给自己圈定一个范围,比如设计一个面面向用户的高可用服务应用(如电商的商品体系、技术派这种社区应用);比如设计一个高可用的通用服务,如应用网关,如缓存应用,如消息推送等;再比如对cap比较敏感的注册中心;
因为不同的服务定位,需要考虑的点都不一样,在回答这个问题之前,一个非常好的方式是和面试官聊一聊,是想设计一个什么样的分布式系统,可以把上面我说到的几种情况的特点,给面试官提一下表明自己在设计一个系统的时候,除了关注通用的设计方案之外,还很关注是实际的应用场景
问题拆解
题目上说的是“如何构建一个高可用的分布式系统”,只要我们听过大名鼎鼎的CAP理论,那么再回答这个问题的时候,请务必记得,谈一下一致性的问题。
分布式系统本身也会有很多的知识点可以聊,比如最常见的如何保证一致性? 我们在回答的时候可以把分布式系统的特性简单说一下,尤其是一致性和可用性两点都抛出来,看面试官更关注哪一个方面,然后将更多的关注点放在面试官想聊的那个点上(一般来讲上面这个问题面试官大概率更关注高可用,但是你把分布式的一致性这个也抛出来,只会加分不会减分,如果他只想聊高可用,也不怕,他会给你指出来的)
然后下来进入正题,针对这个问题,怎么进行条理的回答
1. 首先聊分布式系统
紧抓分布式这个点,首先说一下自己对分布式这个词的理解
不懂的小伙伴,可以看下我之前的分享
结合上面的内容,实际举例说明
1.1 说先说个人的分布式的理解:直白来说分布式系统主要是针对之前的单节点应用,改变成多机或者单机多节点应用,最主要的就是为了解决单点问题,可以做能力扩展,负载分摊
1.2 紧抓重点:在实际设计这样的系统时,我们需要重点考虑数据一致性问题,实际上有很多保证数据一致性的手段,如cap理论,如果对c要求高,那么就牺牲a,比如参考zk的强一致性策略,使用zab协议,或者使用业内成熟的raft,paxos算法来保障(自己知道那个就说那个,别提了一个自己不了解的算法被怼懵了)
1.3 抛出其他可能遇到的问题,进行针对性方案设计,如
1.3.1 时钟不一致问题,即每个机器的时钟不一致,可能导致很多基于当前时间的业务逻辑出现问题,因此可以考虑对所有的机器使用相同的时钟源
1.3.2 资源竞争,多个节点对同一个资源的竞争导致出现业务逻辑问题如aba,我们可以考虑使用分布式锁,或者借助DB的锁来限制排他性
1.3.3 网络分区很难避免,为了避免出现这种问题,我们尽量将应用部署在同一个机房,相同的局域网内,走内网通信,但是这中方式,其实是牺牲了一定的可用性的,比如一个机房全崩,导致所有服务不可用(到这里自然就抛出了高可用的概念,然后可以转到下一个话题)
2.接下来我们再看一下高可用
高可用,从下面几个点出发找可能出现问题的点
-
单机不可靠,搞多节点
-
每个环节都可能出现问题
-
外部尤其不可靠,只要涉及到外部访问时都做好保护
接下来看一下具体的通用的回答考虑点
2.1 部署多台机器 避免出现单点故障;其次使用多机用来分流,减少单机的访问量
2.2 对于多机部署,根据实际的情况选择集群策略,比如采用DB的这种主备,主从集群方式,如Redis集群的hash路由拆分方式;比如常见业务服务的去中心集群方式,根据不同的场景来选择不同的策略
2.3 应用保活检测,实现自动的服务故障时,流量转移
2.4 负载均衡,根据实际的应用场景,分摊对应的流量;
2.5 流量打过来,做好缓存:内存缓存->分布式缓存->数据源。 一个方面是提高系统响应能力,增加tps,另一方面是减少io交互,使用性能更高,更稳定的代替其他的
2.6 尽量少引入第三方组件,外部依赖越少,稳定性越高
2.7 能少外部交互就少外部交互
2.8 与外部的交互,如果可以用异步方案就少用同步方案,设置重试策略,设置超时保护,设置降级策略
2.9 评估好自己服务的负载能力,做好熔断保护,做好背压,避免出现流量激增导致服务被打崩
2.10 做好隔离,安全容错,避免一个地方崩了导致所有的的服务崩了;
2.11 做好预警监控,第一时间发现问题,解决问题,减少不可用的时间
实例演示
最后给一个我曾经面试时遇到一个问题,让我设计一个实现日均千万量级的高可用的订单履约系统
针对这种指向明确的设计题,更好的方式当场画架构图,然后就着图给面试官讲解自己的思路(我当时就是这么干的,好处也很明显,图画出来之后,更容易让面试官了解你的思路,同时你自己对着图讲,更不容易遗漏要点,也会显得逻辑缜密、条理清晰)
首先预估服务承载能力: 1kw / 1d = 116 单/s ,一般来说瞬时的最大消费能力会大于平均值,所以我们假定按照200单/s进行设计
最开始,基于面试官对这个系统的简单的业务描述,然后我就设计了一个上面的整体架构图
整体系统架构说明
-
首先单独设计一个收单服务,做成集群方式,主要负责从上游同步订单(采用MQ的异步方式)
-
解释为什么采用MQ:首先是mq的方案,可以非常有效的进行削峰,可以让我们后续的系统按照200tps的消费能力进行设置,无需关注比如大促时,零点的瞬时单量情况;其次就是mq的方案,在我们的系统出现问题之后,进行消息回访,提高我们整体可用性 (因为履约系统不是面向C端用户,它的可用性整体更多的体现在订单是否正常履约)
-
其次就是简单介绍一下,收单服务有哪些东西,比如各种校验,就是为了提前排除不规范的数据;然后就是做一个数据模型转换,可以将不同来源的数据进行统一
-
然后再谈履约的系统(因为在当时我没做过履约业务,所以也不知道内部有哪些系统,只是根据面试官提的有各种订单状态变更这个点出发,给了一个第一版的设计,整了一个类似Storm的数据流式消费的方案)
当我将上面这个方案说完之后,我自己就意识到这个方案和高可用存在冲突,即一个服务的中断,将会影响这个链路的流转,所以可以灵活的表达一下自己对这个方案的说明,比如这个方案适用于链路清晰、每个服务节点逻辑比较轻量可控的场景;当然考虑到对高可用的设计,我们完全可以将这种串行的推进,改成异步的并发调度
然后再把上面这个改动画出来,接着给面试官分析:
-
将服务之间的串行流转,改为由统一的状态机进行调度编排,优势如下:
-
减少服务之间的直接依赖,可以有效的进行流量控制,速度调节,异常重试
-
每个服务只需关注自己的业务逻辑,它通知状态机可以是同步,也可以是异步方案,对于服务提供者而言,更好维护
-
每个服务可以根据自己的承载能力,当自己的消费能力弱时,多加机器;消费能力强时,减少机器(前面串行的方案也有这个能力); 状态机可以根据实际的情况,调整流量分配
-
实际业务会更灵活,比如某些业务场景下,服务2可以不执行;前面串行的方案相比较于后面的状态机调度方案实现上会更复杂、且不通用
-
再其次就是有些服务之间是可以并行调度的,相比于前面的串行方案,无疑消费能力更强
然后再到下面一层,数据存储,一天千万单,所以必然是分库分表,比如最常见的根据订单id进行分库分表; 其次就是考虑到实际的业务特点,也可以考虑冷热方式分库分表
高可用说明
整体架构说完之后,并没有结束,因为问题中明细提出了要高可用,所以我们需要对着这个图来谈一下怎么表明它的高可用
因为上面这个架构图,分了三层,所以我们就有从上往下进行说:
- 收单服务的高可用设计:
-
采用集群方案
-
比如为了减少不同平台的订单导致彼此相互影响,我们可以考虑将对收单服务根据订单来源进行路由区分,如将天猫的订单、打到天猫的收单服务集群;将京东的订单、打到京东的收单服务集群
-
异步拉单方案
-
不然前台的订单服务直接调用收单服务,改为mq的异步交互方式,可以有效的实现削峰,也可以做流量控制
- 履约服务
-
做服务拆分
-
根据不同的实际场景,将履约拆分成一个一个独立的服务,每个服务可以按照自己的实际消费能力,选择部署的实例个数
-
服务拆分之后,相比较于所有服务放在一起而言,可以有效的减少服务之间的彼此影响
-
服务可以放在同一个机房;然后为了提高可用性,可以在不同的机房部署一套对应的服务,比如根据大陆的都放在大陆机房;欧洲的,都放在欧洲机房
-
服务之间的调用,交由统一的状态机来完成
-
由状态机来管理订单的流转,可以根据实际的服务能力来分配调用量;比如当一个服务能力达到上限之后,可以进行限流,避免直接把服务打挂,这样可以确保每个服务都在自己的安全水位线之下运转,提高整体的可用性
-
状态机,实际在这里提供了负载均衡、流量控制、背压、重试等高可用的技术保障
-
状态机的高可用
-
状态机这种通用的服务,由专门的中间件团队维护,交由他们来保障高可用,即便真的出了问题,到时候锅也不是我的(开玩笑的语气说这种话)
-
如果状态机服务让我们自己来处理,那么必然是设计为集群调度方式,状态机与服务之间的交互也可以改成基于MQ的异步交互方式,减少服务因为调用状态机失败不断重试、导致流量放大的问题;也可以避免出现丢数据的场景
- 数据库
-
分库分表来保障高可用,主备、主从、多主多从等成熟的体系来保证可用性
-
如果mysql满足不了要求,用更牛的技术如tidb之类的才保障
- 加监控、加日志、加预警
- 在上面的所有流转地方,都加上服务监控预警、关键日志,如果真的出现问题,那就提前发现问题,排查问题和解决问题
小结
最后小结一下,关于如何设计高可用的分布式系统,非常考虑一个人的综合能力,上面写的这些,主要是为了给大家提供一个回答的思路,但是请抱着质疑的目光来阅读它,肯定会有更好、更完美的方案,如何能在短短的一两个小时的面试时间内,将自己的思考呈现在面试官眼前,这个才是最重要的点,不要过于纠结与全而美,相比于此,多锻炼一下自己的表达方式和逻辑感更为实际
前置说明
一个非常考察个人能力的一个问题,基本上面资深、架构或多或少都会遇到类似的问题;
主要考察个人的整体架构设计能力、技术广度、严谨程度
通常来说,不太会强求再短短的一两个小时的面试时间内,给出一个完美的答复,一个听上去行至可行,逻辑自洽的回答,基本上就可以得到高分了; 下面的回答,算是一个抛砖引玉,给大家提供一个可以怎么去回答这种问题的思路
问题拆解
将抽象问题具体化
对于这种问题,说实话有点大,直接回答会有点虚,所以比较好的是先给自己圈定一个范围,比如设计一个面面向用户的高可用服务应用(如电商的商品体系、技术派这种社区应用);比如设计一个高可用的通用服务,如应用网关,如缓存应用,如消息推送等;再比如对cap比较敏感的注册中心;
因为不同的服务定位,需要考虑的点都不一样,在回答这个问题之前,一个非常好的方式是和面试官聊一聊,是想设计一个什么样的分布式系统,可以把上面我说到的几种情况的特点,给面试官提一下表明自己在设计一个系统的时候,除了关注通用的设计方案之外,还很关注是实际的应用场景
问题拆解
题目上说的是“如何构建一个高可用的分布式系统”,只要我们听过大名鼎鼎的CAP理论,那么再回答这个问题的时候,请务必记得,谈一下一致性的问题。
分布式系统本身也会有很多的知识点可以聊,比如最常见的如何保证一致性? 我们在回答的时候可以把分布式系统的特性简单说一下,尤其是一致性和可用性两点都抛出来,看面试官更关注哪一个方面,然后将更多的关注点放在面试官想聊的那个点上(一般来讲上面这个问题面试官大概率更关注高可用,但是你把分布式的一致性这个也抛出来,只会加分不会减分,如果他只想聊高可用,也不怕,他会给你指出来的)
然后下来进入正题,针对这个问题,怎么进行条理的回答
1. 首先聊分布式系统
紧抓分布式这个点,首先说一下自己对分布式这个词的理解
不懂的小伙伴,可以看下我之前的分享
结合上面的内容,实际举例说明
1.1 说先说个人的分布式的理解:直白来说分布式系统主要是针对之前的单节点应用,改变成多机或者单机多节点应用,最主要的就是为了解决单点问题,可以做能力扩展,负载分摊
1.2 紧抓重点:在实际设计这样的系统时,我们需要重点考虑数据一致性问题,实际上有很多保证数据一致性的手段,如cap理论,如果对c要求高,那么就牺牲a,比如参考zk的强一致性策略,使用zab协议,或者使用业内成熟的raft,paxos算法来保障(自己知道那个就说那个,别提了一个自己不了解的算法被怼懵了)
1.3 抛出其他可能遇到的问题,进行针对性方案设计,如
1.3.1 时钟不一致问题,即每个机器的时钟不一致,可能导致很多基于当前时间的业务逻辑出现问题,因此可以考虑对所有的机器使用相同的时钟源
1.3.2 资源竞争,多个节点对同一个资源的竞争导致出现业务逻辑问题如aba,我们可以考虑使用分布式锁,或者借助DB的锁来限制排他性
1.3.3 网络分区很难避免,为了避免出现这种问题,我们尽量将应用部署在同一个机房,相同的局域网内,走内网通信,但是这中方式,其实是牺牲了一定的可用性的,比如一个机房全崩,导致所有服务不可用(到这里自然就抛出了高可用的概念,然后可以转到下一个话题)
2.接下来我们再看一下高可用
高可用,从下面几个点出发找可能出现问题的点
-
单机不可靠,搞多节点
-
每个环节都可能出现问题
-
外部尤其不可靠,只要涉及到外部访问时都做好保护
接下来看一下具体的通用的回答考虑点
2.1 部署多台机器 避免出现单点故障;其次使用多机用来分流,减少单机的访问量
2.2 对于多机部署,根据实际的情况选择集群策略,比如采用DB的这种主备,主从集群方式,如Redis集群的hash路由拆分方式;比如常见业务服务的去中心集群方式,根据不同的场景来选择不同的策略
2.3 应用保活检测,实现自动的服务故障时,流量转移
2.4 负载均衡,根据实际的应用场景,分摊对应的流量;
2.5 流量打过来,做好缓存:内存缓存->分布式缓存->数据源。 一个方面是提高系统响应能力,增加tps,另一方面是减少io交互,使用性能更高,更稳定的代替其他的
2.6 尽量少引入第三方组件,外部依赖越少,稳定性越高
2.7 能少外部交互就少外部交互
2.8 与外部的交互,如果可以用异步方案就少用同步方案,设置重试策略,设置超时保护,设置降级策略
2.9 评估好自己服务的负载能力,做好熔断保护,做好背压,避免出现流量激增导致服务被打崩
2.10 做好隔离,安全容错,避免一个地方崩了导致所有的的服务崩了;
2.11 做好预警监控,第一时间发现问题,解决问题,减少不可用的时间
实例演示
最后给一个我曾经面试时遇到一个问题,让我设计一个实现日均千万量级的高可用的订单履约系统
针对这种指向明确的设计题,更好的方式当场画架构图,然后就着图给面试官讲解自己的思路(我当时就是这么干的,好处也很明显,图画出来之后,更容易让面试官了解你的思路,同时你自己对着图讲,更不容易遗漏要点,也会显得逻辑缜密、条理清晰)
首先预估服务承载能力: 1kw / 1d = 116 单/s ,一般来说瞬时的最大消费能力会大于平均值,所以我们假定按照200单/s进行设计
最开始,基于面试官对这个系统的简单的业务描述,然后我就设计了一个上面的整体架构图
整体系统架构说明
-
首先单独设计一个收单服务,做成集群方式,主要负责从上游同步订单(采用MQ的异步方式)
-
解释为什么采用MQ:首先是mq的方案,可以非常有效的进行削峰,可以让我们后续的系统按照200tps的消费能力进行设置,无需关注比如大促时,零点的瞬时单量情况;其次就是mq的方案,在我们的系统出现问题之后,进行消息回访,提高我们整体可用性 (因为履约系统不是面向C端用户,它的可用性整体更多的体现在订单是否正常履约)
-
其次就是简单介绍一下,收单服务有哪些东西,比如各种校验,就是为了提前排除不规范的数据;然后就是做一个数据模型转换,可以将不同来源的数据进行统一
-
然后再谈履约的系统(因为在当时我没做过履约业务,所以也不知道内部有哪些系统,只是根据面试官提的有各种订单状态变更这个点出发,给了一个第一版的设计,整了一个类似Storm的数据流式消费的方案)
当我将上面这个方案说完之后,我自己就意识到这个方案和高可用存在冲突,即一个服务的中断,将会影响这个链路的流转,所以可以灵活的表达一下自己对这个方案的说明,比如这个方案适用于链路清晰、每个服务节点逻辑比较轻量可控的场景;当然考虑到对高可用的设计,我们完全可以将这种串行的推进,改成异步的并发调度
然后再把上面这个改动画出来,接着给面试官分析:
-
将服务之间的串行流转,改为由统一的状态机进行调度编排,优势如下:
-
减少服务之间的直接依赖,可以有效的进行流量控制,速度调节,异常重试
-
每个服务只需关注自己的业务逻辑,它通知状态机可以是同步,也可以是异步方案,对于服务提供者而言,更好维护
-
每个服务可以根据自己的承载能力,当自己的消费能力弱时,多加机器;消费能力强时,减少机器(前面串行的方案也有这个能力); 状态机可以根据实际的情况,调整流量分配
-
实际业务会更灵活,比如某些业务场景下,服务2可以不执行;前面串行的方案相比较于后面的状态机调度方案实现上会更复杂、且不通用
-
再其次就是有些服务之间是可以并行调度的,相比于前面的串行方案,无疑消费能力更强
然后再到下面一层,数据存储,一天千万单,所以必然是分库分表,比如最常见的根据订单id进行分库分表; 其次就是考虑到实际的业务特点,也可以考虑冷热方式分库分表
高可用说明
整体架构说完之后,并没有结束,因为问题中明细提出了要高可用,所以我们需要对着这个图来谈一下怎么表明它的高可用
因为上面这个架构图,分了三层,所以我们就有从上往下进行说:
- 收单服务的高可用设计:
-
采用集群方案
-
比如为了减少不同平台的订单导致彼此相互影响,我们可以考虑将对收单服务根据订单来源进行路由区分,如将天猫的订单、打到天猫的收单服务集群;将京东的订单、打到京东的收单服务集群
-
异步拉单方案
-
不然前台的订单服务直接调用收单服务,改为mq的异步交互方式,可以有效的实现削峰,也可以做流量控制
- 履约服务
-
做服务拆分
-
根据不同的实际场景,将履约拆分成一个一个独立的服务,每个服务可以按照自己的实际消费能力,选择部署的实例个数
-
服务拆分之后,相比较于所有服务放在一起而言,可以有效的减少服务之间的彼此影响
-
服务可以放在同一个机房;然后为了提高可用性,可以在不同的机房部署一套对应的服务,比如根据大陆的都放在大陆机房;欧洲的,都放在欧洲机房
-
服务之间的调用,交由统一的状态机来完成
-
由状态机来管理订单的流转,可以根据实际的服务能力来分配调用量;比如当一个服务能力达到上限之后,可以进行限流,避免直接把服务打挂,这样可以确保每个服务都在自己的安全水位线之下运转,提高整体的可用性
-
状态机,实际在这里提供了负载均衡、流量控制、背压、重试等高可用的技术保障
-
状态机的高可用
-
状态机这种通用的服务,由专门的中间件团队维护,交由他们来保障高可用,即便真的出了问题,到时候锅也不是我的(开玩笑的语气说这种话)
-
如果状态机服务让我们自己来处理,那么必然是设计为集群调度方式,状态机与服务之间的交互也可以改成基于MQ的异步交互方式,减少服务因为调用状态机失败不断重试、导致流量放大的问题;也可以避免出现丢数据的场景
- 数据库
-
分库分表来保障高可用,主备、主从、多主多从等成熟的体系来保证可用性
-
如果mysql满足不了要求,用更牛的技术如tidb之类的才保障
- 加监控、加日志、加预警
- 在上面的所有流转地方,都加上服务监控预警、关键日志,如果真的出现问题,那就提前发现问题,排查问题和解决问题
小结
最后小结一下,关于如何设计高可用的分布式系统,非常考虑一个人的综合能力,上面写的这些,主要是为了给大家提供一个回答的思路,但是请抱着质疑的目光来阅读它,肯定会有更好、更完美的方案,如何能在短短的一两个小时的面试时间内,将自己的思考呈现在面试官眼前,这个才是最重要的点,不要过于纠结与全而美,相比于此,多锻炼一下自己的表达方式和逻辑感更为实际
前置说明
一个非常考察个人能力的一个问题,基本上面资深、架构或多或少都会遇到类似的问题;
主要考察个人的整体架构设计能力、技术广度、严谨程度
通常来说,不太会强求再短短的一两个小时的面试时间内,给出一个完美的答复,一个听上去行至可行,逻辑自洽的回答,基本上就可以得到高分了; 下面的回答,算是一个抛砖引玉,给大家提供一个可以怎么去回答这种问题的思路
问题拆解
将抽象问题具体化
对于这种问题,说实话有点大,直接回答会有点虚,所以比较好的是先给自己圈定一个范围,比如设计一个面面向用户的高可用服务应用(如电商的商品体系、技术派这种社区应用);比如设计一个高可用的通用服务,如应用网关,如缓存应用,如消息推送等;再比如对cap比较敏感的注册中心;
因为不同的服务定位,需要考虑的点都不一样,在回答这个问题之前,一个非常好的方式是和面试官聊一聊,是想设计一个什么样的分布式系统,可以把上面我说到的几种情况的特点,给面试官提一下表明自己在设计一个系统的时候,除了关注通用的设计方案之外,还很关注是实际的应用场景
问题拆解
题目上说的是“如何构建一个高可用的分布式系统”,只要我们听过大名鼎鼎的CAP理论,那么再回答这个问题的时候,请务必记得,谈一下一致性的问题。
分布式系统本身也会有很多的知识点可以聊,比如最常见的如何保证一致性? 我们在回答的时候可以把分布式系统的特性简单说一下,尤其是一致性和可用性两点都抛出来,看面试官更关注哪一个方面,然后将更多的关注点放在面试官想聊的那个点上(一般来讲上面这个问题面试官大概率更关注高可用,但是你把分布式的一致性这个也抛出来,只会加分不会减分,如果他只想聊高可用,也不怕,他会给你指出来的)
然后下来进入正题,针对这个问题,怎么进行条理的回答
1. 首先聊分布式系统
紧抓分布式这个点,首先说一下自己对分布式这个词的理解
不懂的小伙伴,可以看下我之前的分享
结合上面的内容,实际举例说明
1.1 说先说个人的分布式的理解:直白来说分布式系统主要是针对之前的单节点应用,改变成多机或者单机多节点应用,最主要的就是为了解决单点问题,可以做能力扩展,负载分摊
1.2 紧抓重点:在实际设计这样的系统时,我们需要重点考虑数据一致性问题,实际上有很多保证数据一致性的手段,如cap理论,如果对c要求高,那么就牺牲a,比如参考zk的强一致性策略,使用zab协议,或者使用业内成熟的raft,paxos算法来保障(自己知道那个就说那个,别提了一个自己不了解的算法被怼懵了)
1.3 抛出其他可能遇到的问题,进行针对性方案设计,如
1.3.1 时钟不一致问题,即每个机器的时钟不一致,可能导致很多基于当前时间的业务逻辑出现问题,因此可以考虑对所有的机器使用相同的时钟源
1.3.2 资源竞争,多个节点对同一个资源的竞争导致出现业务逻辑问题如aba,我们可以考虑使用分布式锁,或者借助DB的锁来限制排他性
1.3.3 网络分区很难避免,为了避免出现这种问题,我们尽量将应用部署在同一个机房,相同的局域网内,走内网通信,但是这中方式,其实是牺牲了一定的可用性的,比如一个机房全崩,导致所有服务不可用(到这里自然就抛出了高可用的概念,然后可以转到下一个话题)
2.接下来我们再看一下高可用
高可用,从下面几个点出发找可能出现问题的点
-
单机不可靠,搞多节点
-
每个环节都可能出现问题
-
外部尤其不可靠,只要涉及到外部访问时都做好保护
接下来看一下具体的通用的回答考虑点
2.1 部署多台机器 避免出现单点故障;其次使用多机用来分流,减少单机的访问量
2.2 对于多机部署,根据实际的情况选择集群策略,比如采用DB的这种主备,主从集群方式,如Redis集群的hash路由拆分方式;比如常见业务服务的去中心集群方式,根据不同的场景来选择不同的策略
2.3 应用保活检测,实现自动的服务故障时,流量转移
2.4 负载均衡,根据实际的应用场景,分摊对应的流量;
2.5 流量打过来,做好缓存:内存缓存->分布式缓存->数据源。 一个方面是提高系统响应能力,增加tps,另一方面是减少io交互,使用性能更高,更稳定的代替其他的
2.6 尽量少引入第三方组件,外部依赖越少,稳定性越高
2.7 能少外部交互就少外部交互
2.8 与外部的交互,如果可以用异步方案就少用同步方案,设置重试策略,设置超时保护,设置降级策略
2.9 评估好自己服务的负载能力,做好熔断保护,做好背压,避免出现流量激增导致服务被打崩
2.10 做好隔离,安全容错,避免一个地方崩了导致所有的的服务崩了;
2.11 做好预警监控,第一时间发现问题,解决问题,减少不可用的时间
实例演示
最后给一个我曾经面试时遇到一个问题,让我设计一个实现日均千万量级的高可用的订单履约系统
针对这种指向明确的设计题,更好的方式当场画架构图,然后就着图给面试官讲解自己的思路(我当时就是这么干的,好处也很明显,图画出来之后,更容易让面试官了解你的思路,同时你自己对着图讲,更不容易遗漏要点,也会显得逻辑缜密、条理清晰)
首先预估服务承载能力: 1kw / 1d = 116 单/s ,一般来说瞬时的最大消费能力会大于平均值,所以我们假定按照200单/s进行设计
最开始,基于面试官对这个系统的简单的业务描述,然后我就设计了一个上面的整体架构图
整体系统架构说明
-
首先单独设计一个收单服务,做成集群方式,主要负责从上游同步订单(采用MQ的异步方式)
-
解释为什么采用MQ:首先是mq的方案,可以非常有效的进行削峰,可以让我们后续的系统按照200tps的消费能力进行设置,无需关注比如大促时,零点的瞬时单量情况;其次就是mq的方案,在我们的系统出现问题之后,进行消息回访,提高我们整体可用性 (因为履约系统不是面向C端用户,它的可用性整体更多的体现在订单是否正常履约)
-
其次就是简单介绍一下,收单服务有哪些东西,比如各种校验,就是为了提前排除不规范的数据;然后就是做一个数据模型转换,可以将不同来源的数据进行统一
-
然后再谈履约的系统(因为在当时我没做过履约业务,所以也不知道内部有哪些系统,只是根据面试官提的有各种订单状态变更这个点出发,给了一个第一版的设计,整了一个类似Storm的数据流式消费的方案)
当我将上面这个方案说完之后,我自己就意识到这个方案和高可用存在冲突,即一个服务的中断,将会影响这个链路的流转,所以可以灵活的表达一下自己对这个方案的说明,比如这个方案适用于链路清晰、每个服务节点逻辑比较轻量可控的场景;当然考虑到对高可用的设计,我们完全可以将这种串行的推进,改成异步的并发调度
然后再把上面这个改动画出来,接着给面试官分析:
-
将服务之间的串行流转,改为由统一的状态机进行调度编排,优势如下:
-
减少服务之间的直接依赖,可以有效的进行流量控制,速度调节,异常重试
-
每个服务只需关注自己的业务逻辑,它通知状态机可以是同步,也可以是异步方案,对于服务提供者而言,更好维护
-
每个服务可以根据自己的承载能力,当自己的消费能力弱时,多加机器;消费能力强时,减少机器(前面串行的方案也有这个能力); 状态机可以根据实际的情况,调整流量分配
-
实际业务会更灵活,比如某些业务场景下,服务2可以不执行;前面串行的方案相比较于后面的状态机调度方案实现上会更复杂、且不通用
-
再其次就是有些服务之间是可以并行调度的,相比于前面的串行方案,无疑消费能力更强
然后再到下面一层,数据存储,一天千万单,所以必然是分库分表,比如最常见的根据订单id进行分库分表; 其次就是考虑到实际的业务特点,也可以考虑冷热方式分库分表
高可用说明
整体架构说完之后,并没有结束,因为问题中明细提出了要高可用,所以我们需要对着这个图来谈一下怎么表明它的高可用
因为上面这个架构图,分了三层,所以我们就有从上往下进行说:
- 收单服务的高可用设计:
-
采用集群方案
-
比如为了减少不同平台的订单导致彼此相互影响,我们可以考虑将对收单服务根据订单来源进行路由区分,如将天猫的订单、打到天猫的收单服务集群;将京东的订单、打到京东的收单服务集群
-
异步拉单方案
-
不然前台的订单服务直接调用收单服务,改为mq的异步交互方式,可以有效的实现削峰,也可以做流量控制
- 履约服务
-
做服务拆分
-
根据不同的实际场景,将履约拆分成一个一个独立的服务,每个服务可以按照自己的实际消费能力,选择部署的实例个数
-
服务拆分之后,相比较于所有服务放在一起而言,可以有效的减少服务之间的彼此影响
-
服务可以放在同一个机房;然后为了提高可用性,可以在不同的机房部署一套对应的服务,比如根据大陆的都放在大陆机房;欧洲的,都放在欧洲机房
-
服务之间的调用,交由统一的状态机来完成
-
由状态机来管理订单的流转,可以根据实际的服务能力来分配调用量;比如当一个服务能力达到上限之后,可以进行限流,避免直接把服务打挂,这样可以确保每个服务都在自己的安全水位线之下运转,提高整体的可用性
-
状态机,实际在这里提供了负载均衡、流量控制、背压、重试等高可用的技术保障
-
状态机的高可用
-
状态机这种通用的服务,由专门的中间件团队维护,交由他们来保障高可用,即便真的出了问题,到时候锅也不是我的(开玩笑的语气说这种话)
-
如果状态机服务让我们自己来处理,那么必然是设计为集群调度方式,状态机与服务之间的交互也可以改成基于MQ的异步交互方式,减少服务因为调用状态机失败不断重试、导致流量放大的问题;也可以避免出现丢数据的场景
- 数据库
-
分库分表来保障高可用,主备、主从、多主多从等成熟的体系来保证可用性
-
如果mysql满足不了要求,用更牛的技术如tidb之类的才保障
- 加监控、加日志、加预警
- 在上面的所有流转地方,都加上服务监控预警、关键日志,如果真的出现问题,那就提前发现问题,排查问题和解决问题
小结
最后小结一下,关于如何设计高可用的分布式系统,非常考虑一个人的综合能力,上面写的这些,主要是为了给大家提供一个回答的思路,但是请抱着质疑的目光来阅读它,肯定会有更好、更完美的方案,如何能在短短的一两个小时的面试时间内,将自己的思考呈现在面试官眼前,这个才是最重要的点,不要过于纠结与全而美,相比于此,多锻炼一下自己的表达方式和逻辑感更为实际
知识星球
扫码加入星球
查看更多优质内容
https://wx.zsxq.com/mweb/views/joingroup/join_group.html?group_id=15522885221412