Hystrix-request cache(请求缓存)

开启请求缓存

  请求缓存在run()和construce()执行之前生效,所以可以有效减少不必要的线程开销。你可以通过实现getCachekey()方法来开启请求缓存。

package org.hope.hystrix.example.request.cache;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;

public class CommandUsingRequestCache extends HystrixCommand<Boolean> {
    private final int value;

    public CommandUsingRequestCache(int value) {
        super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
        this.value = value;
    }

    @Override
    protected Boolean run() throws Exception {
        return value == 0 || value % 2 == 0;
    }

    @Override
    protected String getCacheKey() {
        return String.valueOf(value);
    }
}

单元测试

package org.hope.hystrix.example.request.cache;

import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.hope.hystrix.example.request.cache.CommandUsingRequestCache;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class CommandUsingRequestCacheTest {

    @Test
    public void testWithoutCacheHits() {
        HystrixRequestContext cxt = HystrixRequestContext.initializeContext();
        try {
            assertTrue(new CommandUsingRequestCache(2).execute());
            assertTrue(new CommandUsingRequestCache(1).execute());
        } finally {
            cxt.shutdown();
        }
    }

    @Test
    public void testWithCacheHits() {
        HystrixRequestContext cxt = HystrixRequestContext.initializeContext();
        try {
            CommandUsingRequestCache command2a = new CommandUsingRequestCache(2);
            CommandUsingRequestCache command2b = new CommandUsingRequestCache(2);

            assertTrue(command2a.execute());
            // this is the first time we‘ve executed this command with the value of "2" so it should not be from cache
//            assertFalse(command2a.isResponseFromCache());
            System.out.println(command2a.isResponseFromCache());

            assertTrue(command2b.execute());
            // this is the second time we‘ve executed this command with the same value so it should return from cache
//            assertTrue(command2b.isResponseFromCache());
            System.out.println(command2b.isResponseFromCache());
        } finally {
            cxt.shutdown();
        }

        // start a new request context
        cxt = HystrixRequestContext.initializeContext();
        try {
            CommandUsingRequestCache command3b = new CommandUsingRequestCache(2);
            assertTrue(command3b.execute());
            // this is a new request context so this should not come from cache
//            assertFalse(command3b.isResponseFromCache());
            System.out.println(command3b.isResponseFromCache());
        } finally {
            cxt.shutdown();
        }
    }
}

清理失效缓存

package org.hope.hystrix.example.request.cache;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixRequestCache;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;

/**
 * 清理缓存
 */
public class CommandUsingRequestCacheInvalidation{

    private static volatile String prefixStoredOnRemoteDataStore = "ValueBeforeSet_";

    public static class GetterCommand extends HystrixCommand<String> {
        private static final HystrixCommandKey GETTER_KEY = HystrixCommandKey.Factory.asKey("GetterCommand");
        private final int id;
        public GetterCommand(int id) {
            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetSetGet")).andCommandKey(GETTER_KEY));
            this.id = id;
        }

        @Override
        protected String run() throws Exception {
            return prefixStoredOnRemoteDataStore + id;
        }

        @Override
        protected String getCacheKey() {
            return String.valueOf(id);
        }

        //Allow the cache to be flushed for this object.
        public static void flushCache(int id) {
            HystrixRequestCache.getInstance(GETTER_KEY, HystrixConcurrencyStrategyDefault.getInstance()).clear(String.valueOf(id));
        }

    }

    public static class SetterCommand extends HystrixCommand<Void> {
        private final int id;
        private final String prefix;

        public SetterCommand(int id, String prefix) {
            super(HystrixCommandGroupKey.Factory.asKey("GetSetGet"));
            this.id = id;
            this.prefix = prefix;
        }

        @Override
        protected Void run() throws Exception {
            // persist the value against the datastore
            prefixStoredOnRemoteDataStore = prefix;
            // flush the cache
            GetterCommand.flushCache(id);
            return null;
        }
    }

}

单元测试:

package org.hope.hystrix.example.request.cache;

import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.junit.Test;

/**
 * Created by lisen on 2017/12/27.
 */
public class CommandUsingRequestCacheInvalidationTest {

    @Test
    public void flushCacheTest() {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        System.out.println(new CommandUsingRequestCacheInvalidation.GetterCommand(1).execute());

        CommandUsingRequestCacheInvalidation.GetterCommand commandAgainstCache = new CommandUsingRequestCacheInvalidation.GetterCommand(1);

        System.out.println(commandAgainstCache.isResponseFromCache()); //false
        System.out.println(commandAgainstCache.execute());
        System.out.println(commandAgainstCache.isResponseFromCache()); //false
        // set the new value
        new CommandUsingRequestCacheInvalidation.SetterCommand(1, "ValueAfterSet_").execute();
        // fetch it again
        CommandUsingRequestCacheInvalidation.GetterCommand commandAfterSet = new CommandUsingRequestCacheInvalidation.GetterCommand(1);
        //the getter should return with the new prefix, not the value from cache
        System.out.println(commandAfterSet.isResponseFromCache());
        System.out.println(commandAfterSet.execute());
    }
}

注解的实现请求缓存

注解 描述 属性
@CacheResult 改注解用来标记请求命令返回的结果应该被缓存,它必须与@HystrixCommand注解结合使用 cacheKeyMethod
@CacheRemove 该注解用来让请求命令的缓存失效,失效的缓存根据定义的key决定 commandKey,cacheKeyMethod
@CacheKey
改注解用来在请求命令的参数上标记,使其作为缓存的Key值,如果没有标注则会使用所有参数。如果同时还使用了@CacheResult和

@CacheRemove注解的cacheKeyMethod方法指定缓存Key的生成,那么该注解将不会起作用

value

设置缓存

package org.hope.hystrix.example.request.cache;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import org.hope.hystrix.example.model.User;
import org.springframework.stereotype.Service;
@Service
public class RequestCacheAnnotation {

    /**
     *  返回的结果会置入请求缓存中,缓存的key值会使用所有的方法入参,
     *  也就是这里Long类型的id
     */
    @CacheResult
    @HystrixCommand
    public String getUserById(Long id) {
        return "你好" + id;
    }

    /**
     *  cacheKeyMethod可以为缓存指定具体的缓存key
     */
    @CacheResult(cacheKeyMethod = "getUserByIdCacheKey")
    @HystrixCommand
    public String getUserById2(Long id) {
        return "你好:" + id;
    }

    public String getUserByIdCacheKey(Long id) {
        return String.valueOf(id);
    }

    /**
     *  通过@CacheKey来定义具体的缓存Key。
     *  但是注意,@CacheKey的优先级比@CacheResult(cacheKeyMethod = "")的优先级低。
     *  如果已经使用了cacheKeyMethod指定缓存Key的生成函数,那么@CacheKey注解不会生效
     */
    @CacheResult
    @HystrixCommand
    public String getUserById3(@CacheKey("id") Long id) {
        return "你好:" + id;
    }

    /**
     *  @CacheKey还可以通过访问参数对象内部属性作为缓存key
     *  这里指定了User对象id属性作为缓存key
     */
    @CacheResult
    @HystrixCommand
    public String getUserById4(@CacheKey("id") User user) {
        return "你好" + user.getId();
    }

}

清理缓存

package org.hope.hystrix.example.request.cache;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import org.hope.hystrix.example.model.User;

public class RequestClearCacheAnnotation {

    @CacheResult
    @HystrixCommand
    public User getUserById(@CacheKey("id") Long id) {
        User u = new User();
        u.setId(id);
        return u;
    }

    /**
     * 用@CacheRemove来清理失效缓存,其中commandKey是必须指定的
     */
    @CacheRemove(commandKey = "getUserById")
    @HystrixCommand
    public void update(@CacheKey("id") User user) {
        User u = new User();
        u.setId(20L);
    }

    public String getUserById(User user) {
        return String.valueOf(user.getId());
    }
}

https://gitee.com/huayicompany/Hystrix-learn/tree/master/hystrix-example

参考:

[1]Github,https://github.com/Netflix/Hystrix/wiki/How-it-Works

[2] 《SpringCloud微服务实战》,电子工业出版社,翟永超

原文地址:https://www.cnblogs.com/happyflyingpig/p/8119754.html

时间: 2024-11-15 09:27:39

Hystrix-request cache(请求缓存)的相关文章

基于 request cache 请求缓存技术优化批量商品数据查询接口_一点课堂(多岸学院)

基于 request cache 请求缓存技术优化批量商品数据查询接口 Hystrix command 执行时 8 大步骤第三步,就是检查 Request cache 是否有缓存. 首先,有一个概念,叫做 Request Context 请求上下文,一般来说,在一个 web 应用中,如果我们用到了 Hystrix,我们会在一个 filter 里面,对每一个请求都施加一个请求上下文.就是说,每一次请求,就是一次请求上下文.然后在这次请求上下文中,我们会去执行 N 多代码,调用 N 多依赖服务,有的

Hystrix请求缓存

为什么要使用请求缓存这种策略,官方给出的答案是: Different code paths can execute Hystrix Commands without concern of duplicate work. 白话文大概就是:不同的调用方,可以不必去处理一些重复的操作 这种模式在一个大型系统中,可以屏蔽一些底层的逻辑,让调用方更加简介清晰: 如何实现: 1.首先重写Command的getCacheKey方法 protected String getCacheKey() { // 自定义

手动缓存Retrofit+OkHttp响应体,不再局限于Get请求缓存

转载请标明出处: http://blog.csdn.net/iamzgx/article/details/51764848 概括 这篇博客是接着上一篇博客学会Retrofit+OkHttp+RxAndroid三剑客的使用,让自己紧跟Android潮流的步伐,没看过的,建议看完上一篇再来看这篇.在上一篇博客中仅仅是简单的讲解了OkHttp的缓存问题,主要是通过http协议里面的control-cache控制缓存,而且是仅仅只能是Get请求才能缓存,如果Post请求OkHttp会让response返

缓存雪崩 Cache Avalanche 缓存穿透 Cache Penetration 缓存击穿 Hotspot Invalid

一.无处不在的缓存缓存在计算机系统是无处不在,在CPU层面有L1-L3的Cache,在Linux中有TLB加速虚拟地址和物理地址的转换,在应用层有Redis等内存数据库缓存.在浏览器有本地缓存.手机有本地文件缓存等等.可见,缓存在计算机系统中有非常重要的地位,主要作用就是提高响应速度.减少磁盘读取等,本文主要讨论在高并发系统中的缓存系统.一句话概括缓存系统在高并发系统中的地位的话,就是: 如果高并发系统是烤羊肉串,那么缓存系统就是那一撮孜然...... 二.高并发系统中的缓存 缓存系统的作用 缓

【报文】理解HTTP协议的Request/Response(请求响应)模型

[报文]理解HTTP协议的Request/Response(请求响应)模型 系列目录 [简介]"请求/响应"模型 http://www.cnblogs.com/engraver-lxw/p/7550514.html [原理]理解HTTP协议的Request/Response(请求响应)模型 http://www.cnblogs.com/engraver-lxw/p/7550691.html [报文]理解HTTP协议的Request/Response(请求响应)模型--当前 http:/

关于IE和edge浏览器中get请求缓存的坑。

主要是在一些使用到cookie的ajax场景中. 比如:Angularjs的$http({"url":url,"method":"GET",withCredentials":true}).success(function(){}) get请求无法得到正确数据的时候,先查看控制台. 如果该请求 from cache 或 来自缓存 你会发现该get请求的请求头为空. 这时就会向服务器发送空请求,导致服务器得不到你的cookie,从而无法根据

Android Xutils框架HttpUtil Get请求缓存问题

话说,今天和服务器开发人员小小的逗逼了一下,为啥呢? 话说今天有个"收藏产品"的请求接口,是get request的哦,我客户端写好接口后,点击"收藏按钮",返回"收藏成功",我又点了一下,尼玛居然还是"收藏成功",我再点一下,这下对了,返回给我"取消收藏成功",好吧,我又点了一下,彻底郁闷了,居然又是"取消收藏成功",这不是逗我的么? 于是我让服务器人员检查他的接口,是不是有啥幺蛾子,

 iOS 网络请求缓存:NSURLCache详解

我读过一些开源项目的网络请求缓存的代码,基本上都是采用在本地存文件的方式进行缓存.如果你打算在你的项目中加入网络请求的缓存,可能你并不需要自己造一个轮子,了解一下 NSURLCache 就足够.本文为大家接收的就是ios开发中的NSURLCache相关使用,一起来看看吧. 缓存 首先, NSURLCache 提供的是内存以及磁盘的综合缓存机制.许多文章谈到,使用NSURLCache 之前需要在 AppDelegate 中缓存空间的设置: - (BOOL)application:(UIApplic

System.Web.Caching.Cache类 缓存 各种缓存依赖

System.Web.Caching.Cache类 缓存 各种缓存依赖 Cache类,是一个用于缓存常用信息的类.HttpRuntime.Cache以及HttpContext.Current.Cache都是该类的实例. 一.属性 属性 说明 Count 获取存储在缓存中的项数. EffectivePercentagePhysicalMemoryLimit 获取在 ASP.NET 开始从缓存中移除项之前应用程序可使用的物理内存百分比. EffectivePrivateBytesLimit 获取可用