高并发架构设计之--「服务降级」、「服务限流」与「服务熔断」

目录

服务降级

1 、简介

2 、使用场景

3 、核心设计

3.1 分布式开关

3.2 自动降级分类

3.3 配置中心

3.4 处理策略

 

3.5 降级分类

3.6 服务降级要考虑的问题

4 、高级特性

4.1 分级降级

4.2 降级权值

5 、总结与展望

服务限流

一、为什么要做服务限流设计?

二、服务限流应该怎么做?

三、服务限流的注意事项

服务熔断

服务熔断和服务降级比较

熔断器

雪崩效应

熔断器(CircuitBreaker)

Hystrix

Hystrix特性

1.断路器机制

2.Fallback

3.资源隔离

Hystrix能做什么?

Hystrix设计原则?

Hystrix怎样实现目标?


服务降级


1 、简介

什么是服务降级?当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作

如果还是不理解,那么可以举个例子:假如目前有很多人想要给我付钱,但我的服务器除了正在运行支付的服务之外,还有一些其它的服务在运行,比如搜索、定时任务和详情等等。然而这些不重要的服务就占用了JVM的不少内存与CPU资源,为了能把钱都收下来(钱才是目标),我设计了一个动态开关,把这些不重要的服务直接在最外层拒掉,这样处理后的后端处理收钱的服务就有更多的资源来收钱了(收钱速度更快了),这就是一个简单的服务降级的使用场景。

2 、使用场景

服务降级主要用于什么场景呢?当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,我们可以将一些 不重要 或 不紧急 的服务或任务进行服务的 延迟使用 或 暂停使用

3 、核心设计

3.1 分布式开关

根据上述需求,我们可以设置一个分布式开关,用于实现服务的降级,然后集中式管理开关配置信息即可。具体方案如下:

3.2 自动降级分类

  • 超时降级 —— 主要配置好超时时间和超时重试次数和机制,并使用异步机制探测恢复情况

  • 失败次数降级 —— 主要是一些不稳定的API,当失败调用次数达到一定阀值自动降级,同样要使用异步机制探测回复情况

  • 故障降级 —— 如要调用的远程服务挂掉了(网络故障、DNS故障、HTTP服务返回错误的状态码和RPC服务抛出异常),则可以直接降级

  • 限流降级 —— 当触发了限流超额时,可以使用暂时屏蔽的方式来进行短暂的屏蔽

当我们去秒杀或者抢购一些限购商品时,此时可能会因为访问量太大而导致系统崩溃,此时开发者会使用限流来进行限制访问量,当达到限流阀值,后续请求会被降级;降级后的处理方案可以是:排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)。

3.3 配置中心

微服务降级的配置信息是集中式的管理,然后通过可视化界面进行友好型的操作。配置中心和应用之间需要网络通信,因此可能会因网络闪断或网络重启等因素,导致配置推送信息丢失、重启或网络恢复后不能再接受、变更不及时等等情况,因此服务降级的配置中心需要实现以下几点特性,从而尽可能的保证配置变更即使达到:

  • 启动主动拉取配置 —— 用于初始化配置(减少第一次定时拉取周期)

  • 发布订阅配置 —— 用于实现配置及时变更(可以解决90%左右的配置变更)

  • 定时拉取配置 —— 用于解决发布订阅失效或消失丢失的情况(可以解决9%左右的发布订阅失效的消息变更)

  • 离线文件缓存配置 —— 用于临时解决重启后连接不上配置中心的问题

  • 可编辑式配置文档 —— 用于直接编辑文档的方式来实现配置的定义

  • 提供Telnet命令变更配置 —— 用于解决配置中心失效而不能变更配置的常见

3.4 处理策略

当触发服务降级后,新的交易再次到达时,我们该如何来处理这些请求呢?从微服务架构全局的视角来看,我们通常有以下是几种常用的降级处理方案:

  • 页面降级 —— 可视化界面禁用点击按钮、调整静态页面

  • 延迟服务 —— 如定时任务延迟处理、消息入MQ后延迟处理

  • 写降级 —— 直接禁止相关写操作的服务请求

  • 读降级 —— 直接禁止相关度的服务请求

  • 缓存降级 —— 使用缓存方式来降级部分读频繁的服务接口

针对后端代码层面的降级处理策略,则我们通常使用以下几种处理措施进行降级处理:

  • 抛异常

  • 返回NULL

  • 调用Mock数据

  • 调用Fallback处理逻辑

3.5 降级分类

  • 降级按照是否自动化可分为:自动开关降级人工开关降级
  • 降级按照功能可分为:读服务降级写服务降级
  • 降级按照处于的系统层次可分为:多级降级

详情参考--架构设计 -- 服务降级策略详解

3.6 服务降级要考虑的问题

  1. 核心和非核心服务
  2. 是否支持降级,降级策略
  3. 业务放通的场景,策略

4 、高级特性

我们已经为每个服务都做好了一个降级开关,也已经在线上验证通过了,感觉完全没问题了。

场景一:某一天,运营搞了一次活动,突然跑过来说,现在流量已经快涨到上限了,有没有批量降级所有不重要服务的方式?开发一脸懵逼的看着,这又不是操作DB,哪里有批量操作呀。

 场景二:某一天,运营又搞事了,说我们等下要搞一个活动,让我们赶紧提前把不重要的服务都降级了,开发又是一脸懵逼,我怎么知道要降级哪些服务呀。

反思:服务降级的功能虽然是实现了,可是没有考虑实施时的体验。服务太多,不知道该降级哪些服务,单个操作降级速度太慢……

4.1 分级降级

当微服务架构发生不同程度的情况时,我们可以根据服务的对比而进行选择式舍弃(即丢车保帅的原则),从而进一步保障核心的服务的正常运作。

如果等线上服务即将发生故障时,才去逐个选择哪些服务该降级、哪些服务不能降级,然而线上有成百上千个服务,则肯定是来不及降级就会被拖垮。同时,在大促或秒杀等活动前才去梳理,也是会有不少的工作量,因此建议在开发期就需要架构师或核心开发人员来提前梳理好,是否能降级的初始评估值,即是否能降级的默认值。

为了便于批量操作微服务架构中服务的降级,我们可以从全局的角度来建立服务重要程度的评估模型,如果有条件的话,建议可以使用 层次分析法(The analytic hierarchy process,简称AHP) 的数学建模模型(或其它模型)来进行定性和定量的评估(肯定比架构师直接拍脑袋决定是否降级好很多倍,当然难度和复杂度也会高许多,即你需要一个会数学建模人才),而层次分析法的基本思路是人对一个复杂的决策问题的思维和判断过程大体上是一样的。

以下是个人给出的最终评价模型,可作为服务降级的评价参考模型进行设计:

我们利用数学建模的方式或架构师直接拍脑袋的方式,结合服务能否降级的优先原则,并根据台风预警(都属于风暴预警)的等级进行参考设计,可将微服务架构的所有服务进行故障风暴等级划分为以下四种:

评估模型

  • 蓝色风暴 —— 表示需要小规模降级非核心服务

  • 黄色风暴 —— 表示需要中等规模降级非核心服务

  • 橙色风暴 —— 表示需要大规模降级非核心服务

  • 红色风暴 —— 表示必须降级所有非核心服务

设计说明

  • 故障严重程度为:蓝色<黄色<橙色<红色

  • 建议根据二八原则可以将服务划分为:80%的非核心服务+20%的核心服务

以上模型只是整体微服务架构的服务降级评估模型,具体大促或秒杀活动时,建议以具体主题为中心进行建立(不同主题的活动,因其依赖的服务不同,而使用不同的进行降级更为合理)。当然模型可以使用同一个,但其数据需要有所差异。最好能建立一套模型库,然后实施时只需要输入相关服务即可输出最终降级方案,即输出本次大促或秒杀时,当发生蓝色风暴时需要降级的服务清单、当发生黄色风暴时需要降级的服务清单……

4.2 降级权值

微服务架构中有服务权值的概念,主要用于负载时的权重选择,同样服务降级权值也是类似,主要用于服务降级选择时的细粒度优先级抉择。所有的服务直接使用以上简单的四级划分方式进行统一处理,显然粒度太粗,或者说出于同一级的多个服务需要降级时的 降级顺序 该如何?甚至我想要人工智能化的 自动降级,又该如何更细粒度的控制?

基于上述的这些AI化的需求,我们可以为每一个服务分配一个降级权值,从而便于更加智能化的实现服务治理。而其评估的数值,同样也可以使用数学模型的方式进行 定性 与 定量 的评估出来,也可以架构师根据经验直接拍脑袋来确定。

5 、总结与展望

以上提供了半实际与半理论的服务降级方案,使用者可以根据其公司的实际情况进行适当的选择,而完整的方案,笔者目前也没有发现有实施过的,但可以建议有长远服务治理规划的大厂进行完整方案的研究与实施,会对未来人工智能万物互联的时代有较好的治理价值存在(个人看法)。而小厂出于成本和其发挥的价值的考虑,不建议使用这么复杂的方案,但可以实现分布式开关和简单分级降级的功能特性。

本文主要以服务降级为核心进行更加理想的治理微服务架构,其中建议运用数学领域的适当模型来实现 定性 和 定量 的合理分析和治理微服务,为未来 人工智能治理微服务(Artificial Intelligence Governance Micro Service,简称AIGMS)提供方案支持。


服务限流


限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。一般来说系统的吞吐量是可以被测算的,为了保证系统的稳定运行,一旦达到的需要限制的阈值,就需要限制流量并采取一些措施以完成限制流量的目的。比如:延迟处理,拒绝处理,或者部分拒绝处理等等

在介绍限流概念之前,我们先来聊聊身边有哪些限流,如果有在帝都的码农估计对限流是最深有感触的,帝都但凡开个XXX会议,各大地铁站都会限流。

每年的双11都是剁手族的天堂,11月11号0点0几秒的时候,下面这些场景或许你曾经遇到过。

当然,这几年双11各大电商对并发的支持做的越来越好,这里只是借鉴双11刚推出之际,常常需要应对的一些问题。

通过这两个场景,基本上服务限流的作用也就明白:

「服务限流」其实是指当系统资源不够,不足以应对大量请求,即系统资源与访问量出现矛盾的时候,我们为了保证有限的资源能够正常服务,因此对系统按照预设的规则进行流量限制或功能限制的一种方法。

一、为什么要做服务限流设计?

再举一个我们生活中的例子:一些热门的旅游景点,往往会对每日的旅游参观人数有严格的限制,比如厦门的鼓浪屿、北京的故宫等,每天只会卖出固定数目的门票,如果你去的晚了,可能当天的票就已经卖完了,当天就无法进去游玩了。

为什么旅游景点要做这样的限制呢?多卖一些门票多赚一些钱岂不是更好?

其实对于旅游景点而言,她们也很无奈,因为景点的服务资源有限嘛,每日能服务的人数是有限的,一旦放开限制了,景点的工作人员就会不够用,卫生情况也得不到保障,安全也有隐患,超密集的人群也会严重的影响游客的体验。
但由于景区名气大,来游玩的旅客络绎不绝,远超出了景区的承载能力,因此景区只好做出限制每日人员流量的举措。

同理,在IT软件行业中,系统服务也是这样的。

如果你的系统理论是时间单位内可服务100W用户,但是今天却突然来了300W用户,由于用户流量的随机性,如果不加以限流,很有可能这300W用户一下子就压垮了系统,导致所有人都得不到服务。

因此为了保证系统至少还能为100W用户提供正常服务,我们需要对系统进行限流设计。

有的人可能会想,既然会有300W用户来访问,那为啥系统不干脆设计成能足以支撑这么大量用户的集群呢?

这是个好问题。如果系统是长期有300W的用户来访问,肯定是要做上述升级的,但是常常面临的情况是,系统的日常访问量就是100W,只不过偶尔有一些不可预知的特定原因导致的短时间的流量激增,这个时候,公司往往出于节约成本的考虑,不会为了一个不常见的尖峰来把我们的系统扩容到最大的尺寸。

二、服务限流应该怎么做?

对系统服务进行限流,一般有如下几个模式:

  1. 熔断
    这个模式是需要系统在设计之初,就要把熔断措施考虑进去。当系统出现问题时,如果短时间内无法修复,系统要自动做出判断,开启熔断开关,拒绝流量访问,避免大流量对后端的过载请求。系统也应该能够动态监测后端程序的修复情况,当程序已恢复稳定时,可以关闭熔断开关,恢复正常服务。

  2. 服务降级
    将系统的所有功能服务进行一个分级,当系统出现问题,需要紧急限流时,可将不是那么重要的功能进行降级处理,停止服务,这样可以释放出更多的资源供给核心功能的去用。
    例如在电商平台中,如果突发流量激增,可临时将商品评论、积分等非核心功能进行降级,停止这些服务,释放出机器和CPU等资源来保障用户正常下单,而这些降级的功能服务可以等整个系统恢复正常后,再来启动,进行补单/补偿处理。
    除了功能降级以外,还可以采用不直接操作数据库,而全部读缓存、写缓存的方式作为临时降级方案。

  3. 延迟处理
    这个模式需要在系统的前端设置一个流量缓冲池,将所有的请求全部缓冲进这个池子,不立即处理。然后后端真正的业务处理程序从这个池子中取出请求依次处理,常见的可以用队列模式来实现。这就相当于用异步的方式去减少了后端的处理压力,但是当流量较大时,后端的处理能力有限,缓冲池里的请求可能处理不及时,会有一定程度延迟。

  4. 特权处理
    这个模式需要将用户进行分类,通过预设的分类,让系统优先处理需要高保障的用户群体,其它用户群的请求就会延迟处理或者直接不处理。

那在实际项目中,对访问流量的限制,可采用如下几种技术方法:

  • 熔断技术
    熔断的技术可以重点参考Netflix的开源组件hystrix的做法,主要有三个模块:熔断请求判断算法、熔断恢复机制、熔断报警。

  • 计数器方法
    系统维护一个计数器,来一个请求就加1,请求处理完成就减1,当计数器大于指定的阈值,就拒绝新的请求。
    基于这个简单的方法,可以再延伸出一些高级功能,比如阈值可以不是固定值,是动态调整的。另外,还可以有多组计数器分别管理不同的服务,以保证互不影响等。

  • 队列方法
    就是基于FIFO队列,所有请求都进入队列,后端程序从队列中取出待处理的请求依次处理。
    基于队列的方法,也可以延伸出更多的玩法来,比如可以设置多个队列以配置不同的优先级。

  • 令牌桶方法
    首先还是要基于一个队列,请求放到队列里面。但除了队列以外,还要设置一个令牌桶,另外有一个脚本以持续恒定的速度往令牌桶里面放令牌,后端处理程序每处理一个请求就必须从桶里拿出一个令牌,如果令牌拿完了,那就不能处理请求了。我们可以控制脚本放令牌的速度来达到控制后端处理的速度,以实现动态流控。

三、服务限流的注意事项

我们在做服务限流的时候,还是有一些原则和事项需要注意的:

  • 实时监控:系统必须要做好全链路的实时监控,才能保证限流的及时检测和处理。

  • 手动开关:除系统自动限流以外,还需要有能手动控制的开关,以保证随时都可以人工介入。

  • 限流的性能:限流的功能理论上是会在一定程度影响到业务正常性能的,因此需要做到限流的性能优化和控制。

系统故障常常都是不可预测且难以避免的,因此作为系统设计师的我们,必须要提前预设各种措施,以应对随时可能的系统风险。

服务熔断


在股票市场,熔断这个词大家都不陌生,是指当股指波幅达到某个点后,交易所为控制风险采取的暂停交易措施。相应的,服务熔断一般是指软件系统中,由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,从而采用的一种保护措施,所以很多地方把熔断亦称为过载保护。

服务熔断和服务降级比较

两者其实从有些角度看是有一定的类似性的:

  1. 目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;
  2. 最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用;
  3. 粒度一般都是服务级别,当然,业界也有不少更细粒度的做法,比如做到数据持久层(允许查询,不允许增删改);
  4. 自治性要求很高,熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段;

而两者的区别也是明显的:

  1. 触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
  2. 管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)
  3. 实现方式不太一样

熔断器

雪崩效应

在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应。服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费者”的不可用,并将不可用逐渐放大的过程。

如果下图所示:A作为服务提供者,B为A的服务消费者,C和D是B的服务消费者。A不可用引起了B的不可用,并将不可用像滚雪球一样放大到C和D时,雪崩效应就形成了。

熔断器(CircuitBreaker)

熔断器的原理很简单,如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器也可以使应用程序能够诊断错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。

熔断器模式就像是那些容易导致错误的操作的一种代理。这种代理能够记录最近调用发生错误的次数,然后决定使用允许操作继续,或者立即返回错误。 
熔断器开关相互转换的逻辑如下图:

熔断器就是保护服务高可用的最后一道防线。

Hystrix

该库旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包(request collapsing,即自动批处理,译者注),以及监控和配置等功能。

Hystrix特性

1.断路器机制

断路器很好理解, 当Hystrix Command请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN). 这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN). Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力.

2.Fallback

Fallback相当于是降级操作. 对于查询操作, 我们可以实现一个fallback方法, 当请求后端服务出现异常的时候, 可以使用fallback方法返回的值. fallback方法的返回值一般是设置的默认值或者来自缓存.

3.资源隔离

在Hystrix中, 主要通过线程池来实现资源隔离. 通常在使用的时候我们会根据调用的远程服务划分出多个线程池. 例如调用产品服务的Command放入A线程池, 调用账户服务的Command放入B线程池. 这样做的主要优点是运行环境被隔离开了. 这样就算调用服务的代码存在bug或者由于其他原因导致自己所在线程池被耗尽时, 不会对系统的其他服务造成影响. 但是带来的代价就是维护多个线程池会对系统带来额外的性能开销. 如果是对性能有严格要求而且确信自己调用服务的客户端代码不会出问题的话, 可以使用Hystrix的信号模式(Semaphores)来隔离资源.

Hystrix能做什么?

  1. 在通过第三方客户端访问(通常是通过网络)依赖服务出现高延迟或者失败时,为系统提供保护和控制
  2. 在分布式系统中防止级联失败
  3. 快速失败(Fail fast)同时能快速恢复
  4. 提供失败回退(Fallback)和优雅的服务降级机制
  5. 提供近实时的监控、报警和运维控制手段

Hystrix设计原则?

  1. 防止单个依赖耗尽容器(例如 Tomcat)内所有用户线程
  2. 降低系统负载,对无法及时处理的请求快速失败(fail fast)而不是排队
  3. 提供失败回退,以在必要时让失效对用户透明化
  4. 使用隔离机制(例如『舱壁』/『泳道』模式,熔断器模式等)降低依赖服务对整个系统的影响
  5. 针对系统服务的度量、监控和报警,提供优化以满足近实时性的要求
  6. 在 Hystrix 绝大部分需要动态调整配置并快速部署到所有应用方面,提供优化以满足快速恢复的要求
  7. 能保护应用不受依赖服务的整个执行过程中失败的影响,而不仅仅是网络请求

Hystrix怎样实现目标?

  1. 在一个单独的线程中通过 HystrixCommand 或 HystrixObservableCommand 对象包装所有外部系统(或依赖)的调用。
  2. 调用超时比设置的阈值更长。虽然有默认值,但是大多数依赖自己配置的这些超时“属性”,所以每个依赖都略高于实测性能的99.5%。
  3. 为每个依赖保持一个小的线程池;如果线程池满了,新来的请求会立即拒绝掉,而不是排队等候。
  4. 测试成功、失败(客户端抛出异常)、超时和线程拒绝。
  5. 当请求失败、被拒、超时或者短路时的性能反馈逻辑。
  6. 准实时的监控指标和配置改变。
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值