请求合并

  使用HystrixObservableCollapser可以将参数不同,但执行过程相同的调用合并执行。当调用observe、toObservable方法时,会向RequestCollapser提交getRequestArgument方法获取的参数。用户需要实现getRequestArgument方法来设定请求参数,RequestCollapser是执行批量的类。

    public Observable<ResponseType> toObservable(Scheduler observeOn) {
return Observable.defer(new Func0<Observable<ResponseType>>() {
@Override
public Observable<ResponseType> call() {
final boolean isRequestCacheEnabled = getProperties().requestCacheEnabled().get();
//是否开启缓存,如果开启缓存并且实现了getCacheKey方法,则首先从HystrixRequestCache获取结果数据
if (isRequestCacheEnabled) {
HystrixCachedObservable<ResponseType> fromCache = requestCache.get(getCacheKey());
if (fromCache != null) {
metrics.markResponseFromCache();
return fromCache.toObservable();
}
}
         //获取合并请求对象,提交请求
RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> requestCollapser = collapserFactory.getRequestCollapser(collapserInstanceWrapper);
Observable<ResponseType> response = requestCollapser.submitRequest(getRequestArgument());
metrics.markRequestBatched();
        // 是否开启缓存,如果开启缓存并且实现了getCacheKey方法,将结果放到HystrixRequestCache
if (isRequestCacheEnabled) {
HystrixCachedObservable<ResponseType> toCache = HystrixCachedObservable.from(response);
HystrixCachedObservable<ResponseType> fromCache = requestCache.putIfAbsent(getCacheKey(), toCache);
if (fromCache == null) {
return toCache.toObservable();
} else {
return fromCache.toObservable();
}
}
return response;
}
});
}

RequestCollapserFactory

  创建RequestCollapser,如果是GLOBAL作用域,会创建一个RequestCollapser,并且使用一个static的ConcurrentHashMap作为一个全局的缓存。如果是REQUEST作用域,会创建一个RequestCollapser,使用HystrixRequestVariableHolder来存储。

private static ConcurrentHashMap<String, RequestCollapser<?, ?, ?>> globalScopedCollapsers = new ConcurrentHashMap<String, RequestCollapser<?, ?, ?>>();
private static ConcurrentHashMap<String, HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>>> requestScopedCollapsers = new ConcurrentHashMap<String, HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>>>(); public RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> getRequestCollapser(HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser) {
if (Scopes.REQUEST == Scopes.valueOf(getScope().name())) {
return getCollapserForUserRequest(commandCollapser);
} else if (Scopes.GLOBAL == Scopes.valueOf(getScope().name())) {
return getCollapserForGlobalScope(commandCollapser);
} else {
logger.warn("Invalid Scope: {} Defaulting to REQUEST scope.", getScope());
return getCollapserForUserRequest(commandCollapser);
}
}

RequestCollapser

  内部有一个RequestBatch对象,代表当前的一批请求,当定时器到达一定间隔,会执行该批量请求对象中所有的请求,然后新建一个RequestBatch对象。


...
private final AtomicReference<RequestBatch<BatchReturnType, ResponseType, RequestArgumentType>> batch = new AtomicReference<RequestBatch<BatchReturnType, ResponseType, RequestArgumentType>>();
....

private class CollapsedTask implements TimerListener {
final Callable<Void> callableWithContextOfParent; CollapsedTask() {
// this gets executed from the context of a HystrixCommand parent thread (such as a Tomcat thread)
// so we create the callable now where we can capture the thread context
callableWithContextOfParent = new HystrixContextCallable<Void>(concurrencyStrategy, new Callable<Void>() {
// the wrapCallable call allows a strategy to capture thread-context if desired @Override
public Void call() throws Exception {
try {
// we fetch current so that when multiple threads race
// we can do compareAndSet with the expected/new to ensure only one happens
RequestBatch<BatchReturnType, ResponseType, RequestArgumentType> currentBatch = batch.get();
// 1) it can be null if it got shutdown
// 2) we don't execute this batch if it has no requests and let it wait until next tick to be executed
if (currentBatch != null && currentBatch.getSize() > 0) {
// do execution within context of wrapped Callable
createNewBatchAndExecutePreviousIfNeeded(currentBatch);
}
} catch (Throwable t) {
logger.error("Error occurred trying to execute the batch.", t);
t.printStackTrace();
// ignore error so we don't kill the Timer mainLoop and prevent further items from being scheduled
}
return null;
} });
} @Override
public void tick() {
try {
callableWithContextOfParent.call();
} catch (Exception e) {
logger.error("Error occurred trying to execute callable inside CollapsedTask from Timer.", e);
e.printStackTrace();
}
} @Override
public int getIntervalTimeInMilliseconds() {
return properties.timerDelayInMilliseconds().get();
} }

  使用HystrixContextCallable是为了batch执行共享父亲HystrixRequestContext。

@Override
public K call() throws Exception {
HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();
try {
// set the state of this thread to that of its parent
HystrixRequestContext.setContextOnCurrentThread(parentThreadState);
// execute actual Callable with the state of the parent
return actual.call();
} finally {
// restore this thread back to its original state
HystrixRequestContext.setContextOnCurrentThread(existingState);
}
}

RequestBatch

  内部有一个ConcurrentMap来存储请求对象。key为:请求参数对象,value为CollapsedRequest对象。

private final ConcurrentMap<RequestArgumentType, CollapsedRequest<ResponseType, RequestArgumentType>> argumentMap =
new ConcurrentHashMap<RequestArgumentType, CollapsedRequest<ResponseType, RequestArgumentType>>();

  当执行批量请求方法时,遍历存储的CollapsedRequest对象,通过commandCollapser的createObservableCommand方法创建执行批量请求的命令,通过commandCollapser的mapResponseToRequests方法将执行结果和请求进行匹配。

try {
// shard batches
Collection<Collection<CollapsedRequest<ResponseType, RequestArgumentType>>> shards = commandCollapser.shardRequests(argumentMap.values());
// for each shard execute its requests
for (final Collection<CollapsedRequest<ResponseType, RequestArgumentType>> shardRequests : shards) {
try {
// create a new command to handle this batch of requests
Observable<BatchReturnType> o = commandCollapser.createObservableCommand(shardRequests); commandCollapser.mapResponseToRequests(o, shardRequests)
...

  

hystrix源码之请求合并的更多相关文章

  1. hystrix源码之请求缓存

    HystrixRequestCache 请求缓存.内部是一个静态ConcurrentHashMap存储各个命令的缓存器,RequestCacheKey为key,HystrixRequestCache为 ...

  2. 第三篇:白话tornado源码之请求来了

    上一篇<白话tornado源码之待请求阶段>中介绍了tornado框架在客户端请求之前所做的准备(下图1.2部分),本质上就是创建了一个socket服务端,并进行了IP和端口的绑定,但是未 ...

  3. 【一起学源码-微服务】Hystrix 源码一:Hystrix基础原理与Demo搭建

    说明 原创不易,如若转载 请标明来源! 欢迎关注本人微信公众号:壹枝花算不算浪漫 更多内容也可查看本人博客:一枝花算不算浪漫 前言 前情回顾 上一个系列文章讲解了Feign的源码,主要是Feign动态 ...

  4. Hystrix源码解析

    1. Hystrix源码解析 1.1. @HystrixCommand原理 直接通过Aspect切面来做的 1.2. feign hystrix原理 它的本质原理就是对HystrixCommand的动 ...

  5. Tomcat源码分析——请求原理分析(下)

    前言 本文继续讲解TOMCAT的请求原理分析,建议朋友们阅读本文时首先阅读过<TOMCAT源码分析——请求原理分析(上)>和<TOMCAT源码分析——请求原理分析(中)>.在& ...

  6. Tomcat源码分析——请求原理分析(中)

    前言 在<TOMCAT源码分析——请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT源码分析——请求原 ...

  7. Tomcat源码分析——请求原理分析(上)

    前言 谈起Tomcat的诞生,最早可以追溯到1995年.近20年来,Tomcat始终是使用最广泛的Web服务器,由于其使用Java语言开发,所以广为Java程序员所熟悉.很多人早期的J2EE项目,由程 ...

  8. 浅谈flask源码之请求过程

    更新时间:2018年07月26日 09:51:36   作者:Dear.   我要评论   这篇文章主要介绍了浅谈flask源码之请求过程,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随 ...

  9. hystrix源码之概述

    概述 hystrix核心原理是通过代理执行用户命令,记录命令执行的metrics信息,通过这些metrics信息进行降级和熔断. 源码结构包括一下几个部分: 熔断器 熔断器就是hystrix用来判断调 ...

随机推荐

  1. 《Head First 设计模式》:适配器模式

    正文 一.定义 适配器模式将一个类的接口(被适配者),转换成客户期望的另一个接口.适配器让原本接口不兼容的类可以合作无间. 要点: 适配器实现了目标接口,并持有被适配者的实例. 适配器使用被适配者的方 ...

  2. JavaScript学习系列博客_31_JavaScript Math 工具类

    Math - Math属于一个工具类,它不需要我们创建对象(例如Date日期对象需要通过构造函数创建对象 var 变量=new Date(),Math不需要),它里边封装了属性运算相关的常量和方法 我 ...

  3. Java 添加条码、二维码到PDF文档

    本文介绍如何通过Java程序在PDF文档中添加条码和二维码.创建条码时,可创建多种不同类型的条码,包括Codebar.Code11.Code128A.Code128B.Code32.Code39.Co ...

  4. 《Python 测试开发技术栈—巴哥职场进化记》—每日站会的意义

    上文<Python测试开发技术栈-巴哥职场进化记>-一道作业题我们讲到华哥给巴哥出了一道作业题,让巴哥用Python实现记录日志的功能,巴哥历经"千辛万苦",终于做出了 ...

  5. nova 云主机 evacuate 简单分析

    原文链接:http://www.ishenping.com/ArtInfo/3318250.html #故障节点compute=down nova host-evacuate ostack245.bj ...

  6. Linux的CentOs系统查看CPU个数、核心数、线程数

    1.查看CPU物理个数 grep 'physical id' /proc/cpuinfo | sort -u | wc -l 或 cat /proc/cpuinfo| grep "physi ...

  7. Java 8新特性(一):Lambda表达式

    2014年3月发布的Java 8,有可能是Java版本更新中变化最大的一次.新的Java 8为开发者带来了许多重量级的新特性,包括Lambda表达式,流式数据处理,新的Optional类,新的日期和时 ...

  8. 网站会不会因为同IP网站被K而受到惩罚

    http://www.wocaoseo.com/thread-289-1-1.html 使用虚拟主机的网站会不会因为同一个IP或同一台服务器上有其他网站作弊被处罚而受连累,也被惩罚? 复制代码 百度官 ...

  9. 使用BeetleX在Linux下部署.NET多站点服务

    ​      在windows下常用IIS来部署.NET的多站点服务,但在Linux下就没这么方便了:虽然可以使用一些代理服务器如nginx,jexus等来反代或部署应用,但nginx对.NET应用的 ...

  10. 树叶婆娑 shader

    效果是树叶摇曳: Shader "LeafAnim" { Properties { _MainTex ("Base (RGB)", 2D) = "wh ...