在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间通过服务注册与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身间题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会因等待出现故障的依赖方响应形成任务积压,最终导致自身服务的瘫痪。

举个例子,在一个电商网站中,我们可能会将系统拆分成用户、订单、库存、积分、评论等一系列服务单元。用户创建一个订单的时候,客户端将调用订单服务的创建订单接口,此时创建订单接口又会向库存服务来请求出货(判断是否有足够库存来出货)。此时若库存服务因自身处理逻辑等原因造成响应缓慢,会直接导致创建订单服务的线程被挂起,以等待库存申请服务的响应,在漫长的等待之后用户会因为请求库存失败而得到创建订单失败的结果。如果在高并发情况之下,因这些挂起的线程在等待库存服务的响应而未能释放,使得后续到来的创建订单请求被阻塞,最终导致订单服务也不可用。在微服务架构中,存在着那么多的服务单元,若一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加不稳定。

为了解决这样的问题, 产生了断路器等一系列的服务保护机制。“断路器”本身是一种开关装置,用于在电路上保护线路过载,当线路中有电器发生短路时,"断路器”能够及时切断故障电路,防止发生过载、发热甚至起火等严重后果。

在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。

针对上述问题,Spring Cloud Hystrix [hɪst’rɪks] 实现了断路器线程隔离等一系列服务保护功能。它也是基于 Netflix 的开源框架 Hystrix 实现的,该框架的目标在于通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix 具备服务降级服务熔断线程和信号隔离请求缓存请求合并以及服务监控等强大功能。

依赖隔离

舱壁模式

舱壁模式(Bulkhead)隔离了每个工作负载或服务的关键资源,如连接池、内存和 CPU。

使用舱壁避免了单个工作负载(或服务)消耗掉所有资源,从而导致其他服务出现故障的场景。

这种模式主要是通过防止由一个服务引起的级联故障来增加系统的弹性。

工业中使用舱壁将船舶划分为几个部分,以便在船体破坏的情况下,可以将船舶各个部件密封起来。舱壁的概念在软件开发中可以被应用在隔离资源上。

通过应用舱壁模式,可以保护有限的资源不被耗尽。例如,对于一个有连接数限制的数据库实例来说,如果有两种连接它的操作,可以采用两个连接池的方式进行连接,来代替仅采用一个共享连接池的方式。由于这种客户端与资源进行了隔离,超时或过度使用池的操作也不会使其他操作失败。

场景说明

让不同任务请求通过自个专门的线程池请求到各自微服务,像舱壁一样对资源进行隔离。

假设这么个场景,在应用中需要使用 REST 通过 HTTP 连接 5 个不同的微服务,使用一个普通的线程池去维持这些连接,如果 5 个服务中其中一个服务由于某种原因出现异常,所有的池成员都将精疲力尽的等待服务器响应。

下图描述了实施舱壁的简单的示例场景:在左侧,微服务 A,用同一个连接池去请求 X 和 Y 两个服务。如果服务 X 或服务的 Y 其中任何一个行为异常,将会影响连接池的整体行为。如果采用舱壁模式实现,如该图所示的右侧,即使微服务 X 被错误操作,只有池 X 将受到影响。微服务 Y 可以继续为应用程序提供服务。

总结

舱壁模式降低依赖服务对整个系统的影响,保护有限的资源不被耗尽,增加了系统得到弹性。


Docker 通过“舱壁模式”实现进程的隔离,使得容器与容器之间不会互相影响。而 Hystrix 则使用该模式实现线程池的隔离,它会为每一个依赖服务创建一个独立的线程池,这样就算某个依赖服务出现延迟过高的情况,也只是对该依赖服务的调用产生影响,而不会拖慢其他的依赖服务。

通过实现对依赖服务的线程池隔离,可以带来如下优势:

  • 应用自身得到完全保护,不会受不可控的依赖服务影响。即便给依赖服务分配的线程池被填满,也不会影响应用自身的其余部分。

  • 可以有效降低接入新服务的风险。如果新服务接入后运行不稳定或存在问题,完全不会影响应用其他的请求。

  • 当依赖的服务从失效恢复正常后,它的线程池会被清理并且能够马上恢复健康的服务,相比之下,容器级别的清理恢复速度要慢得多。

  • 当依赖的服务出现配置错误的时候,线程池会快速反映出此问题(通过失败次数、延迟、超时、拒绝等指标的增加情况)。同时,我们可以在不影响应用功能的情况下通过实时的动态属性刷新(通过Spring Cloud Config 与 Spring Cloud Bus的 联合使用) 来处理它。

  • 当依赖的服务因实现机制调整等原因造成其性能出现很大变化的时候,线程池的监控指标信息会反映出这样的变化。同时,我们也可以通过实时动态刷新自身应用对依赖服务的阙值进行调整以适应依赖方的改变。

  • 除了上面通过线程池隔离服务发挥的优点之外,每个专有线程池都提供了内置的并发实现,可以利用它为同步的依赖服务构建异步访问

总之, 通过对依赖服务实现线程池隔离,可让应用更加健壮,不会因为个别依赖服务出现问题而引起非相关服务的异常。 同时,也使得我们的应用变得更加灵活,可以在不停止服务的情况下,配合动态配置刷新实现性能配置上的调整。

虽然线程池隔离的方案带来如此多的好处,但是很多使用者可能会担心为每一个依赖服务都分配一个线程池是否会过多地增加系统的负载和开销。 对于这一点,Netflix 在设计 Hystrix 的时候,认为线程池上的开销相对于隔离所带来的好处是无法比拟的。

对于大多数需求来说带来的性能消耗是微乎其微的,更何况可为系统在稳定性和灵活性上带来巨大的提升。虽然对于大部分的请求可以忽略线程池的额外开销,而对于小部分延迟本身就非常小的请求(可能只需要 1ms), 那么带来的延迟开销还是非常昂贵的。

Hystrix 也为此设计了另外的解决方案:信号量。在 Hystrix 中除了可使用线程池之外,还可以使用信号量来控制单个依赖服务的并发度,信号量的开销远比线程池的开销小但是它不能设置超时和实现异步访问。所以,只有在依赖服务足够可靠的情况下才使用信号量。

请求缓存

当系统用户不断增长时,每个微服务需要承受的并发压力也越来越大。在分布式环境下,通常压力来自于对依赖服务的调用,因为请求依赖服务的资源需要通过通信来实现,这样的依赖方式比进程内的调用方式会引起一部分的性能损失,同时 HTTP 相比其他高性能的通信协议在速度上没有任何优势,所以它有些类似于对数据库这样的外部资源进行读写操作,在高并发的情况下可能会成为系统的瓶颈。

既然如此,很容易联想到类似数据访问的缓存保护是否也可以应用到依赖服务的调用上呢?答案显而易见,在高并发的场景之下,Hystrix 中提供了请求缓存的功能,可以方便地开启和使用请求缓存来优化系统,达到减轻高并发时的请求线程消耗降低请求响应时间的效果。

通过开启请求缓存具备下面几项好处:

  • 减少重复的请求数,降低依赖服务的并发度
  • 在同一用户请求的上下文中,相同依赖服务的返回数据始终保持一致
  • 请求缓存在 run() 和 construct() 执行之前生效,所以可以有效减少不必要的线程开销

请求合并

微服务架构中的依赖通常通过远程调用实现,而远程调用中最常见的问题就是通信消耗连接数(线程数)占用。在高并发的情况之下,因通信次数的增加,总的通信时间消耗将会变得不那么理想。同时,因为依赖服务的线程池资源有限,将出现排队等待响应延迟的清况。为了优化这两个问题, Hystrix 提供了 HystrixCollapser 来实现请求的合并,以减少通信消耗和线程数的占用。

在使用了 HystrixCollapser 请求合并器之后,同一时间发生的多个请求处于请求合并器的一个时间窗内,这些请求被请求合并器拦截下来,并在合并器中进行组合,然后将这些请求合并成一个请求发向批量处理接口。在获取到批量请求结果之后,通过请求合并器再将批量结果拆分并分配给每个被合并的请求。

通过使用请求合并器有效减少了对线程池中资源的占用。所以在资源有效并且短时间内会产生高并发请求的时候,为避免连接不够用而引起的延迟可以考虑使用请求合并器的方式来处理和优化。

请求合并的额外开销

虽然通过请求合并可以减少请求的数量以缓解依赖服务线程池的资源,但是在使用的时候也需要注意它所带来的额外开销: 用于请求合并的延迟时间窗会使得依赖服务的请求延迟增高

例如,某个请求不通过请求合并器访问的平均耗时为 5 ms,请求合并的延迟时间窗为 10 ms (默认值),那么当该请求设置了请求合并器之后,最坏情况下(在延迟时间窗结束时才发起请求)该请求需要 15 ms 才能完成。由于请求合并器的延迟时间窗会带来额外开销,所以是否使用请求合并器需要根据依赖服务调用的实际情况来选择,主要考虑下面两个方面:

  • 请求命令本身的延迟。如果依赖服务的请求命令本身是一个高延迟的命令,那么可以使用请求合并器,因为延迟时间窗的时间消耗显得微不足道了。
  • 延迟时间窗内的并发量。如果一个时间窗内只有 1-2 个请求,那么这样的依赖服务不适合使用请求合并器。这种情况不但不能提升系统性能,反而会成为系统瓶颈,因为每个请求都需要多消耗一个时间窗才响应。相反,如果一个时间窗内具有很高的并发量,并且服务提供方也实现了批量处理接口,那么使用请求合并器可以有效 减少网络连接数量并极大提升系统吞吐量,此时延迟时间窗所增加的消耗就可以忽略不计了。

参考:

《Spring Cloud 微服务实战》翟永超 著

Spring Cloud Hystrix 服务容错保护相关推荐

  1. Spring Cloud微服务简介

    1. 基础知识1 什么是微服务架构? 与单体系统的区别 如何实施微服务? 微服务优缺点 为什么选择Spring Cloud? 微服务技术选型 为什么选择Spring Cloud? Spring Clo ...

  2. Spring Cloud构建微服务架构:服务容错保护(Hystrix断路器)

    断路器 断路器模式源于Martin Fowler的Circuit Breaker一文."断路器"本身是一种开关装置,用于在电路上保护线路过载,当线路中有电器发生短路时," ...

  3. java版电子商务spring cloud分布式微服务b2b2c社交电商:服务容错保护(Hystrix断路器)...

    断路器 断路器模式源于Martin Fowler的Circuit Breaker一文."断路器"本身是一种开关装置,用于在电路上保护线路过载,当线路中有电器发生短路时," ...

  4. Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)【Dalston版】

    前言 在微服务架构中,我们将系统拆分成了一个个的服务单元,各单元应用间通过服务注册与订阅的方式互相依赖.由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服 ...

  5. Spring Cloud构建微服务架构:服务容错保护(Hystrix依赖隔离)【Dalston版】

    前言 在上一篇<Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)>中,我们已经体验了如何使用@HystrixCommand来为一个依赖资源定义服务降级逻辑.实 ...

  6. Spring Cloud构建微服务架构:服务容错保护(Hystrix断路器)【Dalston版】

    前言 在前两篇<Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)>和<Spring Cloud构建微服务架构:服务容错保护(Hystrix依赖隔离)&g ...

  7. Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)【Dalston版】 1

    前言 在微服务架构中,我们将系统拆分成了一个个的服务单元,各单元应用间通过服务注册与订阅的方式互相依赖.由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服 ...

  8. java版电子商务spring cloud分布式微服务b2b2c社交电商-服务容错保护(Hystrix服务降级)...

    动手试一试 Spring cloud b2b2c电子商务社交平台源码请加企鹅求求:一零三八七七四六二六.在开始使用Spring Cloud Hystrix实现断路器之前,我们先拿之前实现的一些内容作为 ...

  9. Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)

    2019独角兽企业重金招聘Python工程师标准>>> 动手试一试 在开始使用Spring Cloud Hystrix实现断路器之前,我们先拿之前实现的一些内容作为基础,其中包括: ...

最新文章

  1. 解决cocos2dx 3.x 导入cocostudio的ui界面出现错位问题
  2. 高性能云计算展望(中)
  3. 细数英特尔收购McAfee可获得安全产品
  4. 放大缩小保证div对齐_GraphPad Prism 绘图教程 | 如何在图表中对齐对象
  5. springboot+Mybatis-plue自动生成代码
  6. python基础----特性(property)、静态方法(staticmethod)、类方法(classmethod)、__str__的用法...
  7. 杜克大学用13幅图告诉你人生的真谛,值得深思!
  8. FPGA是什么呢,通透讲解单片机和FPGA的区别
  9. python文件seek_Python文件读取中:f.seek(0)和f.seek(0,0)有什么区别?
  10. 20190328-几种数据清洗的方法
  11. uniapp 安卓 长按app 快捷方式 shortcut
  12. 如何利用Java进行高效的彩信群发
  13. linux 常用的shell脚本
  14. Python人脸识别项目-人脸识别-获取人脸图片
  15. 智能枕头的功能及工作原理
  16. 全面回顾2022年加密行业大事件:破后而立方能绝处逢生
  17. PW5328B的锂电池升压9V芯片方案,设计图
  18. 下列关于python语言中缩进的说法正确的是_关于Python程序中与“缩进”有关的说法中,以下选项中正确的是 _________ 。_学小易找答案...
  19. unity 远处模糊(贴图变模糊)
  20. PC远程控制android思路,PC 远程控制 android手机的方法之一VNC

热门文章

  1. 微计算机最新科技应用论文,微计算机应用
  2. 模电练习题-多路信号发生器(仿真解答)
  3. GreenPlum中性能调优之shared_buffers修改
  4. EXCEL VBA 使用正则表达式清洗替换数据
  5. 钱包终局之战:无私钥的未来
  6. Qt应用程序图标设置任务栏图标设置
  7. vmware 静态ip上网 防止切换网络换ip
  8. 蓝牙技术基础知识总结笔记1 - 蓝牙版本及 4.0 和 BLE 的关系等
  9. python超市收银程序_用java编写超市收银小程序
  10. 长方形图片html圆形,css实现圆角矩形、半圆、圆形效果—border-radius使用详解