1. 程式人生 > >【SpringCloud】HystrixCommand的threadPoolKey預設值及執行緒池初始化

【SpringCloud】HystrixCommand的threadPoolKey預設值及執行緒池初始化

關於threadPoolKey預設值的疑問

使用SpingCloud必然會用到Hystrix做熔斷降級,也必然會用到@HystrixCommand註解,@HystrixCommand註解可以配置的除了常用的groupKey、commandKey、fallbackMethod等,還有一個很關鍵的就是threadPoolKey,就是使用Hystrix執行緒隔離策略時的執行緒池Key

<span style="color:#000000"><code><span style="color:green">/**
 * This annotation used to specify some methods which should be processes as hystrix commands.
 */</span>
<span style="color:#2b91af">@Target</span>({ElementType.METHOD})
<span style="color:#2b91af">@Retention</span>(RetentionPolicy.RUNTIME)
<span style="color:#2b91af">@Inherited</span>
<span style="color:#2b91af">@Documented</span>
<span style="color:#0000ff">public</span> <span style="color:#2b91af">@interface</span> HystrixCommand {

    <span style="color:green">/**
     * The command group key is used for grouping together commands such as for reporting,
     * alerting, dashboards or team/library ownership.
     * <p/>
     * default => the runtime class name of annotated method
     *
     * <span style="color:gray">@return</span> group key
     */</span>
    String <span style="color:#a31515">groupKey</span>() <span style="color:#0000ff">default</span> "";

    <span style="color:green">/**
     * Hystrix command key.
     * <p/>
     * default => the name of annotated method. for example:
     * <code>
     *     ...
     *     <span style="color:gray">@HystrixCommand</span>
     *     public User getUserById(...)
     *     ...
     *     the command name will be: 'getUserById'
     * </code>
     *
     * <span style="color:gray">@return</span> command key
     */</span>
    String <span style="color:#a31515">commandKey</span>() <span style="color:#0000ff">default</span> "";

    <span style="color:green">/**
     * The thread-pool key is used to represent a
     * HystrixThreadPool for monitoring, metrics publishing, caching and other such uses.
     *
     * <span style="color:gray">@return</span> thread pool key
     */</span>
    String <span style="color:#a31515">threadPoolKey</span>() <span style="color:#0000ff">default</span> "";
    
    ......省略
}</code></span>

而使用中我們常常只指定fallbackMethod回退方法,而不會指定所有屬性,從@HystrixCommand的原始碼註釋來看

  • groupKey的預設值是使用@HystrixCommand標註的方法所在的類名
  • commandKey的預設值是@HystrixCommand標註的方法名,即每個方法會被當做一個HystrixCommand
  • threadPoolKey沒有預設值

但threadPoolKey卻沒有說明預設值,而threadPoolKey是和執行HystrixCommand的執行緒池直接相關的

所以我的疑問就是,threadPoolKey有預設值嗎? 預設值是什麼? 執行HystrixCommand的執行緒池又是怎麼初始化的? 可以動態調整嗎?

測試論證

測試程式碼

spring-cloud-example-consumer-ribbon-hystrix-threadpool

測試端點及方式

首先需要啟動 spring-cloud-example-eureka-server-standalone註冊中心 和 spring-cloud-example-simple-provider服務提供者

再啟動 spring-cloud-example-consumer-ribbon-hystrix-threadpool

測試端點

http://127.0.0.1:20006/testDefaultThreadPoolKey

http://127.0.0.1:20006/testDefaultThreadPoolKey2

testDefaultThreadPoolKey 和 testDefaultThreadPoolKey2 是同一個service的兩個方法,分別使用@HystrixCommand指定fallback方法

執行緒池大小設定為2,且不使用佇列暫存,服務提供方sleep 30秒,通過chrome多視窗呼叫 /testDefaultThreadPoolKey 端點

或同時呼叫 /testDefaultThreadPoolKey/testDefaultThreadPoolKey2 端點
通過大於執行緒池最大值的請求被執行緒池拒絕進入fallback,判斷執行緒池是方法級,還是類級的,以及threadPoolKey預設值

注意:

使用firefox瀏覽器測試有問題,多標籤頁必須等待一個GET請求完成,才能繼續下一個,測不出併發的效果。

一開始以為是程式上的限制,後來才發現是瀏覽器,使用chrome問題解決

執行緒池配置

<span style="color:#000000"><code>hystrix.threadpool.<span style="color:#0000ff">default</span>.coreSize = 2
hystrix.threadpool.<span style="color:#0000ff">default</span>.maximumSize = 2
hystrix.threadpool.<span style="color:#0000ff">default</span>.maxQueueSize = -1</code></span>

執行緒池的coreSizemaximumSize都設定為2(1.5.9版本後才新增maximumSize),且執行緒池佇列大小為-1,即使用SynchronousQueue

Hystrix執行緒池的其它屬性: Hystrix Thread Pool Properties

測試結果

chrome瀏覽器連續GET請求呼叫6次,分別呼叫3次 /testDefaultThreadPoolKey,3次 /testDefaultThreadPoolKey2,以綠色線問分隔,可見前兩次呼叫成功,後4次均直接拒絕,進入fallback

具體異常資訊為:

java.util.concurrent.RejectedExecutionException: Task [email protected] rejected from [email protected][Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 1]

執行緒池大小為2起到了作用,將大於併發數的請求拒絕了,並且無論是隻呼叫 /testDefaultThreadPoolKey,還是輪詢呼叫 /testDefaultThreadPoolKey 和 /testDefaultThreadPoolKey2 ,測試結果都是這樣。再根據hystrix執行緒的名字 hystrix-ConsumerRibbonHystrixThreadPoolService-n,可以猜想:Hystrix的 threadPoolKey是和hystrixCommand執行的類相關的,可能一個類使用一個執行緒池,所以兩個service方法才會共用執行緒池

原理分析

HystrixCommandAspect

首先,被@HystrixCommand註解標註的方法會被AOP攔截,具體邏輯在 HystrixCommandAspect

<span style="color:#000000"><code><span style="color:#0000ff">private</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">final</span> Map<HystrixPointcutType, MetaHolderFactory> META_HOLDER_FACTORY_MAP;

<span style="color:green">// 初始化用於處理 HystrixCommand 和 HystrixCollapser 的 MetaHolderFactory</span>
<span style="color:green">// HystrixCommand -- CommandMetaHolderFactory</span>
<span style="color:green">// HystrixCollapser -- CollapserMetaHolderFactory</span>
<span style="color:#0000ff">static</span> {
    META_HOLDER_FACTORY_MAP = ImmutableMap.<HystrixPointcutType, MetaHolderFactory>builder()
            .put(HystrixPointcutType.COMMAND, <span style="color:#0000ff">new</span> CommandMetaHolderFactory())
            .put(HystrixPointcutType.COLLAPSER, <span style="color:#0000ff">new</span> CollapserMetaHolderFactory())
            .build();
}


<span style="color:green">// HystrixCommand Pointcut切入點</span>
<span style="color:#2b91af">@Pointcut</span>(<span style="color:#a31515">"@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)"</span>)
<span style="color:#0000ff">public</span> <span style="color:#0000ff">void</span> <span style="color:#a31515">hystrixCommandAnnotationPointcut</span>() {
}

<span style="color:green">// HystrixCollapser Pointcut切入點</span>
<span style="color:#2b91af">@Pointcut</span>(<span style="color:#a31515">"@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)"</span>)
<span style="color:#0000ff">public</span> <span style="color:#0000ff">void</span> <span style="color:#a31515">hystrixCollapserAnnotationPointcut</span>() {
}

<span style="color:green">// HystrixCommand 和 HystrixCollapser 的環繞通知</span>
<span style="color:#2b91af">@Around</span>(<span style="color:#a31515">"hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()"</span>)
<span style="color:#0000ff">public</span> Object <span style="color:#a31515">methodsAnnotatedWithHystrixCommand</span>(<span style="color:#0000ff">final</span> ProceedingJoinPoint joinPoint) <span style="color:#0000ff">throws</span> Throwable {
    Method method = getMethodFromTarget(joinPoint);
    Validate.notNull(method, <span style="color:#a31515">"failed to get method from joinPoint: %s"</span>, joinPoint);
    <span style="color:#0000ff">if</span> (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
        <span style="color:#0000ff">throw</span> <span style="color:#0000ff">new</span> IllegalStateException(<span style="color:#a31515">"method cannot be annotated with HystrixCommand and HystrixCollapser "</span> +
                <span style="color:#a31515">"annotations at the same time"</span>);
    }
    
    <span style="color:green">// 建立metaHolder,用於儲存元資料</span>
    MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
    MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
    
    <span style="color:green">// 建立HystrixCommand,HystrixInvokable是父介面</span>
    HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
    ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
            metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();

    <span style="color:green">// 執行HystrixCommand</span>
    Object result;
    <span style="color:#0000ff">try</span> {
        <span style="color:#0000ff">if</span> (!metaHolder.isObservable()) {
            result = CommandExecutor.execute(invokable, executionType, metaHolder);
        } <span style="color:#0000ff">else</span> {
            result = executeObservable(invokable, executionType, metaHolder);
        }
    } <span style="color:#0000ff">catch</span> (HystrixBadRequestException e) {
        <span style="color:#0000ff">throw</span> e.getCause() != <span style="color:#0000ff">null</span> ? e.getCause() : e;
    } <span style="color:#0000ff">catch</span> (HystrixRuntimeException e) {
        <span style="color:#0000ff">throw</span> hystrixRuntimeExceptionToThrowable(metaHolder, e);
    }
    <span style="color:#0000ff">return</span> result;
}</code></span>

重點是methodsAnnotatedWithHystrixCommand()環繞通知的實現方法

其中MetaHolder metaHolder = metaHolderFactory.create(joinPoint)根據joinPoint的資訊建立元資料時肯定會有初始化預設groupKey預設commandKey以及預設threadPoolKey的邏輯

建立MetaHolder元資料

<span style="color:#000000"><code><span style="color:#0000ff">private</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">class</span> <span style="color:#a31515">CommandMetaHolderFactory</span> <span style="color:#0000ff">extends</span> <span style="color:#a31515">MetaHolderFactory</span> {
    <span style="color:#2b91af">@Override</span>
    <span style="color:#0000ff">public</span> MetaHolder <span style="color:#a31515">create</span>(Object proxy, Method method, Object obj, Object[] args, <span style="color:#0000ff">final</span> ProceedingJoinPoint joinPoint) {
        HystrixCommand hystrixCommand = method.getAnnotation(HystrixCommand.class);
        ExecutionType executionType = ExecutionType.getExecutionType(method.getReturnType());
        
        <span style="color:green">// 建立MetaHolderBuilder</span>
        MetaHolder.Builder builder = metaHolderBuilder(proxy, method, obj, args, joinPoint);
        <span style="color:#0000ff">if</span> (isCompileWeaving()) {
            builder.ajcMethod(getAjcMethodFromTarget(joinPoint));
        }
        
        <span style="color:#0000ff">return</span> builder.defaultCommandKey(method.getName())  <span style="color:green">//預設commandKey是方法名</span>
                        .hystrixCommand(hystrixCommand)
                        .observableExecutionMode(hystrixCommand.observableExecutionMode())
                        .executionType(executionType)
                        .observable(ExecutionType.OBSERVABLE == executionType)
                        .build();
    }
}


<span style="color:green">//----------再來看看建立MetaHolderBuilder - metaHolderBuilder()</span>
<span style="color:green">//== MetaHolderFactory#metaHolderBuilder()</span>
MetaHolder.Builder <span style="color:#a31515">metaHolderBuilder</span>(Object proxy, Method method, Object obj, Object[] args, <span style="color:#0000ff">final</span> ProceedingJoinPoint joinPoint) {
    MetaHolder.Builder builder = MetaHolder.builder()
            .args(args).method(method).obj(obj).proxyObj(proxy)
            .joinPoint(joinPoint);

    <span style="color:green">// 設定fallback方法</span>
    setFallbackMethod(builder, obj.getClass(), method);
    <span style="color:green">// 設定預設配置</span>
    builder = setDefaultProperties(builder, obj.getClass(), joinPoint);
    
    <span style="color:#0000ff">return</span> builder;
}

<span style="color:green">//== 設定預設配置 setDefaultProperties()</span>
<span style="color:#0000ff">private</span> <span style="color:#0000ff">static</span> MetaHolder.Builder <span style="color:#a31515">setDefaultProperties</span>(MetaHolder.Builder builder, Class<?> declaringClass, <span style="color:#0000ff">final</span> ProceedingJoinPoint joinPoint) {
    <span style="color:green">//根據@DefaultProperties註解獲取配置</span>
    Optional<DefaultProperties> defaultPropertiesOpt = AopUtils.getAnnotation(joinPoint, DefaultProperties.class);
    <span style="color:green">//設定 預設groupKey為類名simpleName</span>
    builder.defaultGroupKey(declaringClass.getSimpleName());
    
    <span style="color:green">//如果存在@DefaultProperties,使用其指定的groupKey、threadPoolKey</span>
    <span style="color:#0000ff">if</span> (defaultPropertiesOpt.isPresent()) {
        DefaultProperties defaultProperties = defaultPropertiesOpt.get();
        builder.defaultProperties(defaultProperties);
        <span style="color:#0000ff">if</span> (StringUtils.isNotBlank(defaultProperties.groupKey())) {
            builder.defaultGroupKey(defaultProperties.groupKey());
        }
        <span style="color:#0000ff">if</span> (StringUtils.isNotBlank(defaultProperties.threadPoolKey())) {
            builder.defaultThreadPoolKey(defaultProperties.threadPoolKey());
        }
    }
    <span style="color:#0000ff">return</span> builder;
}</code></span>

由此可見,在構造metaHolder元資料時,通過@HystrixCommand標準方法所在的類名作為goutpKey,通過方法名作為commandKey,但沒有指定threadPoolKey

但執行HystrixCommand時是有預設threadPoolKey的,那麼這個預設值從何而來,command又是怎麼初始化執行緒池的呢??

通過metaHolder構造HystrixCommandBuilder

<span style="color:#000000"><code><span style="color:green">//----------HystrixCommandFactory#create()</span>
<span style="color:#0000ff">public</span> HystrixInvokable <span style="color:#a31515">create</span>(MetaHolder metaHolder) {
    HystrixInvokable executable;
    <span style="color:#0000ff">if</span> (metaHolder.isCollapserAnnotationPresent()) {
        executable = <span style="color:#0000ff">new</span> CommandCollapser(metaHolder);
    } 
    <span style="color:#0000ff">else</span> <span style="color:#0000ff">if</span> (metaHolder.isObservable()) {
        executable = <span style="color:#0000ff">new</span> GenericObservableCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder));
    } 
    <span style="color:#0000ff">else</span> {
        <span style="color:green">//通過metaHolder構造HystrixCommandBuilder,再建立GenericCommand</span>
        executable = <span style="color:#0000ff">new</span> GenericCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder));
    }
    <span style="color:#0000ff">return</span> executable;
}


<span style="color:green">//----------HystrixCommandBuilderFactory#create()  建立HystrixCommandBuilder</span>
<span style="color:green">//在建立HystrixCommandBuilder時,createGenericSetterBuilder(metaHolder)構造了Setter,是用於設定groupKey、commandKey、threadPoolKey的</span>
<span style="color:#0000ff">public</span> <ResponseType> HystrixCommandBuilder <span style="color:#a31515">create</span>(MetaHolder metaHolder, Collection<HystrixCollapser.CollapsedRequest<ResponseType, Object>> collapsedRequests) {
    validateMetaHolder(metaHolder);

    <span style="color:#0000ff">return</span> HystrixCommandBuilder.builder()
            .setterBuilder(createGenericSetterBuilder(metaHolder)) <span style="color:green">//重點:設定setterBuilder</span>
            .commandActions(createCommandActions(metaHolder))
            .collapsedRequests(collapsedRequests)
            .cacheResultInvocationContext(createCacheResultInvocationContext(metaHolder))
            .cacheRemoveInvocationContext(createCacheRemoveInvocationContext(metaHolder))
            .ignoreExceptions(metaHolder.getCommandIgnoreExceptions())
            .executionType(metaHolder.getExecutionType())
            .build();
}

<span style="color:green">//----------createGenericSetterBuilder()  建立SetterBuilder</span>
<span style="color:#0000ff">private</span> GenericSetterBuilder <span style="color:#a31515">createGenericSetterBuilder</span>(MetaHolder metaHolder) {
    GenericSetterBuilder.Builder setterBuilder = GenericSetterBuilder.builder()
            .groupKey(metaHolder.getCommandGroupKey())
            .threadPoolKey(metaHolder.getThreadPoolKey()) <span style="color:green">//檢視從metaHolder如何獲取threadPoolKey</span>
            .commandKey(metaHolder.getCommandKey())
            .collapserKey(metaHolder.getCollapserKey())
            .commandProperties(metaHolder.getCommandProperties())
            .threadPoolProperties(metaHolder.getThreadPoolProperties())
            .collapserProperties(metaHolder.getCollapserProperties());
    <span style="color:#0000ff">if</span> (metaHolder.isCollapserAnnotationPresent()) {
        setterBuilder.scope(metaHolder.getHystrixCollapser().scope());
    }
    <span style="color:#0000ff">return</span> setterBuilder.build();
}

<span style="color:green">//如果使用了Command註解,從註解指定的threadPoolKey 和 defaultThreadPoolKey二選一,以前者為主</span>
<span style="color:green">//本例中,既沒有通過註解指定threadPoolKey,也沒有defaultThreadPoolKey</span>
<span style="color:#0000ff">public</span> String <span style="color:#a31515">getThreadPoolKey</span>() {
    <span style="color:#0000ff">return</span> isCommandAnnotationPresent() ? get(hystrixCommand.threadPoolKey(), defaultThreadPoolKey) : <span style="color:#a31515">""</span>;
}</code></span>

從上面看,HystrixCommandBuilder都構造完成了,還沒有設定threadPoolKey

通過HystrixCommandBuilder建立HystrixCommand

下面是通過HystrixCommandBuilder作為引數建立GenericCommand(),即通過HystrixCommandBuilder建立HystrixCommand

GenericCommand的類圖為:

可見GenericCommand整合關係,從AbstractHystrixCommand --> HystrixCommand --> AbstractCommand,最終他們都是HystrixInvokeable介面的實現了,即可被Hystrix呼叫的

向上進入父類構造,HystrixCommand(Setter setter)

<span style="color:#000000"><code><span style="color:#0000ff">protected</span> <span style="color:#a31515">HystrixCommand</span>(Setter setter) {
    <span style="color:green">// use 'null' to specify use the default</span>
    <span style="color:#0000ff">this</span>(setter.groupKey, setter.commandKey, setter.threadPoolKey, <span style="color:#0000ff">null</span>, <span style="color:#0000ff">null</span>, setter.commandPropertiesDefaults, setter.threadPoolPropertiesDefaults, <span style="color:#0000ff">null</span>, <span style="color:#0000ff">null</span>, <span style="color:#0000ff">null</span>, <span style="color:#0000ff">null</span>, <span style="color:#0000ff">null</span>);
}</code></span>

從setter中獲取了groupKey、commandKey、threadPoolKey、commandPropertiesDefaults、threadPoolPropertiesDefaults,其它引數為null

AbstractCommand構造

進入到 AbstractCommand構造方法,封裝了構造一個HystrixCommand的基本上所有元素的邏輯

<span style="color:#000000"><code><span style="color:#0000ff">protected</span> <span style="color:#a31515">AbstractCommand</span>(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool,
        HystrixCommandProperties.Setter commandPropertiesDefaults, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults,
        HystrixCommandMetrics metrics, TryableSemaphore fallbackSemaphore, TryableSemaphore executionSemaphore,
        HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) {

    <span style="color:#0000ff">this</span>.commandGroup = initGroupKey(group); <span style="color:green">//初始化commandGroupKey</span>
    <span style="color:#0000ff">this</span>.commandKey = initCommandKey(key, getClass()); <span style="color:green">//初始化commandKey</span>
    <span style="color:#0000ff">this</span>.properties = initCommandProperties(<span style="color:#0000ff">this</span>.commandKey, propertiesStrategy, commandPropertiesDefaults); <span style="color:green">//初始化commandProperties</span>
    <span style="color:#0000ff">this</span>.threadPoolKey = initThreadPoolKey(threadPoolKey, <span style="color:#0000ff">this</span>.commandGroup, <span style="color:#0000ff">this</span>.properties.executionIsolationThreadPoolKeyOverride().get()); <span style="color:green">//初始化threadPoolKey</span>
    <span style="color:#0000ff">this</span>.metrics = initMetrics(metrics, <span style="color:#0000ff">this</span>.commandGroup, <span style="color:#0000ff">this</span>.threadPoolKey, <span style="color:#0000ff">this</span>.commandKey, <span style="color:#0000ff">this</span>.properties); <span style="color:green">//初始化metrics</span>
    <span style="color:#0000ff">this</span>.circuitBreaker = initCircuitBreaker(<span style="color:#0000ff">this</span>.properties.circuitBreakerEnabled().get(), circuitBreaker, <span style="color:#0000ff">this</span>.commandGroup, <span style="color:#0000ff">this</span>.commandKey, <span style="color:#0000ff">this</span>.properties, <span style="color:#0000ff">this</span>.metrics); <span style="color:green">//初始化斷路器</span>
    <span style="color:#0000ff">this</span>.threadPool = initThreadPool(threadPool, <span style="color:#0000ff">this</span>.threadPoolKey, threadPoolPropertiesDefaults); <span style="color:green">//初始化執行緒池</span>

    <span style="color:green">//Strategies from plugins</span>
    <span style="color:#0000ff">this</span>.eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
    <span style="color:#0000ff">this</span>.concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
    HystrixMetricsPublisherFactory.createOrRetrievePublisherForCommand(<span style="color:#0000ff">this</span>.commandKey, <span style="color:#0000ff">this</span>.commandGroup, <span style="color:#0000ff">this</span>.metrics, <span style="color:#0000ff">this</span>.circuitBreaker, <span style="color:#0000ff">this</span>.properties);
    <span style="color:#0000ff">this</span>.executionHook = initExecutionHook(executionHook);

    <span style="color:#0000ff">this</span>.requestCache = HystrixRequestCache.getInstance(<span style="color:#0000ff">this</span>.commandKey, <span style="color:#0000ff">this</span>.concurrencyStrategy);
    <span style="color:#0000ff">this</span>.currentRequestLog = initRequestLog(<span style="color:#0000ff">this</span>.properties.requestLogEnabled().get(), <span style="color:#0000ff">this</span>.concurrencyStrategy);

    <span style="color:green">/* fallback semaphore override if applicable */</span>
    <span style="color:#0000ff">this</span>.fallbackSemaphoreOverride = fallbackSemaphore;

    <span style="color:green">/* execution semaphore override if applicable */</span>
    <span style="color:#0000ff">this</span>.executionSemaphoreOverride = executionSemaphore;
}</code></span>

接下來主要看是如何初始化threadPoolKey,以及threadPool的

initThreadPoolKey()

initThreadPoolKey(threadPoolKey, this.commandGroup, this.properties.executionIsolationThreadPoolKeyOverride().get())

引數:

  • threadPoolKey -- 指定的 或 預設的threadPoolKey

  • this.commandGroup -- 當前的groupKey

  • this.properties.executionIsolationThreadPoolKeyOverride().get()) -- 字串型別,允許動態覆蓋修改HystrixThreadPoolKey的值,並將動態更新HystrixCommand執行的HystrixThreadPool,這個override值的典型值是null,並且在構造HystrixCommandProperties時override全域性的配置為null

    <span style="color:#000000"><code><span style="color:green">// threadpool doesn't have a global override, only instance level makes sense</span>
    <span style="color:#0000ff">this</span>.executionIsolationThreadPoolKeyOverride = forString().add(propertyPrefix + <span style="color:#a31515">".command."</span> + key.name() + <span style="color:#a31515">".threadPoolKeyOverride"</span>, <span style="color:#0000ff">null</span>).build();</code></span>

接著看 initThreadPoolKey() 方法內部

<span style="color:#000000"><code><span style="color:green">/*
 * ThreadPoolKey
 *
 * This defines which thread-pool this command should run on.
 *
 * It uses the HystrixThreadPoolKey if provided, then defaults to use HystrixCommandGroup.
 * 如果提供了threadPoolKey,就使用,否則預設使用groupKey
 *
 * It can then be overridden by a property if defined so it can be changed at runtime.
 * 可以被threadPoolKeyOverride在執行時動態覆蓋
 */</span>
<span style="color:#0000ff">private</span> <span style="color:#0000ff">static</span> HystrixThreadPoolKey <span style="color:#a31515">initThreadPoolKey</span>(HystrixThreadPoolKey threadPoolKey, HystrixCommandGroupKey groupKey, String threadPoolKeyOverride) {
    <span style="color:#0000ff">if</span> (threadPoolKeyOverride == <span style="color:#0000ff">null</span>) {
        <span style="color:green">// we don't have a property overriding the value so use either HystrixThreadPoolKey or HystrixCommandGroup</span>
        <span style="color:#0000ff">if</span> (threadPoolKey == <span style="color:#0000ff">null</span>) {
            <span style="color:green">/* 
             * use HystrixCommandGroup if HystrixThreadPoolKey is null 
             * 如果HystrixThreadPoolKey為空,使用groupKey作為threadPoolKey
             */</span>
            <span style="color:#0000ff">return</span> HystrixThreadPoolKey.Factory.asKey(groupKey.name());
        } <span style="color:#0000ff">else</span> {
            <span style="color:#0000ff">return</span> threadPoolKey;
        }
    } <span style="color:#0000ff">else</span> {
        <span style="color:green">// we have a property defining the thread-pool so use it instead</span>
        <span style="color:#0000ff">return</span> HystrixThreadPoolKey.Factory.asKey(threadPoolKeyOverride);
    }
}</code></span>

可見,在最開始構造HystrixCommand時,threadPoolKeyOverride為null,且沒有自己指定的threadPoolKey,也沒有預設的threadPoolKey,那麼將使用groupKey作為threadPoolKey

所以,預設使用groupKey作為threadPoolKey,而group預設值是標註了@HystrixCommand的類名

最後,看一下如何根據threadPoolKey,初始化threadPool

initThreadPool()

<span style="color:#000000"><code><span style="color:green">//----------AbstractCommand#initThreadPool()</span>
<span style="color:#0000ff">private</span> <span style="color:#0000ff">static</span> HystrixThreadPool <span style="color:#a31515">initThreadPool</span>(HystrixThreadPool fromConstructor, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults) {
    <span style="color:green">// fromConstructor為null,使用HystrixThreadPool.Factory建立執行緒池</span>
    <span style="color:#0000ff">if</span> (fromConstructor == <span style="color:#0000ff">null</span>) {
        <span style="color:green">// get the default implementation of HystrixThreadPool</span>
        <span style="color:#0000ff">return</span> HystrixThreadPool.Factory.getInstance(threadPoolKey, threadPoolPropertiesDefaults);
    } <span style="color:#0000ff">else</span> {
        <span style="color:#0000ff">return</span> fromConstructor;
    }
}


<span style="color:green">//----------HystrixThreadPool.Factory#getInstance()  獲取HystrixThreadPool例項</span>
<span style="color:#0000ff">static</span> HystrixThreadPool <span style="color:#a31515">getInstance</span>(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter propertiesBuilder) {
    <span style="color:green">// get the key to use instead of using the object itself so that if people forget to implement equals/hashcode things will still work</span>
    String key = threadPoolKey.name();

    <span style="color:green">// this should find it for all but the first time</span>
    <span style="color:green">// 從快取threadPools中獲取HystrixThreadPool,有則直接返回</span>
    HystrixThreadPool previouslyCached = threadPools.get(key);
    <span style="color:#0000ff">if</span> (previouslyCached != <span style="color:#0000ff">null</span>) {
        <span style="color:#0000ff">return</span> previouslyCached;
    }

    <span style="color:green">// if we get here this is the first time so we need to initialize</span>
    <span style="color:green">// 第一次初始化HystrixThreadPool</span>
    <span style="color:#0000ff">synchronized</span> (HystrixThreadPool.class) {
        <span style="color:#0000ff">if</span> (!threadPools.containsKey(key)) {
            threadPools.put(key, <span style="color:#0000ff">new</span> HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder));
        }
    }
    <span style="color:#0000ff">return</span> threadPools.get(key);
}</code></span>

先根據threadPoolKey嘗試從threadPools這個ConcurrentHashMap<String, HystrixThreadPool>中獲取,即從執行緒池快取中獲取,有就直接返回previouslyCached之前的快取,如果沒有,synchromized對HystrixThreadPool類上鎖後,再次判斷還是沒有threadPoolKey的快取,就 new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder)

<span style="color:#000000"><code><span style="color:green">//----------new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder)</span>
<span style="color:#0000ff">public</span> <span style="color:#a31515">HystrixThreadPoolDefault</span>(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter propertiesDefaults) {
    <span style="color:#0000ff">this</span>.properties = HystrixPropertiesFactory.getThreadPoolProperties(threadPoolKey, propertiesDefaults); <span style="color:green">//threadPoolProperties</span>
    HystrixConcurrencyStrategy concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy(); <span style="color:green">//併發策略</span>
    <span style="color:#0000ff">this</span>.queueSize = properties.maxQueueSize().get(); <span style="color:green">//執行緒池佇列大小</span>

    <span style="color:green">//建立HystrixThreadPoolMetrics,其中concurrencyStrategy.getThreadPool()會建立執行緒池</span>
    <span style="color:#0000ff">this</span>.metrics = HystrixThreadPoolMetrics.getInstance(threadPoolKey,
            concurrencyStrategy.getThreadPool(threadPoolKey, properties),
            properties);
    <span style="color:#0000ff">this</span>.threadPool = <span style="color:#0000ff">this</span>.metrics.getThreadPool();
    <span style="color:#0000ff">this</span>.queue = <span style="color:#0000ff">this</span>.threadPool.getQueue();

    <span style="color:green">/* strategy: HystrixMetricsPublisherThreadPool */</span>
    HystrixMetricsPublisherFactory.createOrRetrievePublisherForThreadPool(threadPoolKey, <span style="color:#0000ff">this</span>.metrics, <span style="color:#0000ff">this</span>.properties);
}


<span style="color:green">//----------HystrixConcurrencyStrategy#getThreadPool(HystrixThreadPoolKey, HystrixThreadPoolProperties)</span>
<span style="color:green">// concurrencyStrategy.getThreadPool()時會建立ThreadPoolExecutor</span>
<span style="color:#0000ff">public</span> ThreadPoolExecutor <span style="color:#a31515">getThreadPool</span>(<span style="color:#0000ff">final</span> HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {
    <span style="color:#0000ff">final</span> ThreadFactory threadFactory = getThreadFactory(threadPoolKey);

    <span style="color:#0000ff">final</span> <span style="color:#0000ff">boolean</span> allowMaximumSizeToDivergeFromCoreSize = threadPoolProperties.getAllowMaximumSizeToDivergeFromCoreSize().get(); <span style="color:green">//是否允許maximumSize生效</span>
    <span style="color:#0000ff">final</span> <span style="color:#0000ff">int</span> dynamicCoreSize = threadPoolProperties.coreSize().get(); <span style="color:green">//動態coreSize</span>
    <span style="color:#0000ff">final</span> <span style="color:#0000ff">int</span> keepAliveTime = threadPoolProperties.keepAliveTimeMinutes().get(); <span style="color:green">//大於coreSize的執行緒,未使用的保活時間</span>
    <span style="color:#0000ff">final</span> <span style="color:#0000ff">int</span> maxQueueSize = threadPoolProperties.maxQueueSize().get(); <span style="color:green">//執行緒佇列最大值</span>
    <span style="color:#0000ff">final</span> BlockingQueue<Runnable> workQueue = getBlockingQueue(maxQueueSize);

    <span style="color:green">//允許使用maximumSize</span>
    <span style="color:#0000ff">if</span> (allowMaximumSizeToDivergeFromCoreSize) {
        <span style="color:#0000ff">final</span> <span style="color:#0000ff">int</span> dynamicMaximumSize = threadPoolProperties.maximumSize().get();
        
        <span style="color:green">//dynamicCoreSize > dynamicMaximumSize,列印error</span>
        <span style="color:#0000ff">if</span> (dynamicCoreSize > dynamicMaximumSize) {
            logger.error(<span style="color:#a31515">"Hystrix ThreadPool configuration at startup for : "</span> + threadPoolKey.name() + <span style="color:#a31515">" is trying to set coreSize = "</span> +
                    dynamicCoreSize + <span style="color:#a31515">" and maximumSize = "</span> + dynamicMaximumSize + <span style="color:#a31515">".  Maximum size will be set to "</span> +
                    dynamicCoreSize + <span style="color:#a31515">", the coreSize value, since it must be equal to or greater than the coreSize value"</span>);
            <span style="color:#0000ff">return</span> <span style="color:#0000ff">new</span> ThreadPoolExecutor(dynamicCoreSize, dynamicCoreSize, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);
        } 
        <span style="color:green">//dynamicCoreSize <= dynamicMaximumSize,正常</span>
        <span style="color:#0000ff">else</span> { 
            <span style="color:#0000ff">return</span> <span style="color:#0000ff">new</span> ThreadPoolExecutor(dynamicCoreSize, dynamicMaximumSize, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);
        }
    } 
    <span style="color:#0000ff">else</span> { <span style="color:green">//不允許使用maximumSize</span>
        <span style="color:#0000ff">return</span> <span style="color:#0000ff">new</span> ThreadPoolExecutor(dynamicCoreSize, dynamicCoreSize, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory);
    }
}</code></span>

至此,執行緒池建立完畢

結論

  • threadPoolKey的預設值是groupKey,而groupKey預設值是@HystrixCommand標註的方法所在類名

  • 可以通過在類上加@DefaultProperties( threadPoolKey="xxx" )設定預設的threadPoolKey

  • 可以通過@HystrixCommand( threadPoolKey="xxx" ) 指定當前HystrixCommand例項的threadPoolKey

  • threadPoolKey用於從執行緒池快取中獲取執行緒池 和 初始化建立執行緒池,由於預設以groupKey即類名為threadPoolKey,那麼預設所有在一個類中的HystrixCommand共用一個執行緒池

  • 動態配置執行緒池 -- 可以通過hystrix.command.HystrixCommandKey.threadPoolKeyOverride=執行緒池key動態設定threadPoolKey,對應的HystrixCommand所使用的執行緒池也會重新建立,還可以繼續通過hystrix.threadpool.HystrixThreadPoolKey.coreSize=nhystrix.threadpool.HystrixThreadPoolKey.maximumSize=n動態設定執行緒池大小

    注意: 通過threadPoolKeyOverride動態修改threadPoolKey之後,hystrixCommand會使用新的threadPool,但是老的執行緒池還會一直存在,並沒有觸發shutdown的機制

原文連結:https://www.cnblogs.com/trust-freedom/p/9956427.html

鄭州專業婦科醫院

鄭州男科醫院哪家好

鄭州專業男科醫院

鄭州哪個醫院人流專業