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

[每日一句]

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

[背景介绍]

  • 分布式系统的规模和复杂度不断增加,随着而来的是对分布式系统可用性的要求越来越高。在各种高可用设计模式中,【熔断、隔离、降级、限流】是经常被使用的。而相关的技术,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()方法中实现缓存,这种方式无法避免不必要的线程执行开销

分享资源

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9sEg6B06-1691457511837)(https://pic.imgdb.cn/item/64d0dc6a1ddac507cc857b30.png)]
获取以上资源请访问开源项目 点击跳转

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

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

相关文章

小白到运维工程师自学之路 第六十四集 (dockerfile构建tomcat、mysql、lnmp、redis镜像)

一、tomcat&#xff08;更换jdk&#xff09; mkdir tomcat cd tomcat/ tar xf jdk-8u191-linux-x64.tar.gz tar xf apache-tomcat-8.5.40.tar.gzvim Dockerfile FROM centos:7 MAINTAINER Crushlinux <syh163.com> ADD jdk1.8.0_191 /usr/local/java ENV JAVA_HOME /us…

国内大模型在局部能力上已超ChatGPT

中文大模型正在后来居上&#xff0c;也必须后来居上。 数科星球原创 作者丨苑晶 编辑丨大兔 从GPT3.5彻底出圈后&#xff0c;大模型的影响力开始蜚声国际。一段时间内&#xff0c;国内科技公司可谓被ChatGPT按在地上打&#xff0c;毫无还手之力。 彼时&#xff0c;很多企业…

怎么快速搭建BI?奥威BI系统做出了表率

搭建BI系统有两大关键&#xff0c;分别是环境搭建和数仓建设。这两点不管是哪一个都相当地费时费力&#xff0c;那要怎么才能快速搭建BI平台&#xff0c;顺利实现全企业数字化运营决策&#xff1f;奥威BI系统方案&#xff0c;你值得拥有&#xff01; 奥威BI系统方案&#xff0…

三种方法实现tab栏切换(CSS方法、JS方法、Vue方法)

一、需求 给下图的静态页面添加tab栏切换效果 二、CSS方法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"v…

云知识库软件的推荐清单,你看看你喜欢哪一个?

在选择云知识库软件时&#xff0c;有很多因素需要考虑&#xff0c;如功能、易用性、可定制性、安全性、价格等。下面是一些我喜欢的云知识库软件推荐清单&#xff1a; Confluence&#xff1a; Confluence是一款由Atlassian开发的知识管理和协作工具。它提供了强大的编辑和协作…

Go微服务实践 - Rpc核心概念理解

概述 从0研究一下Golang已经Golang的微服务生态体系&#xff0c;Golang的微服务首先要从Rpc开始&#xff0c;在升级到Grpc&#xff0c;详细介绍这些技术点都在解决什么技术问题。 Rpc Rpc (Remote Procedure Call) 远程过程调用&#xff0c;简单的理解是一个节点请求另一个节…

【果树农药喷洒机器人】Part4:果树冠层图像实例分割模型优化

文章目录 一、引言二、数据集制作2.1图像采集2.2图像标注与增强 三、构建柑橘树冠实例分割模型结构3.1优化特征提取网络3.2U-Net替换FCN 一、引言 为准确获取柑橘树冠的生长信息&#xff0c;实现果树喷药机器人的精准喷施&#xff0c;对处于多种生长阶段的柑橘树冠进行图像分割…

AI和ChatGPT:人工智能的奇迹

AI和ChatGPT&#xff1a;人工智能的奇迹 引言什么是人工智能&#xff1f;ChatGPT&#xff1a;AI的语言之王ChatGPT的工作原理ChatGPT的优势和挑战AI和ChatGPT的未来展望结论 引言 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一项令人兴奋的…

IAR开发环境的安装、配置和新建STM32工程模板

IAR到环境配置到新建工程模板-以STM32为例 一、 简单介绍一下IAR软件1. IAR的安装&#xff08;1&#xff09; 下载IAR集成开发环境安装文件&#xff08;2&#xff09; 安装 2. 软件注册授权 二、IAR上手使用(基于STM32标准库新建工程)1、下载标准库文件2、在IAR新建工程&#x…

ImageNet Classification with Deep Convolutional Neural Networks

&#xff08;一&#xff09;Some Words: 这里主要是通过记录一些笔记来阅读这篇 Paper&#xff0c;它的产生跟 ImageNet LSVRC-2010 竞赛有关&#xff0c;通过训练一个大的、深的卷积网络来将 1.2 million 的 HR 图像分成 1000 类 &#xff0c;这个网络实现了 top-1 37.5% 和 …

GPU显存泄露/显存溢出/显存爆炸 解决方案

问题描述 最近在跑一个基于pytorch的强化学习代码&#xff0c;在训练过程中显存增大非常明显&#xff0c;迭代不到200个iteration就可以占据70G的显存。由于博主是第一次在pytorch实现的强化学习算法上加入自己的实现&#xff0c;很没有应对经验&#xff0c;现将调试过程记录下…

计算机网络(5) --- http协议

计算机网络&#xff08;4&#xff09; --- 协议定制_哈里沃克的博客-CSDN博客协议定制https://blog.csdn.net/m0_63488627/article/details/132070683?spm1001.2014.3001.5501 目录 1.http协议介绍 1.协议的延申 2.http协议介绍 3.URL 4.urlencode和urldecode 2.HTTP协…

使用 RKE 方式搭建 K8s 集群并部署 NebulaGraph

本文由社区用户 Albert 贡献&#xff0c;首发于 NebulaGraph 论坛&#xff0c;旨在提供多一种的部署方式使用 NebulaGraph。 在本文&#xff0c;我将会详细地记录下我用 K8s 部署分布式图数据库 NebulaGraph 的过程。下面是本次实践的内容规划&#xff1a; 一到十章节为 K8s 集…

用html+javascript打造公文一键排版系统16:更新单个附件说明排版,实现多个附件说明排版

利用公休的时间继续完善。 一、更新单个附件说明排版 之前实现单个附件说明排版时&#xff0c;我们只考虑了“附件&#xff1a;”中冒号为半角的情况&#xff0c;而没有考虑存在多任余空格的情况&#xff0c;我们今天先针对存在多任余空格的情况进行完善&#xff0c;增加了温…

APP外包开发的开发语言对比

在开发iOS APP时有两种语言可以选择&#xff0c;Swift&#xff08;Swift Programming Language&#xff09;和 Objective-C&#xff08;Objective-C Programming Language&#xff09;&#xff0c;它们是两种不同的编程语言&#xff0c;都被用于iOS和macOS等苹果平台的软件开发…

[国产MCU]-BL602开发实例-定时器

定时器 文章目录 定时器1、BL602定时器介绍2、定时器驱动API介绍3、定时器使用实例3.1 单次计时3.2 持续计时通用定时器,用于定时,当时间到达我们所设置的定时时间会产生定时中断,可以用来完成定时任务。本文将详细介绍如何使用BL602的定时器功能。 1、BL602定时器介绍 BL6…

如何搭建自动化测试框架?资深测试整理的PO模式,一套打通自动化...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Po模型介绍 1、简…

Redis 报错 RedisConnectionException: Unable to connect to x.x.x.x:6379

文章目录 Redis报错类型可能解决方案 Redis报错类型 org.springframework.data.redis.connection. spingboot调用redis出错 PoolException: Could not get a resource from the pool; 连接池异常:无法从池中获取资源; nested exception is io.lettuce.core. 嵌套异常 RedisConn…

聊聊JDK动态代理原理

1. 示例 首先&#xff0c;定义一个接口&#xff1a; public interface Staff {void work(); }然后&#xff0c;新增一个类并实现上面的接口&#xff1a; public class Coder implements Staff {Overridepublic void work() {System.out.println("认真写bug……");…

一起学数据结构(3)——万字解析:链表的概念及单链表的实现

上篇文章介绍了数据结构的一些基本概念&#xff0c;以及顺序表的概念和实现&#xff0c;本文来介绍链表的概念和单链表的实现&#xff0c;在此之前&#xff0c;首先来回顾以下顺序表的特点&#xff1a; 1.顺序表特点回顾&#xff1a; 1. 顺序表是一组地址连续的存储单元依次存…