什么是请求合并?我们先来看两张图:

上方的两张图中,第二张可以看出服务端只执行了一次响应,这就是请求合并。客户端新增的请求合并模块,内部存在一个等待的时间窗口,将一定时间段内满足条件的请求进行合并,以此降低服务端的请求响应压力。

可以看出,请求合并是在客户端中实现的,接下来我们通过代码来实践一下。

首先给出服务端的代码,这里打印了入参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 学习(三)请求合并的更多相关文章

  1. spring cloud: Hystrix(三):健康指数 health Indicator

    spring cloud: Hystrix(三):健康指数 health Indicator ribbon+hystrix 当使用Hystrix时(spring-cloud-starter-hystr ...

  2. Spring Cloud Hystrix 学习(一)

    在学习Hystrix之前,首先引入一个问题场景,服务雪崩.如下图所示: 可以看到,三个入口服务A.B.C最终都会请求到服务T.当服务T的请求过载,打满CPU都无法匹配请求的频率时,同步调用的上级服务就 ...

  3. spring cloud深入学习(三)-----服务消费

    在上一篇博文中简单实现了eureka-server以及eureka-provider,后面会实现eureka-cosumer,现在针对eureka做进一步的详解. 微服务整体架构 文字再美也没有图片直 ...

  4. Spring Cloud Hystrix 学习(二)熔断与降级

    今天来看下Hystrix的熔断与降级. 首先什么是降级?当请求超时.资源不足等情况发生时进行服务降级处理,不调用真实服务逻辑,而是使用快速失败(fallback)方式直接返回一个托底数据,保证服务链条 ...

  5. spring cloud深入学习(四)-----eureka源码解析、ribbon解析、声明式调用feign

    基本概念 1.Registe 一一服务注册当eureka Client向Eureka Server注册时,Eureka Client提供自身的元数据,比如IP地址.端口.运行状况指标的Uri.主页地址 ...

  6. 笔记:Spring Cloud Hystrix 异常处理、缓存和请求合并

    异常处理 在 HystrixCommand 实现的run方法中抛出异常,除了 HystrixBadRequestException之外,其他异常均会被Hystrix 认为命令执行失败并触发服务降级处理 ...

  7. 《Spring Cloud》学习(三) 容错保护!

    在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间互相依赖.由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身间题出现调用故障或延迟,而 ...

  8. Spring Cloud学习 之 Spring Cloud Hystrix(基础知识铺垫)

    Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 文章目录 前述: 快速入门: 命令模式: RxJava: 前述: ​ 在微服务架构中, ...

  9. 第五章 服务容错保护:Spring Cloud Hystrix

    在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能 ...

随机推荐

  1. ACM学习笔记:可持久化线段树

    title : 可持久化线段树 date : 2021-8-18 tags : 数据结构,ACM 可持久化线段树 可以用来解决线段树存储历史状态的问题. 我们在进行单点修改后,线段树只有logn个(一 ...

  2. 武器级工具包 Immunity Canvas 7.26 泄露事件 | 附下载地址

    关于Immunity Canvas Immunity CANVAS是Immunity公司的一款商业级漏洞利用和渗透测试工具,包含了480多个以上的漏洞利用,该工具并不开源,其中文版介绍如下: &quo ...

  3. kivy之TextInput属性实操练习

    TextInput属性比较多,常用在页面设计上的属性做了实操练习,便于很直观的了解学习本部件.并将其中一个输入提示的属性在实操源码里单独建立了一个功能进行演示. 主程序文件main.py我就不贴出来了 ...

  4. Docker创建seafile搭建私有云

    docker-compose.yml version: '2.0' services: db: image: mariadb:10.1 container_name: seafile-mysql en ...

  5. DotNetCore深入了解:HTTPClientFactory类

    一.HttpClient使用 在C#中,如果我们需要向某特定的URL地址发送Http请求的时候,通常会用到HttpClient类.会将HttpClient包裹在using内部进行声明和初始化,如下面的 ...

  6. COM笔记-类厂

    CoCreateInstance实际上并没有直接创建COM组件 ,而是创建了一个被称作是类厂的组件.而所需的组件正是由些类厂创建的.类厂组件的唯一功能就创建其他的组件.创建组件的标准接口是IClass ...

  7. C#基础知识---扩展方法

    一.简介 扩展方法为现有的类型(.Net类型或者自定义类型)扩展应该附加到该类型中的方法. 二.基本原则 定义一个非嵌套.非泛型的静态类 扩展方法是静态的 扩展方法至少要有一个参数,该参数类型是要扩展 ...

  8. qt 中的画图

  9. hive表导出到mysql报错

    Exception in thread "main" java.lang.NoClassDefFoundError: org/json/JSONObject hadoop@hado ...

  10. Blazor+Dapr+K8s微服务之事件发布订阅

    我们要实现的是:在blazorweb服务中发布一个事件,并传递事件参数,然后在serviceapi1服务中订阅该事件,接收到blazorweb服务中发布的事件和参数. 1         在blazo ...