Spring Cloud Hystrix 学习(三)请求合并
什么是请求合并?我们先来看两张图:


上方的两张图中,第二张可以看出服务端只执行了一次响应,这就是请求合并。客户端新增的请求合并模块,内部存在一个等待的时间窗口,将一定时间段内满足条件的请求进行合并,以此降低服务端的请求响应压力。
可以看出,请求合并是在客户端中实现的,接下来我们通过代码来实践一下。
首先给出服务端的代码,这里打印了入参ids,后续我们将通过这个入参打印的情况来对请求合并的情况进行观察。
@RequestMapping(value = "/mergeTest", method = RequestMethod.GET)
public List<Test> mergeTest(String ids) { System.out.println("ids:{" + ids + "}");
String[] strs = ids.split(","); List<Test> lstResult = new ArrayList<Test>();
for (int i = 0; i < strs.length; i++) {
lstResult.add(new Test(i, Integer.parseInt(strs[i])));
}
return lstResult;
}
这里补充说明一点,对于测试用的Test类必须存在空构造函数,否则在客户端收到应答后反序列化时可能会抛出如下异常:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `hystrix.dto.Test` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (PushbackInputStream); line: 1, column: 3] (through reference chain: java.lang.Object[][0])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.9.10.6.jar:2.9.10.6]
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1452) ~[jackson-databind-2.9.10.6.jar:2.9.10.6]
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1028) ~[jackson-databind-2.9.10.6.jar:2.9.10.6]
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297) ~[jackson-databind-2.9.10.6.jar:2.9.10.6]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326) ~[jackson-databind-2.9.10.6.jar:2.9.10.6]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) ~[jackson-databind-2.9.10.6.jar:2.9.10.6]
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:195) ~[jackson-databind-2.9.10.6.jar:2.9.10.6]
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:21) ~[jackson-databind-2.9.10.6.jar:2.9.10.6]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4014) ~[jackson-databind-2.9.10.6.jar:2.9.10.6]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3085) ~[jackson-databind-2.9.10.6.jar:2.9.10.6]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:271) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:240) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:102) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:733) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:666) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:307) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
at hystrix.service.TestService.mergeTest(TestService.java:53) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
接下来再看下客户端请求合并逻辑的实现,这里我们采用注解的方式来完成:
@Service
public class TestService { @Autowired
private RestTemplate restTemplate; @Autowired
private DiscoveryClient discoveryClient; @HystrixCollapser(batchMethod = "mergeTest", collapserProperties = {
@HystrixProperty(name = "timerDelayInMilliseconds", value = "3000")
})
public Future<Test> singleTest(Integer id) {
return null;
} @HystrixCommand
public List<Test> mergeTest(List<Integer> ids) { ServiceInstance instance = discoveryClient.getInstances("spring-cloud-service-provider").get(0);
String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/mergeTest";
Test[] tests = restTemplate.getForObject(url + "?ids={1}", Test[].class, StringUtils.join(ids, ","));
return Arrays.asList(tests);
}
}
singleTest通过@HystrixCollapser注解实现请求合并,并指定了合并后调用的方法为mergeTest(),同时设置了时间窗口的大小为3000毫秒。
最后就是测试代码:
@GetMapping("/hystrix/test")
public String helloHystrix() throws ExecutionException, InterruptedException {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
Future<Test> f1 = service.singleTest(101);
Future<Test> f2 = service.singleTest(102);
Future<Test> f3 = service.singleTest(103);
Test t1 = f1.get();
Test t2 = f2.get();
Test t3 = f3.get();
Thread.sleep(3000);
Future<Test> f4 = service.singleTest(104);
Test t4 = f4.get();
context.close();
return t1.getIndex() + ", " + t2.getIndex() + ", " + t3.getIndex() + ", " + t4.getIndex();
}
通过postman进行请求后,服务端打印信息如下:

可以看到前三条请求合并为一条汇总请求调用到服务端,由于第四条请求是在sleep(3000)之后进行发起,并未和前三条请求进入同一个时间窗口,因此单独调用到了服务端。
参考资料:
https://segmentfault.com/a/1190000011468804
https://www.cnblogs.com/yb-ken/p/15068392.html
Spring Cloud Hystrix 学习(三)请求合并的更多相关文章
- spring cloud: Hystrix(三):健康指数 health Indicator
spring cloud: Hystrix(三):健康指数 health Indicator ribbon+hystrix 当使用Hystrix时(spring-cloud-starter-hystr ...
- Spring Cloud Hystrix 学习(一)
在学习Hystrix之前,首先引入一个问题场景,服务雪崩.如下图所示: 可以看到,三个入口服务A.B.C最终都会请求到服务T.当服务T的请求过载,打满CPU都无法匹配请求的频率时,同步调用的上级服务就 ...
- spring cloud深入学习(三)-----服务消费
在上一篇博文中简单实现了eureka-server以及eureka-provider,后面会实现eureka-cosumer,现在针对eureka做进一步的详解. 微服务整体架构 文字再美也没有图片直 ...
- Spring Cloud Hystrix 学习(二)熔断与降级
今天来看下Hystrix的熔断与降级. 首先什么是降级?当请求超时.资源不足等情况发生时进行服务降级处理,不调用真实服务逻辑,而是使用快速失败(fallback)方式直接返回一个托底数据,保证服务链条 ...
- spring cloud深入学习(四)-----eureka源码解析、ribbon解析、声明式调用feign
基本概念 1.Registe 一一服务注册当eureka Client向Eureka Server注册时,Eureka Client提供自身的元数据,比如IP地址.端口.运行状况指标的Uri.主页地址 ...
- 笔记:Spring Cloud Hystrix 异常处理、缓存和请求合并
异常处理 在 HystrixCommand 实现的run方法中抛出异常,除了 HystrixBadRequestException之外,其他异常均会被Hystrix 认为命令执行失败并触发服务降级处理 ...
- 《Spring Cloud》学习(三) 容错保护!
在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间互相依赖.由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身间题出现调用故障或延迟,而 ...
- Spring Cloud学习 之 Spring Cloud Hystrix(基础知识铺垫)
Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 文章目录 前述: 快速入门: 命令模式: RxJava: 前述: 在微服务架构中, ...
- 第五章 服务容错保护:Spring Cloud Hystrix
在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能 ...
随机推荐
- scrapy爬虫框架使用
一.scrapy框架 1.什么是scrapy: 爬虫中封装好的一个明星框架.功能:高性能的持久化存储,异步的数据下载,高性能的数据解析,分布式. 2.使用方法: 安装: 下载tiwisted,此处位下 ...
- 轻松上手SpringBoot+SpringSecurity+JWT实RESTfulAPI权限控制实战
前言 我们知道在项目开发中,后台开发权限认证是非常重要的,springboot 中常用熟悉的权限认证框架有,shiro,还有就是springboot 全家桶的 security当然他们各有各的好处,但 ...
- one_gadget的一些姿势
概要 one_gadget是libc中存在的一些执行execve("/bin/sh", NULL, NULL)的片段,当可以泄露libc地址,并且可以知道libc版本的时候,可以使 ...
- 【LeetCode】80. 删除有序数组中的重复项 II
80. 删除有序数组中的重复项 II 知识点:数组:排序:双指针: 题目描述 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度. 不要使 ...
- 题解 God Knows
传送门 这里有个线段树维护单调栈的神仙技巧 同机房dalao @Yubai的不同理解方式 yysy,我考场上连\(n^2\)的暴力都没搞出来 这里实际上求的是最小权极大上升子序列 但这个跟题目几乎没什 ...
- 神州战神U盘安装windows10系统,启动项制作好后,在bios中识别不到自己的u盘问题
我笔记本是神州战神,启动盘做完了后,按快捷键F2,进入boot下进行设置,找了半天没找到自己的u盘,很郁闷,捣鼓了半天才搞定,以下是我修改之后的设置: 1.把Secure Boot设置为disable ...
- CentOS7 yum方式安装MySQL5.7 + 远程连接
1 下载并安装MySQL官方的 Yum Repository [root@localhost ~]# wget -i -c http://dev.mysql.com/get/mysql57-commu ...
- 【转】SpringCloud学习
Spring Cloud Alibaba与Spring Boot.Spring Cloud之间不得不说的版本关系 这篇博文是临时增加出来的内容,主要是由于最近连载<Spring Cloud ...
- javacc在stanfordnlp中的应用
总结: 这个javacc感觉比较复杂,在于stanfordnlp中 p.p1 { margin: 0; font: 11px Monaco } CoreMapExpressionExtractor这个 ...
- python turtle的使用
turtle.pendown() # 放下画笔 turtle.penup() # 抬起画笔 turtle.pensize(int) # 设置画笔宽度,值为整数型 turtle.forward(f ...