Hystrix之request collapser请求合并详解

对于高并发的访问,可以将多个command进行合并只进行一次command执行,也就是只需要发送一次网络请求来提升系统性能

请求合并的三种级别:

  1. global context,tomcat所有调用线程,对一个依赖服务的任何一个command调用都可以被合并在一起,hystrix就传递一个HystrixRequestContext
  2. user request context,tomcat内某一个调用线程,将某一个tomcat线程对某个依赖服务的多个command调用合并在一起
  3. object modeling,基于对象的请求合并,如果有几百个对象,遍历后依次调用每个对象的某个方法,可能导致发起几百次网络请求,基于hystrix可以自动将对多个对象模型的调用合并到一起

通常使用第二种即可


request collapser带来的利弊:

使用请求合并,由于需要把请求进行合并处理,因此会对返回的结果有一定的延迟影响,因此推荐将延迟本身就比较高的请求合并,而不是对延时很低的请求来合并处理。通过请求合并,系统可以使用比较少的线程资源,因此可以提高整个系统的吞吐量以及减少网络上的资源开销


请求合并时,可以设置一个batch size,以及elapsed time(控制什么时候触发合并后的command执行)。对于一般的请求合并来说,堆同一个资源的command只是参数不同是非常有效的。同时配合使用request cache对相同参数进行缓存来最大程度提升性能。

1)maxRequestsInBatch

控制一个Batch中最多允许多少个request被合并,然后才会触发一个batch的执行

默认值是无限大,就是不依靠这个数量来触发执行,而是依靠时间

HystrixCollapserProperties.Setter()
   .withMaxRequestsInBatch(int value)

(2)timerDelayInMilliseconds

控制一个batch创建之后,多长时间以后就自动触发batch的执行,默认是10毫秒

HystrixCollapserProperties.Setter()
   .withTimerDelayInMilliseconds(int value)

super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("GetProductInfosCollapser"))
                .andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter()
                           .withMaxRequestsInBatch(100)
                           .withTimerDelayInMilliseconds(20))); 

具体实现:

public class GetProductInfosCollapser extends HystrixCollapser<List<ProductInfo>, ProductInfo, Long> {

    private Long productId;

    public GetProductInfosCollapser(Long productId) {
        this.productId = productId;
    }

    @Override
    public Long getRequestArgument() {
        return productId;
    }

    @Override
    protected HystrixCommand<List<ProductInfo>> createCommand(
            Collection<com.netflix.hystrix.HystrixCollapser.CollapsedRequest<ProductInfo, Long>> requests) {
        StringBuilder paramsBuilder = new StringBuilder(""); 
        for(CollapsedRequest<ProductInfo, Long> request : requests) {
            paramsBuilder.append(request.getArgument()).append(","); 
        }
        String params = paramsBuilder.toString();
        params = params.substring(0, params.length() - 1);

        return new BatchCommand(requests);
    }

    @Override
    protected void mapResponseToRequests(
            List<ProductInfo> batchResponse,
            Collection<com.netflix.hystrix.HystrixCollapser.CollapsedRequest<ProductInfo, Long>> requests) {
        int count = 0;
        for(CollapsedRequest<ProductInfo, Long> request : requests) {
            request.setResponse(batchResponse.get(count++));  
        }
    }

    @Override
    protected String getCacheKey() {
        return "product_info_" + productId;
    }

    private static final class BatchCommand extends HystrixCommand<List<ProductInfo>> {

        public final Collection<CollapsedRequest<ProductInfo, Long>> requests;

        public BatchCommand(Collection<CollapsedRequest<ProductInfo, Long>> requests) {
            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ProductInfoService"))
                    .andCommandKey(HystrixCommandKey.Factory.asKey("GetProductInfosCollapserBatchCommand")));
            this.requests = requests;
        }

        @Override
        protected List<ProductInfo> run() throws Exception {
            // 将一个批次内的商品id给拼接在了一起
            StringBuilder paramsBuilder = new StringBuilder(""); 
            for(CollapsedRequest<ProductInfo, Long> request : requests) {
                paramsBuilder.append(request.getArgument()).append(","); 
            }
            String params = paramsBuilder.toString();
            params = params.substring(0, params.length() - 1);

            // 在这里,我们可以做到什么呢,将多个商品id合并在一个batch内,直接发送一次网络请求,获取到所有的结果

            String url = "http://localhost:8082/getProductInfos?productIds=" + params;
            String response = HttpClientUtils.sendGetRequest(url);

            List<ProductInfo> productInfos = JSONArray.parseArray(response, ProductInfo.class);

            return productInfos;
        }

    }

}

可以使用以下代码调用上述处理:

List<Future<ProductInfo>> futures = new ArrayList<Future<ProductInfo>>();

        for(String productId : productIds.split(",")) {
            GetProductInfosCollapser getProductInfosCollapser = 
                    new GetProductInfosCollapser(Long.valueOf(productId)); 
            futures.add(getProductInfosCollapser.queue());
        }

        try {
            for(Future<ProductInfo> future : futures) {
                System.out.println("CacheController的结果:" + future.get());  
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值