zoukankan      html  css  js  c++  java
  • Hystrix框架2--超时

    timeout

    在调用第三方服务时有些情况需要对服务响应时间进行把控,当超时的情况下进行fallback的处理
    下面来看下超时的案例

    public class CommandTimeout extends HystrixCommand<String> {
    
        private final String name;
    
        public CommandTimeout(String name) {
            super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
            this.name = name;
        }
    
        @Override
        protected String run()  {
        	System.out.println("aaaa");
        	try {
    			//sleep10秒强制超时,默认超时时间是1s
    			Thread.sleep(10000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
        	System.out.println("run end");
        	return "";
        }
        @Override
        protected String getFallback() {
            return "Hello Failure " + name + "!";
        }
    }
    

    接下来是测试方法

    @Test
    public void testSynchronous() throws InterruptedException {
    	System.out.println(new CommandHelloWorld("World").execute());
    }
    
    java.lang.InterruptedException: sleep interrupted
    	at java.lang.Thread.sleep(Native Method)
    	at hystrix.CommandHelloWorld.run(CommandHelloWorld.java:32)
    	at hystrix.CommandHelloWorld.run(CommandHelloWorld.java:1)
    	...
    run end
    Hello Failure World!
    

    可以看到sleep被强制interrupted,并且调用的输出也变成了fallback方法的返回值

    如何查看是哪里调用的interrupt方法

    这里顺便说下如何看是哪个方法调用的interrupt
    根据stackoverflow的一个答案,没有直接的方法来断点到interrupt的方法,只能通过在Thread的interrupt方法上打断点,再反向看栈信息得知哪里中断当前线程。

    如何改变timeout设置

    在HystrixCommand的够着方法中可以在第二个参数配置一个timeout的毫秒数

    public CommandHelloWorld(String name) {
        super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"),1000000000);
        this.name = name;
    }
    

    这个构造方法是在调用AbastractCommand的构造方法时将毫秒数配置在CommandProperties中,如下:

    super(group, null, null, null, null, HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(executionIsolationThreadTimeoutInMilliseconds), null, null, null, null, null, null);
    

    Hystrix的timeout是怎么运行的

    在运行对应的command时,Hystrix会通过HystrixObservableTimeoutOperator注册一个Timer到一个定时线程池中,当超时后会启用一个HystrixTimer线程来interruptCommand的执行

    //创建一个TimerListener
    public Reference<TimerListener> addTimerListener(final TimerListener listener) {
        startThreadIfNeeded();
        // add the listener
    
        Runnable r = new Runnable() {
    
            @Override
            public void run() {
                try {
                    listener.tick();
                } catch (Exception e) {
                    logger.error("Failed while ticking TimerListener", e);
                }
            }
        };
    	//通过ScheduledThreadPoolExecutor在到达超时时间时运行上面的listener.tick,而时间是从listener的getIntervalTimeInMilliseconds方法中获得的
        ScheduledFuture<?> f = executor.get().getThreadPool().scheduleAtFixedRate(r, listener.getIntervalTimeInMilliseconds(), listener.getIntervalTimeInMilliseconds(), TimeUnit.MILLISECONDS);
        //返回包含timer的Reference,在任务在规定时间内完成是用于cancel超时处理
    	return new TimerReference(listener, f);
    }
    //下面是上面listener的定义
    TimerListener listener = new TimerListener() {
    
        @Override
        public void tick() {
            // if we can go from NOT_EXECUTED to TIMED_OUT then we do the timeout codepath
            // otherwise it means we lost a race and the run() execution completed or did not start
    		//这里使用CAS的操作将将状态设置为TIME_OUT,使用CAS的原因是如果运行成功而timeout没有被取消时不会标记任务超时
            if (originalCommand.isCommandTimedOut.compareAndSet(TimedOutStatus.NOT_EXECUTED, TimedOutStatus.TIMED_OUT)) {
                // report timeout failure
                originalCommand.eventNotifier.markEvent(HystrixEventType.TIMEOUT, originalCommand.commandKey);
                // shut down the original request
    			//内部会取消当前并调用fallback
                s.unsubscribe();
                timeoutRunnable.run();
                //if it did not start, then we need to mark a command start for concurrency metrics, and then issue the timeout
            }
        }
    
        @Override
        public int getIntervalTimeInMilliseconds() {
    		//这里从command的配置中获得配置的超时时间
            return originalCommand.properties.executionTimeoutInMilliseconds().get();
        }
    };
    

    上面是Command超时后的处理操作,当Command在时间内完成时会调用TimeReference的clear方法,内部调用了future的cancel来取消timer的超时任务

    private static class TimerReference extends SoftReference<TimerListener> {
    
        private final ScheduledFuture<?> f;
    	//保存scheduledFuture
        TimerReference(TimerListener referent, ScheduledFuture<?> f) {
            super(referent);
            this.f = f;
        }
    
        @Override
        public void clear() {
            super.clear();
            // stop this ScheduledFuture from any further executions
    		//停止scheduledFuture
            f.cancel(false);
        }
    
    }
    
  • 相关阅读:
    python学习之老男孩python全栈第九期_day024知识点总结——单继承、多继承
    python学习之老男孩python全栈第九期_day023知识点总结——类和对象命名空间、组合
    校园管理系统 -- 登录部分
    cycloneii normal mode vs. arithmetic mode
    cycloneii LAB-wide signals
    关于Synthesis
    CycloneII lcell_comb 和 lcell_FF 的结构
    Verilog与VHDL的混合模块例化
    关于公式文件.eqn
    关于文本处理(1)
  • 原文地址:https://www.cnblogs.com/resentment/p/5892769.html
Copyright © 2011-2022 走看看