hystrix 源码学习

demo 演示

    @HystrixCommand(
            groupKey = "thread-control1",
            fallbackMethod = "failback",
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"), 
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100"), //超时时间
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "50"),//触发熔断最小请求数量
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "30"),//触发熔断的错误占比阈值
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "3000"),//熔断器回复时间
                    @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "300"),// 单机最高并发
                    @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "100")// fallback单机最高并发
            }
    )
    public String call() {
        System.out.println("main run start:" + System.currentTimeMillis());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            System.out.println("thead interruptedException");
        }
        System.out.println("main run end:" + System.currentTimeMillis());
        return "main return";

    }

    public String failback() {
        System.out.println("failback run:" + System.currentTimeMillis());
        return "failback return";
    }
    /**
     * @return
     */
    @HystrixCommand(
            fallbackMethod = "fallback" ,
            groupKey = "thread-control2",
            commandProperties = {
                    @HystrixProperty(name="execution.isolation.strategy", value="THREAD"),
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000"), //超时时间
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value="20"),//触发熔断最小请求数量
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value="50"),//触发熔断的错误占比阈值
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value="5000"),//熔断器回复时间
                    @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value="300")
            },
            threadPoolProperties = {
                    @HystrixProperty(name = "coreSize", value = "123"), //核心线程数,当前版本不支持显示设置最大线程数,最大线程数=核心线程数
                    @HystrixProperty(name = "maxQueueSize", value = "1000"),
                    @HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
                    @HystrixProperty(name = "queueSizeRejectionThreshold", value = "50"),
            }
    )
    public String call2(){
        System.out.println("main run start:" + System.currentTimeMillis());

        try {
            System.out.println("线程池:" + ThreadLocalTest.get());
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            System.out.println("InterruptedException");
        }
        System.out.println("main run end:" + System.currentTimeMillis());
        return "main return";
    }

    public String fallback() {
        System.out.println("callback run:" + System.currentTimeMillis());
        return "fallback return";
    }

信号量

信号量流程图

private Observable<R> applyHystrixSemantics(final AbstractCommand<R> _cmd) {
    // mark that we're starting execution on the ExecutionHook
    // if this hook throws an exception, then a fast-fail occurs with no fallback.  No state is left inconsistent
    executionHook.onStart(_cmd);

    /* determine if we're allowed to execute */
    // 断路器check是否熔断
    if (circuitBreaker.allowRequest()) {
         // 获取信号量控制器
        // 信号量策略在这里控制,线程池策略则会返回一个空的默认控制器
        final TryableSemaphore executionSemaphore = getExecutionSemaphore();
        final AtomicBoolean semaphoreHasBeenReleased = new AtomicBoolean(false);
        // 信号量释放回调
        final Action0 singleSemaphoreRelease = new Action0() {
            @Override
            public void call() {
                if (semaphoreHasBeenReleased.compareAndSet(false, true)) {
                    executionSemaphore.release();
                }
            }
        };

        final Action1<Throwable> markExceptionThrown = new Action1<Throwable>() {
            @Override
            public void call(Throwable t) {
                eventNotifier.markEvent(HystrixEventType.EXCEPTION_THROWN, commandKey);
            }
        };
        // 尝试获取信号量,成功则进入,失败则进入fallback
        if (executionSemaphore.tryAcquire()) {
            try {
                /* used to track userThreadExecutionTime */
                executionResult = executionResult.setInvocationStartTime(System.currentTimeMillis());
                // 执行命令
                return executeCommandAndObserve(_cmd)
                        .doOnError(markExceptionThrown)
                        .doOnTerminate(singleSemaphoreRelease)
                        .doOnUnsubscribe(singleSemaphoreRelease);
            } catch (RuntimeException e) {
                return Observable.error(e);
            }
        } else {
            return handleSemaphoreRejectionViaFallback();
        }
    } else {
        return handleShortCircuitViaFallback();
    }
}

线程池

线程池流程图

return Observable.defer(new Func0<Observable<R>>() {
    @Override
    public Observable<R> call() {
        executionResult = executionResult.setExecutionOccurred();
        // 判断命令此时的状态
        if (!commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.USER_CODE_EXECUTED)) {
            return Observable.error(new IllegalStateException("execution attempted while in state : " + commandState.get().name()));
        }

        metrics.markCommandStart(commandKey, threadPoolKey, ExecutionIsolationStrategy.THREAD);
        // 判断命令此时的状态
        if (isCommandTimedOut.get() == TimedOutStatus.TIMED_OUT) {
            // the command timed out in the wrapping thread so we will return immediately
            // and not increment any of the counters below or other such logic
            return Observable.error(new RuntimeException("timed out before executing run()"));
        }
        if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.STARTED)) {
            //we have not been unsubscribed, so should proceed
            HystrixCounters.incrementGlobalConcurrentThreads();
            threadPool.markThreadExecution();
            // store the command that is being run
            endCurrentThreadExecutingCommand = Hystrix.startCurrentThreadExecutingCommand(getCommandKey());
            executionResult = executionResult.setExecutedInThread();
            /**
             * If any of these hooks throw an exception, then it appears as if the actual execution threw an error
             */
            try {
                executionHook.onThreadStart(_cmd);
                executionHook.onRunStart(_cmd);
                executionHook.onExecutionStart(_cmd);
                return getUserExecutionObservable(_cmd);
            } catch (Throwable ex) {
                return Observable.error(ex);
            }
        } else {
            //command has already been unsubscribed, so return immediately
            return Observable.error(new RuntimeException("unsubscribed before executing run()"));
        }
    }
}).doOnTerminate(new Action0() {
    @Override
    public void call() {
        if (threadState.compareAndSet(ThreadState.STARTED, ThreadState.TERMINAL)) {
            handleThreadEnd(_cmd);
        }
        if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.TERMINAL)) {
            //if it was never started and received terminal, then no need to clean up (I don't think this is possible)
        }
        //if it was unsubscribed, then other cleanup handled it
    }
}).doOnUnsubscribe(new Action0() {
    @Override
    public void call() {
        if (threadState.compareAndSet(ThreadState.STARTED, ThreadState.UNSUBSCRIBED)) {
            handleThreadEnd(_cmd);
        }
        if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.UNSUBSCRIBED)) {
            //if it was never started and was cancelled, then no need to clean up
        }
        //if it was terminal, then other cleanup handled it
    }
    // 设置rxjava为异步执行,将线程池设置进去。
    // 线程池策略的job在此线程中提交
}).subscribeOn(threadPool.getScheduler(new Func0<Boolean>() {
    @Override
    public Boolean call() {
        return properties.executionIsolationThreadInterruptOnTimeout().get() && _cmd.isCommandTimedOut.get() == TimedOutStatus.TIMED_OUT;
    }
}));

线程池扩展

public class HystrixThreadPoolPluginRegister {

    static {
        // 定制hystric线程池插件
        HystrixPlugins.getInstance().registerConcurrencyStrategy(new TraceHystrixConcurrencyStrategy());
    }
}

failback线程池策略

com.netflix.hystrix.util.HystrixTimer#addTimerListener
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);
}

线程池大小配置

public abstract class HystrixTimerThreadPoolProperties {

    private final HystrixProperty<Integer> corePoolSize;

    protected HystrixTimerThreadPoolProperties() {
        this(new Setter().withCoreSize(Runtime.getRuntime().availableProcessors()));
    }

    protected HystrixTimerThreadPoolProperties(Setter setter) {
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值