在《Hystrix-执行流程》中,我们说到在执行command的时候会先检查是否开启缓存,若开启缓存,且缓存中有数据时,就直接返回结果。今天,我们就通过实战看下这说的是什么意思。
一、创建command
重写getCacheKey方法,返回一个String类型的值作为缓存的key。
public class CommandUsingRequestCache extends HystrixCommand<Boolean> {
private final int value;
protected CommandUsingRequestCache(int value) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.value = value;
}
@Override
protected Boolean run() {
return value == 0 || value % 2 == 0;
}
@Override
protected String getCacheKey() {
return String.valueOf(value);
}
}
二、执行command
public class CommandUsingRequestCacheTest {
public void testWithCacheHits() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
CommandUsingRequestCache commanda = new CommandUsingRequestCache(2);
CommandUsingRequestCache commandb = new CommandUsingRequestCache(2);
System.out.println("commandc execute result:" + commanda.execute());
System.out.println("commandc is from cache:" + commanda.isResponseFromCache());
System.out.println("-------------------------------------------");
System.out.println("commandc execute result:" + commandb.execute());
System.out.println("commandc is from cache:" + commandb.isResponseFromCache());
System.out.println("-------------------------------------------");
} finally {
context.shutdown();
}
context = HystrixRequestContext.initializeContext();
try {
CommandUsingRequestCache commandc = new CommandUsingRequestCache(2);
System.out.println("commandc execute result:" + commandc.execute());
System.out.println("commandc is from cache:" + commandc.isResponseFromCache());
} finally {
context.shutdown();
}
}
public static void main(String[] args) {
CommandUsingRequestCacheTest test = new CommandUsingRequestCacheTest();
test.testWithCacheHits();
}
}
三、执行结果
四、总结
从上诉执行结果我们可以看到,第一次执行isResponseFromCache方法返回false,即表示不是从缓存中获取的数据。第二次为true表示从缓存中直接返回结果。第三次返回false,理论上来说2已经在缓存中,但为什么这里返回false?原来,在Hystrix中有一个概念,叫做请求上下文,即HystrixRequestContext。commanda和commandb在同一个请求上下文中,所以当commandb再次访问时,就会直接取用缓存中的数据。但是commandb执行结束之后,我们关闭了上下文,在执行commandc之前重新创建了一个上下文,此时上下文中缓存数据是为空的,这就解释了为什么commandc.isResponseFromCache()返回的结果为false了。
一般来说,在一个web应用中,我们会在一个filter里面,对每一个请求都施加一个请求上下文,就是说tomcat容器内每一次请求就是一次请求上下文。然后在这次请求上下文中,我们会去执行N多代码,调用N多依赖服务,有的依赖服务可能还会调用好几次。在一次请求上下文中,如果有多个command,参数都是一样的,调用的接口也是一样的,其实结果可以认为也是一样的。那么这个时候,我们就可以让第一次command执行,返回的结果,被缓存在内存中,然后这个请求上下文中,后续的其他对这个依赖的调用全部从内存中取用缓存结果就可以了。不用在一次请求上下文中反复多次的执行一样的command,提升整个请求的性能。