首页 > 其他分享 >【Hystrix技术指南】(6)请求合并机制原理分析

【Hystrix技术指南】(6)请求合并机制原理分析

时间:2023-08-09 09:22:25浏览次数:43  
标签:指南 缓存 请求 Hystrix 合并 并发 线程

推荐超值课程:点击获取

[每日一句]

也许你度过了很糟糕的一天,但这并不代表你会因此度过糟糕的一生。

[背景介绍]

  • 分布式系统的规模和复杂度不断增加,随着而来的是对分布式系统可用性的要求越来越高。在各种高可用设计模式中,【熔断、隔离、降级、限流】是经常被使用的。而相关的技术,Hystrix本身早已算不上什么新技术,但它却是最经典的技术体系!。
  • Hystrix以实现熔断降级的设计,从而提高了系统的可用性。
  • Hystrix是一个在调用端上,实现断路器模式,以及隔舱模式,通过避免级联故障,提高系统容错能力,从而实现高可用设计的一个Java服务组件库。
  • *Hystrix实现了资源隔离机制

请求合并的作用场景和原理

Hystrix请求合并用于应对服务器的高并发场景,通过合并请求,减少线程的创建和使用,降低服务器请求压力,提高在高并发场景下服务的吞吐量和并发能力

在正常的分布式请求中,客户端发送请求,服务器在接受请求后,向服务提供者发送请求获取数据,这种模式在高并发的场景下就会导致线程池有大量的线程处于等待状态,从而导致响应缓慢,同时线程池的资源也是有限的,每一个请求都分配一个资源,也是无谓的消耗了很多服务器资源,在这种场景下我们可以通过使用hystrix的请求合并来降低对提供者过多的访问,减少线程池资源的消耗,从而提高系统的吞吐量和响应速度。

如下图,采用请求合并后的服务模式

请求合并可以通过 构建类和添加注解的方式实现,这里我们先说通过构建合并类的方式实现请求合并

  • 请求合并的实现包含了两个主要实现类,一个是合并请求类,一个是批量处理类,合并请求类的作用是收集一定时间内的请求,将他们传递的参数汇总。
  • *然后调用批量处理类,通过向服务调用者发送请求获取批量处理的结果数据,最后在对应的request方法体中依次封装获取的结果,并返回回去

请求合并

  • 可以在HystrixCommand之前放置一个『请求合并器』(HystrixCollapser为请求合并器的抽象父类),该合并器可以将多个发往同一个后端依赖服务的请求合并成一个。
  • *Hystrix请求合并用于应对服务器的高并发场景,通过合并请求,减少线程的创建和使用,降低服务器请求压力,提高在高并发场景下服务的吞吐量和并发能力

下图展示了在两种场景(未增加『请求合并器』和增加『请求合并器』)下,线程和网络连接数量(假设所有请求在一个很小的时间窗口内,例如 10ms,是『并发』的):

为什么要使用请求合并?

在并发执行HystrixCommand时,利用请求合并能减少线程和网络连接数量。

通过使用HystrixCollapser,Hystrix能自动完成请求的合并,开发者不需要对现有代码做批量化的开发。

全局上下文(适用于所有Tomcat线程)

理想情况下,合并过程应该发生在系统全局层面,这样用户发起的,由Tomcat线程执行的所有请求都能被执行合并操作。

例如有这样一个需求,用户需要获取电影评级,而这些数据需要系统请求依赖服务来获取,对依赖服务的请求使用HystrixCommand进行包装,并增加了请求合并的配置,这样,当同一个JVM中其他线程需要执行同样的请求时Hystrix会将这个请求同其他同样的请求合并,只产生一个网络请求。

注意:合并器会传递一个HystrixRequestContext对象到合并的网络请求中,因此,下游系统需要支持批量化,以使请求合并发挥其高效的特点

用户请求上下文(适用于单个 Tomcat 线程)

如果给HystrixCommand只配置成针对单个用户进行请求合并,则 Hystrix 只会在单个 Tomcat 线程(即请求)中进行请求合并。

例如,如果用户想加载 300 个视频对象的书签,请求合并后,Hystrix 会将原本需要发起的 300 个网络请求合并到一个。

对象模型和代码复杂度

很多时候,当你创建一个对象模型,适用于对象的消费者逻辑,结果发现这个模型会导致生产者无法充分利用其拥有的资源。

例如,这里有一个包含300个视频对象的列表,需要遍历这个列表,并对每一个对象调用getSomeAttribute()方法,这是一个显而易见的对象模型,但如果简单处理的话,可能会导致300 次的网络请求(假设getSomeAttribute()方法内需要发出网络请求),每一个网络请求可能都会花上几毫秒(显然,这种方式非常容易拖慢系统)

当然,你也可以要求用户在调用getSomeAttribute()之前,先判断一下哪些视频对象真正需要请求其属性。

你可以将对象模型进行拆分,从一个地方获取视频列表,然后从另一个地方获取视频的属性。

但这些实现会导致API非常丑陋,且实现的对象模型无法完全满足用户使用模式。 并且在企业级开发时,很容易因为开发者的疏忽导致错误或者不够高效,因为不同的开发者可能有不同的请求方式,这样一个地方的优化不足以保证在所有地方都会有优化。

通过将合并逻辑下沉到Hystrix层,不管你如何设计对象模型,或者以何种方式去调用依赖服务,又或者开发者是否意识到这些逻辑需要不需要进行优化,这些都不需要考虑,因为Hystrix能统一处理。

getSomeAttribute()方法能放在它最适合的位置,并且能以最适合的方式被调用,Hystrix 的请求合并器会自动将请求合并到合并时间窗口内。

请求合并带来的额外开销

请求合并会导致依赖服务的请求延迟增高(该延迟为等待请求的延迟),延迟的最大值为合并时间窗口大小。

若某个请求耗时的中位数是 5ms,合并时间窗口为 10ms,那么在最坏情况下(注:合并时间窗口开启时发起请求),请求需要消耗 15ms 才能完成。通常情况下,请求不太可能恰好在合并时间窗口开启时发起,因此,请求合并带来的额外开销应该是合并时间窗口的一般,在此例中是 5ms。

请求合并带来的额外开销是否值得,取决于将要执行的命令,高延迟的命令相比较而言不会有太大的影响。同时,缓存 Key 的选择也决定了在一个合并时间窗口内能『并发』执行的命令数量:如果一个合并时间窗口内只有 1~2 个请求,将请求合并显然不是明智的选择。

事实上,如果单线程循环调用同一个依赖服务的情况下,如果将请求合并,会导致这个循环成为系统性能的瓶颈,因为每一个请求都需要等待 10ms 的合并时间周期。

然而,如果一个命令具有高并发度,并且能批量处理多个,甚至上百个的话,请求合并带来的性能开销会因为吞吐量的极大提升而基本可以忽略,因为 Hystrix 会减少这些请求所需的线程和网络连接数量。

请求合并器的执行流程

请求合并器的执行流程
请求缓存

在HystrixCommand和HystrixObservableCommand的实现中,你可以定义一个缓存的 Key,这个Key用于在同一个请求上下文(全局或者用户级)中标识缓存的请求结果,当然,该缓存是线程安全的

下例展示了在一个完整 HTTP 请求周期内,两个线程执行命令的流程:

请求缓存例子

请求缓存有如下好处:

不同请求路径上针对同一个依赖服务进行的重复请求(有同一个缓存 Key),不会真实请求多次 这个特性在企业级系统中非常有用,在这些系统中,开发者往往开发的只是系统功能的一部分。(注:这样,开发者彼此隔离,不太可能使用同样的方法或者策略去请求同一个依赖服务提供的资源)

例如,请求一个用户的Account的逻辑如下所示,这个逻辑往往在系统不同地方被用到:

Account account = new UserGetAccount(accountId).execute();

Observable accountObservable = new UserGetAccount(accountId).observe();
复制代码

Hystrix的RequestCache只会在内部执行run()方法一次,上面两个线程在执行HystrixCommand命令时,会得到相同的结果,即使这两个命令是两个不同的实例。

数据获取具有一致性

因为缓存的存在,除了第一次请求需要真正访问依赖服务以外,后续请求全部从缓存中获取,可以保证在同一个用户请求内,不会出现依赖服务返回不同的回应的情况。

避免不必要的线程执行

在construct()或run()方法执行之前,会先从请求缓存中获取数据,因此,Hystrix 能利用这个特性避免不必要的线程执行,减小系统开销。

若Hystrix没有实现请求缓存,那么HystrixCommand和HystrixObservableCommand的实现者需要自己在construct()或run()方法中实现缓存,这种方式无法避免不必要的线程执行开销

分享资源

资源分享
扫码关注发送:资源 获取以上资源
字节技术

标签:指南,缓存,请求,Hystrix,合并,并发,线程
From: https://www.cnblogs.com/3shu/p/17615980.html

相关文章

  • [Python爬虫]selenium4新版本使用指南
    From:码同学测试公众号------------------------------------Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7,8,9,10,11),MozillaFirefox,Safari,GoogleChrome,Opera,Edge等。这个工具的主要功能包括......
  • 切面实现下单请求防重提交功能(自定义注释@repeatSubmit)
    该切面功能适用场景下单请求多次提交,导致生成多个相同的订单解决方案前端解决:限制点击下单按钮为1次后失效。不足:用户体验下降,能绕过前端后端解决:防重提交切面解决,自定义注释实现该功能(如下)步骤:自定义注释类RepeatSubmit创建切面并有该注释绑定,在切面类实现防重提......
  • c#调用百度地图web服务api-----该方法可用在js跨域请求上
    百度地图Web服务API为开发者提供http接口,即开发者通过http形式发起检索请求,获取返回json或xml格式的检索数据。用户可以基于此开发JavaScript、C#、C++、Java等语言的地图应用。api官网说明链接:http://developer.baidu.com/map/webservice.htm可用接口列举:获取相关地址提示place......
  • java调用百度地图web服务api-----该方法可用在js跨域请求上
    百度地图Web服务API为开发者提供http接口,即开发者通过http形式发起检索请求,获取返回json或xml格式的检索数据。用户可以基于此开发JavaScript、C#、C++、Java等语言的地图应用。api官网说明链接:http://developer.baidu.com/map/webservice.htm可用接口列举:获取相关地址提示place......
  • Spring Cloud之Hystrix
    微服务架构中,服务数量大大增加,调用关系变得复杂。用户的一个请求,会放大为内部服务间的若干次调用,依赖实际上变多了。而一个服务的故障,沿着调用链传播,也可能造成难以预料的影响。更糟糕的是,在服务数量很多的时候,故障是无可避免的。不论单个服务可用性达到几个9,在服务数量N很大时,......
  • 【JVM技术指南】「GC内存诊断-故障问题排查」一文教你如何打印及分析JVM的GC日志(实战
    当我们在开发Java应用程序时,JVM的GC(垃圾回收)是一个非常重要的话题。GC的作用是回收不再使用的内存,以便程序可以继续运行。在JVM中,GC的日志记录了GC的详细信息,包括GC的类型、时间、内存使用情况等。在本文中,我们将介绍JVMGC日志的格式、含义和分析方法。JVMGC日志格式JVMGC日志的......
  • 深入浅出关于微服务架构实战指南:分布式系统的设计与部署技巧
    深入浅出关于微服务架构实战指南:分布式系统的设计与部署技巧微服务架构实战指南:分布式系统的设计与部署技巧摘要:随着互联网应用的快速发展,传统的单体应用架构已经无法满足高可用、可扩展、快速迭代等需求。微服务架构的出现为解决这些问题提供了一种新的思路。本文将深入探讨微......
  • CodeSys PLC编程指南(ST语言)@Like
    CodeSysPLC编程指南(ST语言)@Like 目录1.软件编程1.1.PLC编程基本概念1.1.1.字符集1.1.2.分界符1.1.3.关键字1.1.4.常数1.1.5.操作数1.1.6.变量1.1.7.数据类型1.1.8.匈牙利命名法1.1.9.变量的类型1.2.ST语言简介1.2.1.执行顺序1.2.2.语句1.3.CODE......
  • 记录--前端实用小技巧: 自动合并的网络请求
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助我们经常会遇到一个场景,比如在一个列表中批量获取用户的信息。 如果我们一次性往后端发送几十条请求是非常愚蠢的事情。此时我们就要学会如何使用批量获取的逻辑。但是批量获取有一个问题就是,我需要在用户列表......
  • Python_GUI(pySide)开发指南(@Like)
    Python_GUI(pySide)开发指南(@Like) 目录一、PythonGUI简介二、PySide6工具安装1.安装VSCode:https://code.visualstudio.com/2.安装Python:https://www.python.org/downloads/3.安装PyCharm:https://www.jetbrains.com/pycharm/4.更新pip: 命令python.exe-mpip......