一文看懂Hystrix超时机制

2,444 阅读2分钟

Hystrix超时入口是在AbstractCommand类中,如图:

       Observable<R> execution;
        if (properties.executionTimeoutEnabled().get()) {
            execution = executeCommandWithSpecifiedIsolation(_cmd)
                    .lift(new HystrixObservableTimeoutOperator<R>(_cmd));
        } else {
            execution = executeCommandWithSpecifiedIsolation(_cmd);
        }

当我们的代码执行的时候会回调HystrixObservableTimeoutOperator.call()方法,超时的逻辑主要在这个方法中。

第一步:TimerListener listener = new TimerListener()创建了一个监听器,很明显这个监听器就是来监听我们的command是否超时的,那它是怎么判断我们的任务是否超时了呢?我们看他的tick()方法。

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
                        s.unsubscribe();

                        final HystrixContextRunnable timeoutRunnable = new HystrixContextRunnable(originalCommand.concurrencyStrategy, hystrixRequestContext, new Runnable() {

                            @Override
                            public void run() {
                                child.onError(new HystrixTimeoutException());
                            }
                        });


                        timeoutRunnable.run();
                        //if it did not start, then we need to mark a command start for concurrency metrics, and then issue the timeout
                    }

它的意思是,判断当前command的TimedOutStatus是否是NOT_EXECUTED,如果不是,则认为超时了,就把状态设置为TIMED_OUT,并抛出HystrixTimeoutException异常,如果是的话,则什么都不做。

第二步: final Reference<TimerListener> tl = HystrixTimer.getInstance().addTimerListener(listener); 获取单列的HystrixTimer,这里面维护了一个线程池ScheduledThreadPoolExecutor,我们老看看他的初始化方法initialize();

 HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();
            int coreSize = propertiesStrategy.getTimerThreadPoolProperties().getCorePoolSize().get();

            ThreadFactory threadFactory = null;
            if (!PlatformSpecific.isAppEngineStandardEnvironment()) {
                threadFactory = new ThreadFactory() {
                    final AtomicInteger counter = new AtomicInteger();

                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread(r, "HystrixTimer-" + counter.incrementAndGet());
                        thread.setDaemon(true);
                        return thread;
                    }

                };
            } else {
                threadFactory = PlatformSpecific.getAppEngineThreadFactory();
            }

            executor = new ScheduledThreadPoolExecutor(coreSize, threadFactory);
            initialized = true;

它构建了一个线程池ScheduledThreadPoolExecutor,默认的coreSize=8

第三步:HystrixTimer.addTimerListener() 这个方法会把之前创建好的TimerListener加入HystrixTimer中,并把TimerListener.tick()封装为一个Runnable扔到线程池里。

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);
                }
            }
        };

        ScheduledFuture<?> f = executor.get().getThreadPool().scheduleAtFixedRate(r, listener.getIntervalTimeInMilliseconds(), listener.getIntervalTimeInMilliseconds(), TimeUnit.MILLISECONDS);
        return new TimerReference(listener, f);
    }

listener.getIntervalTimeInMilliseconds()这个参数就是我们设置的超时时间,所以这个任务会在我们设置的超时时间之后运行,来判断timedOutStatus的状态。

第四步:任务执行完了,怎么清理呢?看下面

 private static class TimerReference extends SoftReference<TimerListener> {

        private final ScheduledFuture<?> f;

        TimerReference(TimerListener referent, ScheduledFuture<?> f) {
            super(referent);
            this.f = f;
        }

        @Override
        public void clear() {
            super.clear();
            // stop this ScheduledFuture from any further executions
            f.cancel(false);
        }

    }

f.cancel()就是清理Runnable的任务。 最后总结如图: enter description here