• 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

  • 相关阅读:
    [Sqlite] 移动嵌入式数据库Sqlite日报SQL操作语句汇总
    Matlab spline
    读书笔记:《重来REWORK》
    读书笔记:《一生的计划》
    6 款好用的 PC+Android 同步 GTD 软件
    第35本:《像外行一样思考,像专家一样实践》
    第34本:《暗时间》
    第33本:《删除:大数据取舍之道》
    第32本:《超级时间整理术----每天多出一小时》
    第31本: 思考的乐趣
  • 原文地址:https://www.cnblogs.com/xuzichao/p/15321442.html
Copyright © 2020-2023  润新知