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微服務實戰》,電子工業出版社,翟永超


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM