hystrix源码之请求缓存
HystrixRequestCache
请求缓存。内部是一个静态ConcurrentHashMap存储各个命令的缓存器,RequestCacheKey为key,HystrixRequestCache为value。
private final static ConcurrentHashMap<RequestCacheKey, HystrixRequestCache> caches = new ConcurrentHashMap<RequestCacheKey, HystrixRequestCache>();
RequestCacheKey由两部分组成:当前command的keyname,指定HystrixConcurrencyStrategy对象。
private static class RequestCacheKey {
private final short type; // used to differentiate between Collapser/Command if key is same between them
private final String key;
private final HystrixConcurrencyStrategy concurrencyStrategy;
private RequestCacheKey(HystrixCommandKey commandKey, HystrixConcurrencyStrategy concurrencyStrategy) {
type = 1;
if (commandKey == null) {
this.key = null;
} else {
this.key = commandKey.name();
}
this.concurrencyStrategy = concurrencyStrategy;
}
...
}
通过getInstance来获取每个命令的缓冲器。
public static HystrixRequestCache getInstance(HystrixCommandKey key, HystrixConcurrencyStrategy concurrencyStrategy) {
return getInstance(new RequestCacheKey(key, concurrencyStrategy), concurrencyStrategy);
}
public static HystrixRequestCache getInstance(HystrixCollapserKey key, HystrixConcurrencyStrategy concurrencyStrategy) {
return getInstance(new RequestCacheKey(key, concurrencyStrategy), concurrencyStrategy);
}
private static HystrixRequestCache getInstance(RequestCacheKey rcKey, HystrixConcurrencyStrategy concurrencyStrategy) {
HystrixRequestCache c = caches.get(rcKey);
if (c == null) {
HystrixRequestCache newRequestCache = new HystrixRequestCache(rcKey, concurrencyStrategy);
HystrixRequestCache existing = caches.putIfAbsent(rcKey, newRequestCache);
if (existing == null) {
// we won so use the new one
c = newRequestCache;
} else {
// we lost so use the existing
c = existing;
}
}
return c;
}
HystrixRequestCache提供了get来获取指定key缓存,提供了putIfAbsent来存储指定key的缓存内容。内部是一个ConcurrentHashMap存储缓存内容,ValueCacheKey为key,HystrixCachedObservable为value。缓存的内容是请求级别共享的,所以放在一个HystrixRequestVariableHolder中。
private static final HystrixRequestVariableHolder<ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>> requestVariableForCache = new HystrixRequestVariableHolder<ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>>(new HystrixRequestVariableLifecycle<ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>>() {
@Override
public ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> initialValue() {
return new ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>();
}
@Override
public void shutdown(ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> value) {
// nothing to shutdown
}
});
ValueCacheKey由三部分组成:RequestCacheKey对象和指定String类型 key。
private static class ValueCacheKey {
private final RequestCacheKey rvKey;
private final String valueCacheKey;
private ValueCacheKey(RequestCacheKey rvKey, String valueCacheKey) {
this.rvKey = rvKey;
this.valueCacheKey = valueCacheKey;
}
...
}
get和putIfAbsent方法
@SuppressWarnings({ "unchecked" })
/* package */<T> HystrixCachedObservable<T> get(String cacheKey) {
ValueCacheKey key = getRequestCacheKey(cacheKey);
if (key != null) {
ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> cacheInstance = requestVariableForCache.get(concurrencyStrategy);
if (cacheInstance == null) {
throw new IllegalStateException("Request caching is not available. Maybe you need to initialize the HystrixRequestContext?");
}
/* look for the stored value */
return (HystrixCachedObservable<T>) cacheInstance.get(key);
}
return null;
}
@SuppressWarnings({ "unchecked" })
/* package */<T> HystrixCachedObservable<T> putIfAbsent(String cacheKey, HystrixCachedObservable<T> f) {
ValueCacheKey key = getRequestCacheKey(cacheKey);
if (key != null) {
/* look for the stored value */
ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> cacheInstance = requestVariableForCache.get(concurrencyStrategy);
if (cacheInstance == null) {
throw new IllegalStateException("Request caching is not available. Maybe you need to initialize the HystrixRequestContext?");
}
HystrixCachedObservable<T> alreadySet = (HystrixCachedObservable<T>) cacheInstance.putIfAbsent(key, f);
if (alreadySet != null) {
// someone beat us so we didn't cache this
return alreadySet;
}
}
// we either set it in the cache or do not have a cache key
return null;
}
HystrixCachedObservable
内部使用了ReplaySubject缓存了originalObservable的结果
protected final Subscription originalSubscription;
protected final Observable<R> cachedObservable;
private volatile int outstandingSubscriptions = 0; protected HystrixCachedObservable(final Observable<R> originalObservable) {
ReplaySubject<R> replaySubject = ReplaySubject.create();
this.originalSubscription = originalObservable
.subscribe(replaySubject); this.cachedObservable = replaySubject
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
outstandingSubscriptions--;
if (outstandingSubscriptions == 0) {
originalSubscription.unsubscribe();
}
}
})
.doOnSubscribe(new Action0() {
@Override
public void call() {
outstandingSubscriptions++;
}
});
} public static <R> HystrixCachedObservable<R> from(Observable<R> o, AbstractCommand<R> originalCommand) {
return new HystrixCommandResponseFromCache<R>(o, originalCommand);
} public static <R> HystrixCachedObservable<R> from(Observable<R> o) {
return new HystrixCachedObservable<R>(o);
} public Observable<R> toObservable() {
return cachedObservable;
} public void unsubscribe() {
originalSubscription.unsubscribe();
}
HystrixCommandResponseFromCache
HystrixCachedObservable的子类,HystrixCommand实际使用来缓存结果的类。该类的作用是,当使用缓存结果时,会同步之前命令的运行结果
public class HystrixCommandResponseFromCache<R> extends HystrixCachedObservable<R> {
private final AbstractCommand<R> originalCommand;
/* package-private */ HystrixCommandResponseFromCache(Observable<R> originalObservable, final AbstractCommand<R> originalCommand) {
super(originalObservable);
this.originalCommand = originalCommand;
}
public Observable<R> toObservableWithStateCopiedInto(final AbstractCommand<R> commandToCopyStateInto) {
final AtomicBoolean completionLogicRun = new AtomicBoolean(false);
return cachedObservable
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
if (completionLogicRun.compareAndSet(false, true)) {
commandCompleted(commandToCopyStateInto);
}
}
})
.doOnCompleted(new Action0() {
@Override
public void call() {
if (completionLogicRun.compareAndSet(false, true)) {
commandCompleted(commandToCopyStateInto);
}
}
})
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
if (completionLogicRun.compareAndSet(false, true)) {
commandUnsubscribed(commandToCopyStateInto);
}
}
});
}
private void commandCompleted(final AbstractCommand<R> commandToCopyStateInto) {
commandToCopyStateInto.executionResult = originalCommand.executionResult;
}
private void commandUnsubscribed(final AbstractCommand<R> commandToCopyStateInto) {
commandToCopyStateInto.executionResult = commandToCopyStateInto.executionResult.addEvent(HystrixEventType.CANCELLED);
commandToCopyStateInto.executionResult = commandToCopyStateInto.executionResult.setExecutionLatency(-1);
}
}
hystrix源码之请求缓存的更多相关文章
- hystrix源码之请求合并
请求合并 使用HystrixObservableCollapser可以将参数不同,但执行过程相同的调用合并执行.当调用observe.toObservable方法时,会向RequestCollapse ...
- 【一起学源码-微服务】Hystrix 源码一:Hystrix基础原理与Demo搭建
说明 原创不易,如若转载 请标明来源! 欢迎关注本人微信公众号:壹枝花算不算浪漫 更多内容也可查看本人博客:一枝花算不算浪漫 前言 前情回顾 上一个系列文章讲解了Feign的源码,主要是Feign动态 ...
- 【转】MaBatis学习---源码分析MyBatis缓存原理
[原文]https://www.toutiao.com/i6594029178964673027/ 源码分析MyBatis缓存原理 1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 ...
- Tomcat源码分析——请求原理分析(中)
前言 在<TOMCAT源码分析——请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT源码分析——请求原 ...
- Mybatis源码手记-从缓存体系看责任链派发模式与循环依赖企业级实践
一.缓存总览 Mybatis在设计上处处都有用到的缓存,而且Mybatis的缓存体系设计上遵循单一职责.开闭原则.高度解耦.及其精巧,充分的将缓存分层,其独到之处可以套用到很多类似的业务上.这里将主要 ...
- 第三篇:白话tornado源码之请求来了
上一篇<白话tornado源码之待请求阶段>中介绍了tornado框架在客户端请求之前所做的准备(下图1.2部分),本质上就是创建了一个socket服务端,并进行了IP和端口的绑定,但是未 ...
- jQuery1.9.1源码分析--数据缓存Data模块
jQuery1.9.1源码分析--数据缓存Data模块 阅读目录 jQuery API中Data的基本使用方法介绍 jQuery.acceptData(elem)源码分析 jQuery.data(el ...
- lodash源码分析之缓存使用方式的进一步封装
在世界上所有的民族之中,支配着他们的喜怒选择的并不是天性,而是他们的观点. --卢梭<社会与契约论> 本文为读 lodash 源码的第九篇,后续文章会更新到这个仓库中,欢迎 star:po ...
- Hystrix源码解析
1. Hystrix源码解析 1.1. @HystrixCommand原理 直接通过Aspect切面来做的 1.2. feign hystrix原理 它的本质原理就是对HystrixCommand的动 ...
随机推荐
- Docker日常使用方式
前提 在安装docker之前,建议你设置系统的国内镜像源先哦,很快~嗯,快. 阿里云镜像源:https://developer.aliyun.com/mirror/ 安装 安装docker 下面都是官 ...
- three.js 制作逻辑转体游戏(上)
今天郭先生又出来制作游戏了,最近有小伙伴要做一个逻辑转体小游戏,我怎么能不先来试试呢.玩法可以看上面的连接,下面附几张图.线案例请点击博客原文. 游戏规则不懂得可以看自行百度哈,其实玩起来还挺有难度的 ...
- API、Win32 SDK、Win32项目、MFC、Windows窗体应用程序的区别
[原]API.Win32 SDK.Win32项目.MFC.Windows窗体应用程序的区别 首先来看一下每一个术语的定义: API:Application Programming Interface. ...
- [PyTorch 学习笔记] 1.2 Tensor(张量)介绍
本章代码: https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson1/tensor_introduce1.py https: ...
- cinder api启动过程源码分析
1.启动cinder-api服务 当你通过cinder-api命令(如:/usr/bin/cinder-api --config-file /etc/cinder/cinder.conf)启动api服 ...
- 发布 npm遇到的问题
npm publish 遇到 403 怎么办? 这说明你没有切换到 npm 原始源,那么你只需要用 npm config delete registry 删除淘宝源,然后再 publish. publ ...
- Mybatis动态语句
If元素If元素是简单的条件判断逻辑,满足制定条件时追加if元素的SQL,不满足条件时不追加,使用格式如下: <select ….> SQL语句1 <if test=“条件表达式”& ...
- Java数据结构——树、二叉树的理论知识汇总
通用树的理论知识 一.树的定义 由一个或多个(n>=0)节点组成的有限集合T,有且仅有一个节点称为根(root),当n>1时,其7余的节点为m(m>=0)个互不相交的有限集合T1,T ...
- 超市管理系统C语言
登录系统 # include <stdio.h> //头文件 # include <string.h> //字符串头文件 # include <stdlib.h> ...
- js实现树级递归,通过js生成tree树形菜单(递归算法)
方法封装: /** * 数据转换为树形(递归),示例:toTreeByRecursion(source, 'id', 'parentId', null, 'children') * @param {A ...