hystrix源码之请求合并
请求合并
使用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源码之请求合并的更多相关文章
- hystrix源码之请求缓存
HystrixRequestCache 请求缓存.内部是一个静态ConcurrentHashMap存储各个命令的缓存器,RequestCacheKey为key,HystrixRequestCache为 ...
- 第三篇:白话tornado源码之请求来了
上一篇<白话tornado源码之待请求阶段>中介绍了tornado框架在客户端请求之前所做的准备(下图1.2部分),本质上就是创建了一个socket服务端,并进行了IP和端口的绑定,但是未 ...
- 【一起学源码-微服务】Hystrix 源码一:Hystrix基础原理与Demo搭建
说明 原创不易,如若转载 请标明来源! 欢迎关注本人微信公众号:壹枝花算不算浪漫 更多内容也可查看本人博客:一枝花算不算浪漫 前言 前情回顾 上一个系列文章讲解了Feign的源码,主要是Feign动态 ...
- Hystrix源码解析
1. Hystrix源码解析 1.1. @HystrixCommand原理 直接通过Aspect切面来做的 1.2. feign hystrix原理 它的本质原理就是对HystrixCommand的动 ...
- Tomcat源码分析——请求原理分析(下)
前言 本文继续讲解TOMCAT的请求原理分析,建议朋友们阅读本文时首先阅读过<TOMCAT源码分析——请求原理分析(上)>和<TOMCAT源码分析——请求原理分析(中)>.在& ...
- Tomcat源码分析——请求原理分析(中)
前言 在<TOMCAT源码分析——请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT源码分析——请求原 ...
- Tomcat源码分析——请求原理分析(上)
前言 谈起Tomcat的诞生,最早可以追溯到1995年.近20年来,Tomcat始终是使用最广泛的Web服务器,由于其使用Java语言开发,所以广为Java程序员所熟悉.很多人早期的J2EE项目,由程 ...
- 浅谈flask源码之请求过程
更新时间:2018年07月26日 09:51:36 作者:Dear. 我要评论 这篇文章主要介绍了浅谈flask源码之请求过程,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随 ...
- hystrix源码之概述
概述 hystrix核心原理是通过代理执行用户命令,记录命令执行的metrics信息,通过这些metrics信息进行降级和熔断. 源码结构包括一下几个部分: 熔断器 熔断器就是hystrix用来判断调 ...
随机推荐
- PythonCrashCourse 第七章习题
编写一个程序,询问用户要租赁什么样的汽车,并打印一条消息,如"Let me see if I can find you a Subaru" car =input("Wha ...
- CentOS 7.3安装指南
下载CentOs 7.3 1.ISO 镜像启动完成后,你机器上会显示如下首屏.在菜单中选择 “Install CentOS 7”并按下回车继续. 2.在安装镜像加载到内存完成后,会显示一个欢迎页面.选 ...
- Java中实现十进制数转换为二进制的三种方法
第一种:除基倒取余法 这是最符合我们平时的数学逻辑思维的,即输入一个十进制数n,每次用n除以2,把余数记下来,再用商去除以2...依次循环,直到商为0结束,把余数倒着依次排列,就构成了转换后的二进制数 ...
- 分块练习C. interval
分块练习C. interval 题目描述 \(N\)个数\(a_i\),\(m\)个操作 \(1\). 从第一个数开始,每隔\(k_i\)个的位置上的数增加\(x_i\) \(2\). 查询\(l\) ...
- Vue的数据响应式
getter和setter怎么用 示例代码 getter ,关键词为 get ,用于获取一个值.定义时为函数,但是使用时不用加括号. setter 用于对数据的改写 Object.defineProp ...
- JavaScript 的诞生
JavaScript的历史 网景 1993年出现网页浏览器NCSA Mosaic 1994年出现Netscape Navigator,并占据四分之三浏览器市场 1995年5月布兰登根据公司的要求发明一 ...
- IDEA的主题配置
搞了半天的主题配色,从一些现有的主题网站上想找按照sublime中monokai进行复刻的主题,都没有找到一样的,部分的颜色还会让人看不清楚,这里分享一下自定义主题的方法,和自己配置好的一个主题吧. ...
- python+opencv 打开网络摄像头
python+opencv 打开网络摄像头(手机)(转) #以下是最常用的读取视频流的方法import cv2url = 'rtsp://admin:admin@192.169.5.2:554/'#根 ...
- ajax请求默认都是异步请求,怎么变为同步请求
Ajax请求默认的都是异步的 如果想同步 async设置为false就可以(默认是true) var html = $.ajax({ url: "some.PHP", as ...
- LeetCode 95 | 构造出所有二叉搜索树
今天是LeetCode专题第61篇文章,我们一起来看的是LeetCode95题,Unique Binary Search Trees II(不同的二叉搜索树II). 这道题的官方难度是Medium,点 ...