【深入浅出SpringCloud原理及实战】「Netflix系列之Hystrix」针对于限流熔断组件Hystrix的回退降级实现方案和机制

针对于限流熔断组件Hystrix的回退降级实现方案和机制

      • 依赖隔离
        • 依赖隔离之线程&线程池
        • 高延迟请求的例子
      • 线程池的优势
      • 线程池的弊端
        • 线程池的开销
        • 线程池开销
    • 信号量

依赖隔离

Hystrix通过使用『舱壁模式』(注:将船的底部划分成一个个的舱室,这样一个舱室进水不会导致整艘船沉没。将系统所有依赖服务隔离起来,一个依赖延迟升高或者失败,不会导致整个系统失败)来隔离依赖服务,并限制访问这些依赖服务的并发度。

依赖隔离之线程&线程池

通过将对依赖服务的访问执行放到单独的线程,将其与调用线程(例如 Tomcat 线程池中的线程)隔离开来,调用线程能空出来去做其他的工作而不至于被依赖服务的访问阻塞过长时间。

Hystrix使用独立的,每个依赖服务对应一个线程池的方式,来隔离这些依赖服务,这样,某个依赖服务的高延迟只会拖慢这个依赖服务对应的线程池。

高延迟请求的例子

当然,也可以不使用线程池来使你的系统免受依赖服务失效的影响,这需要你小心的设置网络连接/读取超时时间和重试配置,并保证这些配置能正确正常的运作,以使这些依赖服务在失效时,能快速返回错误

Netflix在设计Hystrix时,使用线程/线程池来实现隔离,原因如下:

  • 多数系统同时运行了(有时甚至多达数百个)不同的后端服务,这些服务由不同开发组开发

  • 每个服务都提供了自己的客户端库

  • 客户端库经常会发生变动

  • 客户端库可能会改变逻辑,加入新的网络请求

  • 客户端库可能会包含重试逻辑,数据解析,缓存(本地缓存或分布式缓存),或者其他类似逻辑。

  • 客户端库对于使用者来说,相当于『黑盒』,其实现细节,网络访问方式,默认配置等等均对使用者透明。

In several real-world production outages the determination was “oh,something changed and properties should be adjusted” or “the client library changed its behavior.”

  • 即使客户端库本身未发生变化,服务自身发生变化,也可能会影响其性能,从而导致客户端配置不再可靠。

  • 中间依赖服务可能包含一些其依赖服务提供的客户端库,而这些库可能不受控且配置不合理

  • 绝大多数网络访问都采用同步的方式进行

  • 客户端代码可能也会有失效或者高延迟,而不仅仅是在网络访问时

面对失效时 Hystrix 包装的请求拓扑图

线程池的优势

将依赖服务请求通过使用不同的线程池隔离,其优势如下:

  • (拒绝请求)系统完全与依赖服务请求隔离开来,即使依赖服务对应线程池耗尽,也不会影响系统其它请求

  • (资源隔离)降低了系统接入新的依赖服务的风险,若新的依赖服务存在问题,也不会影响系统其它请求

  • 当依赖服务失效后又恢复正常,其对应的线程池会被清理干净,相对于整个 Tomcat容器的线程池被占满需要耗费更长时间以恢复可用来说,此时系统可以快速恢复

  • 若依赖服务的配置有问题,线程池能迅速反映出来(通过失败次数的增加,高延迟,超时,拒绝访问等等),同时,你可以在不影响系统现有功能的情况下,处理这些问题(通常通过热配置等方式)。

  • 若依赖服务的实现发生变更,性能有了很大的变化(这种情况时常发生),需要进行配置调整(例如增加/减小超时阈值,调整重试策略等)时,也可以从线程池的监控信息上迅速反映出来(失败次数增加,高延迟,超时,拒绝访问等等),同时,你可以在不影响其他依赖服务,系统请求和用户的情况下,处理这些问题

线程池处理能起到隔离的作用以外,还能通过这种内置的并发特性,在客户端库同步网络IO上,建立一个异步的Facade(类似 Netflix API建立在 Hystrix 命令上的 Reactive、全异步化的那一套 Java API

简而言之,通过线程池提供的依赖服务隔离,可以使得我们能在不停止服务的情况下,更加优雅地应对客户端库和子系统性能上的变化

注:尽管线程池能提供隔离性,但你仍然需要对你的依赖服务客户端代码增加超时逻辑,并且/或者处理线程中断异常,以使这些代码不会无故地阻塞或者拖慢 Hystrix 线程池。

线程池的弊端

使用线程池的主要弊端是会增加系统 CPU 的负载,每个命令的执行,都包含了 CPU 任务的排队,调度,上下文切换。

Netflix在设计Hystrix 时,认为相对于其带来的好处,其带来的负载的一点点升高对系统的影响是微乎其微的。

线程池的开销

Hystrix的开发人员测试了在子线程中执行construct()或run()方法带来的额外时延,以及在父线程中整个请求的耗时,通过这个测试,你能直观了解 Hystrix 使用线程池带来的一点点系统负载的升高影响(线程,监控,日志,熔断器等)。

Netflix API 使用线程池来隔离依赖服务,每天可以处理超过 100 亿的 Hystrix 命令,每个 API 实例有超过 40 个线程池,每个线程池有 5 到 20 个工作线程(绝大部分设置为 10 个线程)。

下图展示了一个HystrixCommand以 60QPS 的速度,在一个 API 实例(每台服务器每秒运行的线程数峰值为 350)上被执行的耗时监控

线程池开销

(注:有 User 的表示使用线程池来隔离依赖服务后的耗时)

中位数显示二者(未使用线程池和使用线程池)没有差别。

  • 90%的情况下,使用线程池有3ms的延迟

  • 99% 的情况下,使用线程池有9ms的延迟,尽管如此,相对于请求的总时间(2ms28ms),延迟(0ms9ms)基本可以忽略不计

90%的情况下,这些延迟和在使用了熔断器之后更高的延迟,在绝大多数 Netflix 的需求来看,是微不足道的,更何况其能带来系统稳定性和鲁棒性上的巨大提升。

对于那些本来延迟就比较小的请求(例如访问本地缓存成功率很高的请求)来说,线程池带来的开销是非常高的,这时,你可以考虑采用其他方法,例如非阻塞信号量(不支持超时),来实现依赖服务的隔离,使用信号量的开销很小。

但绝大多数情况下,Netflix 更偏向于使用线程池来隔离依赖服务,因为其带来的额外开销可以接受,并且能支持包括超时在内的所有功能。

信号量

除了线程池,队列之外,你可以使用信号量(或者叫计数器)来限制单个依赖服务的并发度。Hystrix 可以利用信号量,而不是线程池,来控制系统负载,但信号量不允许我们设置超时和异步化,如果你对客户端库有足够的信任(延迟不会过高),并且你只需要控制系统负载,那么你可以使用信号量。

HystrixCommand和HystrixObservableCommand在两个地方支持使用信号量:

  • 失败回退逻辑:当 Hystrix 需要执行失败回退逻辑时,其在调用线程(Tomcat 线程)中使用信号量

执行命令时:如果设置了 Hystrix 命令的execution.isolation.strategy属性为SEMAPHORE,则 Hystrix 会使用信号量而不是线程池来控制调用线程调用依赖服务的并发度

你可以通过动态配置(即热部署)来决定信号量的大小,以控制并发线程的数量,信号量大小的估计和使用线程池进行并发度估计一样(仅访问内存数据的请求,一般能达到耗时在 1ms 以内,且能达到 5000rps,这样的请求对应的信号量可以设置为 1 或者 2。默认值为 10)

注意:如果依赖服务使用信号量来进行隔离,当依赖服务出现高延迟,其调用线程也会被阻塞,直到依赖服务的网络请求超时

信号量在达到上限时,会拒绝后续请求的访问,同时,设置信号量的线程也无法异步化(即像线程池那样,实现『提交-做其他工作-得到结果』模式)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/444772.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年2月3日(星期六)骑行卧龙古渔村

2024年2月3日 (星期六) 骑行卧龙古渔村,早8:30到9:00, 大观公园门囗集合,9:30准时出发【因迟到者,骑行速度快者,可自行追赶偶遇。】 偶遇地点:大观公园门囗集合 ,家住东,南,北的骑友…

少儿编程教育市场分析:行业规模有望在2025年达到约500亿元

少儿编程教育是通过编程游戏启蒙、可视化图形编程等课程,培养学生的计算思维和创新解难能力的课程。与成人的编程不同,少儿编程教育并非高等教育那样学习如何写代码、编制应用程序,而是通过编程游戏启蒙、可视化图形编程等课程,培…

MySQL基础(三)-学习笔记

一.innodb引擎: 1). 表空间:表空间是InnoDB存储引擎逻辑结构的最高层,启用了参数 innodb_file_per_table(在 8.0版本中默认开启) ,则每张表都会有一个表空间(xxx.ibd),一个mysql实例可以对应多个…

SpringBoot实战(二十六)集成SFTP

目录 一、SFTP简介二、SpringBoot 集成2.1 Maven 依赖2.2 application.yml 配置2.3 DemoController.java 接口2.4 SftpService.java2.5 DemoServiceImpl.java 实现类2.6 SftpUtils.java 工具类2.7 执行结果1)上传文件2)下载文件3)重命名文件&…

Kotlin 协程1:深入理解withContext

Kotlin 协程1:深入理解withContext 引言 在现代编程中,异步编程已经变得非常重要。在 Kotlin 中,协程提供了一种优雅和高效的方式来处理异步编程和并发。在这篇文章中,我们将深入探讨 Kotlin 协程中的一个重要函数:wi…

物联网可视化平台:赋能企业数字化转型

在数字化转型的大潮中,企业面临着如何更好地理解和利用海量数据的挑战。物联网技术的快速发展,为企业提供了一个全新的视角和解决方案。通过物联网可视化平台,企业能够实时监控、分析和展示物联网数据,从而加速数字化转型的进程。…

RabbitMQ 死信队列应用

1. 概念 死信队列(Dead Letter Queue)是在消息队列系统中的一种特殊队列,用于存储无法被消费的消息。消息可能会因为多种原因变成“死信”,例如消息过期、消息被拒绝、消息队列长度超过限制等。当消息变成“死信”时,…

《高性能MySQL》

文章目录 一、创建1. 磁盘1.1 页、扇区、寻道、寻址、硬盘性能 2. 行结构row_format2.1 Compact紧凑2.1.1 行溢出2.1.2 作用2.1.3 内容1-额外信息1、变长字段长度2、NULL值列表3、记录头信息 2.1.4 内容2-真实数据4、表中列的值5、transaction_id6、roll_point7、row_id 2.2 dy…

MD5算法:高效安全的数据完整性保障

摘要:在数字世界中,确保数据完整性和安全性至关重要。消息摘要算法就是一种用于实现这一目标的常用技术。其中,Message Digest Algorithm 5(MD5)算法因其高效性和安全性而受到广泛关注。本文将详细介绍MD5算法的优缺点…

ElementUI 组件:Container 布局容器实例

ElementUI安装与使用指南 Container 布局容器 点击下载learnelementuispringboot项目源码 效果图 el-container-example.vue&#xff08;Container 布局容器实例&#xff09;页面效果图 项目里el-container-example.vue代码 <script> export default {name: el_cont…

<网络安全>《12 数据库安全审计系统》

1 概念 数据库安全审计系统通过对用户访问数据库行为的记录、分析和汇报&#xff0c;来帮助用户事后生成合规报告、事故追根溯源&#xff0c;同时通过大数据搜索技术提供高效查询审计报告&#xff0c;定位事件原因&#xff0c;以便日后查询、分析、过滤&#xff0c;实现加强内…

SpringBoot使用Rabbit详解含完整代码

1. 摘要 本文将详细介绍如何在Spring Boot应用程序中集成和使用RabbitMQ消息队列。RabbitMQ是一个开源的消息代理和队列服务器&#xff0c;用于通过轻量级和可靠的消息在应用程序或系统之间进行异步通信。本文将通过步骤说明、代码示例和详细注释&#xff0c;指导读者在Spring…