zoukankan      html  css  js  c++  java
  • Hystrix框架5--请求缓存和collapser

    简介

    在Hystrix中有个Request的概念,有一些操作需要在request中进行

    缓存

    在Hystrix调用服务时,如果只是查询接口,可以使用缓存进行优化,从而跳过真实访问请求。

    应用

    需要启用缓存的话需要重写command中getCacheKey方法

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

    之后就可以调用了
    但是如果直接调用command的运行相关方法会得到以下错误

    Caused by: java.lang.IllegalStateException: Request caching is not available. Maybe you need to initialize the HystrixRequestContext?
    

    这里说需要初始化HystrixRequestContext,在Hystrix中带缓存的command是必须在request中调用的。

    public void testWithCacheHits() {
    	//初始化context
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        try {
    		//两个一样的command
            CommandUsingRequestCache command2a = new CommandUsingRequestCache(2);
            CommandUsingRequestCache command2b = new CommandUsingRequestCache(2);
    		
            assertTrue(command2a.execute());
            // 第一次调用的返回是否从cache获得是false
            assertFalse(command2a.isResponseFromCache());
    
            assertTrue(command2b.execute());
            // 第而次调用的返回是否从cache获得是true
            assertTrue(command2b.isResponseFromCache());
        } finally {
    		//关闭context
            context.shutdown();
        }
    }
    

    在不同context中的缓存是不共享的,还有这个request内部一个ThreadLocal,所以request只能限于当前线程

    更新缓存

    如果服务同时有更新的操作,那么在request中需要将原先的缓存失效

    public static class GetterCommand extends HystrixCommand<String> {
    	//getter key 用于命名当前command,之后清楚缓存时需要
        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() {
            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静态方法中找到对应实例,并将响应值清除
            HystrixRequestCache.getInstance(GETTER_KEY,
                    HystrixConcurrencyStrategyDefault.getInstance()).clear(String.valueOf(id));
        }
    }
    

    Collapser

    Collapser可以合并多个请求一起调用

    //需要定义一个Collapser
    public class CommandCollapserGetValueForKey extends HystrixCollapser<List<String>, String, Integer> {
    
        private final Integer key;
    
        public CommandCollapserGetValueForKey(Integer key) {
            this.key = key;
        }
    
        @Override
        public Integer getRequestArgument() {
            return key;
        }
    
        @Override
        protected HystrixCommand<List<String>> createCommand(final Collection<CollapsedRequest<String, Integer>> requests) {
            return new BatchCommand(requests);
        }
    
        @Override
        protected void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, Integer>> requests) {
            int count = 0;
            for (CollapsedRequest<String, Integer> request : requests) {
                request.setResponse(batchResponse.get(count++));
            }
        }
    	//底层command实现
        private static final class BatchCommand extends HystrixCommand<List<String>> {
            private final Collection<CollapsedRequest<String, Integer>> requests;
    
            private BatchCommand(Collection<CollapsedRequest<String, Integer>> requests) {
                    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
                        .andCommandKey(HystrixCommandKey.Factory.asKey("GetValueForKey")));
                this.requests = requests;
            }
    		//内部还是遍历入参进行调用
            @Override
            protected List<String> run() {
                ArrayList<String> response = new ArrayList<String>();
                for (CollapsedRequest<String, Integer> request : requests) {
                    // artificial response for each argument received in the batch
                    response.add("ValueForKey: " + request.getArgument());
                }
                return response;
            }
        }
    }
    
    @Test
    public void testCollapser() throws Exception {
        //初始化request
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        try {
    		//直接调用collapser
            Future<String> f1 = new CommandCollapserGetValueForKey(1).queue();
            Future<String> f2 = new CommandCollapserGetValueForKey(2).queue();
            Future<String> f3 = new CommandCollapserGetValueForKey(3).queue();
            Future<String> f4 = new CommandCollapserGetValueForKey(4).queue();
    
            assertEquals("ValueForKey: 1", f1.get());
            assertEquals("ValueForKey: 2", f2.get());
            assertEquals("ValueForKey: 3", f3.get());
            assertEquals("ValueForKey: 4", f4.get());
    		//只调用了一次command
            // assert that the batch command 'GetValueForKey' was in fact
            // executed and that it executed only once
            assertEquals(1, HystrixRequestLog.getCurrentRequest().getExecutedCommands().size());
            HystrixCommand<?> command = HystrixRequestLog.getCurrentRequest().getExecutedCommands().toArray(new HystrixCommand<?>[1])[0];
            // assert the command is the one we're expecting
            assertEquals("GetValueForKey", command.getCommandKey().name());
            // confirm that it was a COLLAPSED command execution
            assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));
            // and that it was successful
            assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));
        } finally {
            //关闭request
            context.shutdown();
        }
    }
    

    Collapser可以用来一起调用一批请求,在第一个调用get时会对积压的command一起调用。

    总结

    Hystrix的Request主要就是cache和collapser用到。在一般web应用中可以在filter中加入context的初始化和关闭逻辑。还要注意request是不支持跨线程。

  • 相关阅读:
    python调用WebService遇到的问题'Document' object has no attribute 'set'
    jquery AJAX 拦截器 success error
    js 钩子(hook)
    js 继承
    js Object的复制
    js关于 indexOf
    js重排序,笔记
    js类型检测,笔记
    jquery源码的阅读理解
    Windows IPC 连接详解(转)
  • 原文地址:https://www.cnblogs.com/resentment/p/5914390.html
Copyright © 2011-2022 走看看