前言

服务的降级主要是指当服务负载过高或者出现故障时,将一些非核心业务(负载过高)或者故障业务进行移除或者暂不处理的措施,为其它业务空余出处理资源或者无障碍处理。一般来说在一个系统里面服务降级的流程包含服务接入层、服务逻辑处理层、数据访问层和网络传输层。由于服务接入层一般都有Nginx进行控制,例如流量桶控制,一般称为接入层的限流,这里不做介绍,重点讲一下剩下几个层的降级处理方式。

服务层降级

在大中型分布式系统中,通常系统很多依赖(HTTP,Dubbo等),如果一个应用不能对来自依赖的故障进行有效处理,那该应用本身就处在被拖垮的风险中。在一个高流量的网站中,某个单一的后端一旦发生延迟,将会在数秒内导致所有应用资源被耗尽。

例如:一个依赖30个服务的系统,每个服务99.99%可用。

此系统的失败率为1-99.99%的30次方 ≈ 0.3%

意味着一亿次请求 会有 3,000,00次失败

随着服务依赖数量的变多,服务不稳定的概率会成指数性提高.

这些服务依赖之间的稳定性保障就需要服务层的降级功能,这里介绍基于Hystrix的一个典型场景的降级使用。例如一个商品详情服务它需要调用商品、价格及商品评论三个服务,当一个服务出现故障时,它们没有使用降级服务的演变过程如下:

商品详情需要调用三个服务,如果其中某一个服务由于异常无法响应或者响应延迟,就导致了商品详情连带雪崩。

此时就可以使用Hystrix来进行隔离或者熔断降级处理,它的隔离模式是通过线程隔离,以上面的业务流程为例:

Hystrix通过将每个依赖服务分配独立的线程池进行资源隔离, 从而避免服务雪崩。

如上图所示, 当商品评论服务不可用时, 即使商品服务独立分配的20个线程全部处于同步等待状态,也不会影响其他依赖服务的调用。

Hystrix的熔断器模式流程如下:

熔断器模式定义了熔断器开关相互转换的逻辑:

服务的健康状况 = 请求失败数 / 请求总数.

熔断器开关由关闭到打开的状态转换是通过当前服务健康状况和设定阈值比较决定的.

当熔断器开关关闭时, 请求被允许通过熔断器. 如果当前健康状况高于设定阈值, 开关继续保持关闭. 如果当前健康状况低于设定阈值, 开关则切换为打开状态.

当熔断器开关打开时, 请求被禁止通过.

当熔断器开关处于打开状态, 经过一段时间后, 熔断器会自动进入半开状态, 这时熔断器只允许一个请求通过. 当该请求调用成功时, 熔断器恢复到关闭状态. 若该请求失败, 熔断器继续保持打开状态, 接下来的请求被禁止通过.

熔断器的开关能保证服务调用者在调用异常服务时, 快速返回结果, 避免大量的同步等待. 并且熔断器能在一段时间后继续侦测请求执行结果, 提供恢复服务调用的可能.

我们基于HystrixCommand来介绍上面商品详情的一个实现逻辑:

public class CommentServiceHystrixCommand extends HystrixCommand<Response> {private CommentService service;private Request request;public Service1HystrixCommand(CommentService service, Request request){supper(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ServiceGroup")).andCommandKey(HystrixCommandKey.Factory.asKey("CommentServicequery")).andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("CommentServiceThreadPool")).andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(20))//服务线程池数量.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withCircuitBreakerErrorThresholdPercentage(60)//熔断器关闭到打开阈值.withCircuitBreakerSleepWindowInMilliseconds(3000)//熔断器打开到关闭的时间窗长度))this.service = service;this.request = request;);}//业务正常访问@Overrideprotected Response run(){return service.call(request);}//业务降级返回@Overrideprotected Response getFallback(){return Response.dummy();}
}

其它几个模块类似,使用了Command模式构建了服务对象之后, 服务便拥有了熔断器和线程池的功能。整个服务的框架如下如所示:

隔离及熔断流程如下:

1. 构建Hystrix的Command对象, 调用执行方法.

2. Hystrix检查当前服务的熔断器开关是否开启, 若开启, 则执行降级服务getFallback方法.

3. 若熔断器开关关闭, 则Hystrix检查当前服务的线程池是否能接收新的请求, 若超过线程池已满, 则执行降级服务getFallback方法.

4. 若线程池接受请求, 则Hystrix开始执行服务调用具体逻辑run方法.

5. 若服务执行失败, 则执行降级服务getFallback方法, 并将执行结果上报Metrics更新服务健康状况.

6. 若服务执行超时, 则执行降级服务getFallback方法, 并将执行结果上报Metrics更新服务健康状况.

7. 若服务执行成功, 返回正常结果.

8. 若服务降级方法getFallback执行成功, 则返回降级结果.

若服务降级方法getFallback执行失败, 则抛出异常.

数据层降级

数据层降级一般是指数据的读写降级,例如数据库迁移或者变更场景以及读写DB压力过大的临时处理场景都会用到此服务,我们仍然以商品详情页面来进行分析,假设商品的评论表进行迁移,在实时过程中不希望有新的数据写入,到时仍然希望保障用户的使用连贯性,对于评论仍然可以正常读取查看。

这个实现可以通过配置中心动态配置实现,逻辑处理层依据配置动态调整逻辑分支,例如降级后所有的写操作就走另外一个分支返回“系统维护中,暂无法处理”的提示,但是此模式就需要所有业务逻辑基础上添加一层降级处理,对业务侵入很大。那么怎么处理呢?这里介绍一种基于spring的热加载方案来实现动态切换,Spring的HotSwappableTargetSource,它可以实时动态的修改业务实现Bean,这样我们只需要保障之前的业务Bean不变,重新实现一个降级Bean即可,假设评论如下接口:

public interface CommentService {public get(String id);public write(String id, String comment)
}

正常评论的业务实现如下:

public CommentServiceImpl implements CommentService {public get(String id){//获取评论信息}public write(String id, String comment){//写入评论信息}
}

降级评论的业务实现如下:

public CommentServiceDegradationImpl implements CommentService {public get(String id){//获取评论信息}public write(String id, String comment){throw new DegradationException("系统维护中,暂无法处理");}
}

接下来配置HotSwappableTargetSource,如下:

 <bean id="CommentService"class="org.frame.base.annotation.support.EhCacheFactoryBean" init-method="init"> <property name="targetSource"><ref bean = "targetSource"/></property> </bean> <!-- 默认配置 --><bean id="targetSource" class="org.springframework.aop.target.HotSwappableTargetSource" autowire="constructor" ><constructor-arg><ref bean="commentServiceImpl"/></constructor-arg><bean id="commentServiceImpl"class="com.test.CommentServiceImpl" /> <bean id="commentServiceDegradationImpl "class="com.test.CommentServiceDegradationImpl " /> </bean>

当需要降级的时候,通过配置中心感知到降级指令,再如下swap修改即可切换到降级service:

HotSwappableTargetSource targetSource = (HotSwappableTargetSource) ctx.getBean("targetSource");CommentService commentService = (CommentService) ctx.getBean("commentServiceDegradationImpl");targetSource.swap(commentService);

网络层降级

网络层降级这里主要是指多机房间专线的流量降级,多机房间专线是核心资源,几乎业务的所有数据都有可能会通过专线进行传输,实现数据的双向或者单向的流转,那么当带宽出现波峰的时候就自然需要将某些不重要的业务进行降级或者流量控制,它的通用架构图如下:

它分为两种,一种是完全暂停服务,不再占用带宽,另外一种是通过令牌桶或者流量桶进行流控服务,降低带宽使用。

降级服务可通过配置中心实时下发指令,直接停止或者限制数据同步服务即可。

降低带宽可使用令牌桶或者流量桶,详细可参看本公众号的高并发系统下的限流方案如何实现。

欢迎移步搜索关注公众号:互联网架构师之路(hlw_architector),获取最新架构材料,阅读公众号原文。

ios13.5.1降级_高并发系统下的降级如何实现相关推荐

  1. 高并发处理方案_高并发系统下的缓存解决方案

    什么样的数据适合做缓存? 缓存和DB数据一致性在之前已讲过,详细可参考下面阅读推荐<如何保障mysql和redis之间的数据一致性>,我们这里讲一讲缓存穿透.缓存雪崩和击穿的三种场景解决方 ...

  2. java currenttimemillis 效率_高并发场景下System.currentTimeMillis()的性能问题的优化

    前言 System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我也不知道,不过听说在100倍左右),然而该方法又是一个常用方法,有时不得不使用,比如生 ...

  3. oracle rac 高并发性能_高并发业务下 JVM 涉及的垃圾回收与性能问题分析与定位...

    最近好多 Java 的朋友问:"高并发业务场景下,JVM涉及的性能问题好难搞呀--".看来是大家的技术经验相对少了些,拿不准该从哪些地方上手,其实,每个技术人要该懂得怎样更好打造自 ...

  4. tomcat 请求超时_高并发环境下如何优化Tomcat性能?看完我懂了!

    来自:冰河技术 写在前面 Tomcat作为最常用的Java Web服务器,随着并发量越来越高,Tomcat的性能会急剧下降,那有没有什么方法来优化Tomcat在高并发环境下的性能呢? Tomcat运行 ...

  5. 队列处理高并发_高并发场景下缓存处理的一些思路

    在实际的开发当中,我们经常需要进行磁盘数据的读取和搜索,因此经常会有出现从数据库读取数据的场景出现. 但是当数据访问量次数增大的时候,过多的磁盘读取可能会最终成为整个系统的性能瓶颈,甚至是压垮整个数据 ...

  6. 当 高并发系统下 Redis 发生高延迟时,其内部到底发生了什么

    Redis 是一种内存数据库,将数据保存在内存中,读写效率要比传统的将数据保存在磁盘上的数据库要快很多.但是 Redis 也会发生延迟时,这是就需要我们对其产生原因有深刻的了解,以便于快速排查问题,解 ...

  7. 布隆过滤器速度_高并发系统一定要考虑的 Bloom Filter 布隆过滤器

    开篇思考 你能想到哪些方式判断一个元素是否存在集合中? 布隆过滤器并不存储数据本身,那么是怎么做到过滤的? 布隆过滤器实现?参数配置? 一般我们用来判断一个元素是否存在,会想到用 List,Map,S ...

  8. 都是套路:高并发系统的降级特技

    转载自 都是套路:高并发系统的降级特技 转载于:https://www.cnblogs.com/wzj4858/p/8290266.html

  9. 高并发系统之降级特技

    2019独角兽企业重金招聘Python工程师标准>>> 高并发系统之降级特技 博客分类: 架构 在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.之前已经有一些文章介绍过缓 ...

最新文章

  1. CV技术在医疗领域中有哪些应用?Salesforce、谷歌、斯坦福综述文章登上Nature子刊...
  2. Di-visible Confusion 贪心,模拟,思维,时间复杂度
  3. linux下ifconfig只剩下lo的解决方法
  4. RUP大讲堂(第三讲):如何建立软件产品的愿景
  5. c++现在有一棵合法的二叉树,树的节点都是用数字表示,现在给定这棵树上所有的父子关系,求这棵树的高度
  6. 再获绿色等级5A称号!揭开腾讯数据中心节能环保黑科技
  7. 分布领域驱动设计(DDD):领域接口化设计式缓存的选择
  8. 有关label标签和单选按钮的注意事项
  9. spark 数据倾斜之两阶段聚合(局部聚合+全局聚合)
  10. 获得iframe中的对象的方法
  11. 阿里研究院安筱鹏:云计算推动企业迈向高频竞争时代
  12. SpringMVC文件上传下载实战(单文件、多文件)
  13. RQNOJ:PID4 数列
  14. 信度和效度经典例子_效度与信度的通俗解释
  15. Windows系统睡眠和休眠的区别
  16. 硬盘的结构和介绍,硬盘MBR详细介绍(超详细彩图)
  17. Mongo Java按日期查询
  18. GeoGebra2笔记:二维或三维画图
  19. 《数据库原理》实验六 SQL数据查询实验
  20. windows安装perl

热门文章

  1. python beautifulsoup报错bs4 FeatureNotFound Couldnot find a tree builder with the features
  2. python 求子字符串_求子串-KPM模式匹配-NFA/DFA
  3. 鼠标划过图片进行缩放效果
  4. Spring Boot 学习之,数据库三 ,事务
  5. scal的函数定义(day01)
  6. linux通过vnc掉出浏览器,VNC远程Linux桌面控制好用 --尤其是用浏览器
  7. python绘制3d机械图_使用python绘制3d的图形
  8. 正则表达式 python3_python3正则表达式总结
  9. aspnet网站开发实例_给自己开发一个网站,这是我的方法。
  10. (九)把一切放在一起:用深度伪造换脸