Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)

今天来研究下@HystrixCommand注解。使用Sping Cloud必然会用到Hystrix做熔断降级,也必然会用到@HystrixCommand注解,该注解可以配置的除了常用的groupKey、commandKey、fallbackMethod等,还有一个很关键的就是threadPoolKey,就是使用Hystrix线程隔离策略时的线程池Key。

/**
 * Copyright 2012 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.netflix.hystrix.contrib.javanica.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * This annotation used to specify some methods which should be processes as hystrix commands.
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HystrixCommand {

    /**
     * The command group key is used for grouping together commands such as for reporting,
     * alerting, dashboards or team/library ownership.
     * 

* default => the runtime class name of annotated method * * @return group key */ String groupKey() default ""; /** * Hystrix command key. *

* default => the name of annotated method. for example: * * ... * @HystrixCommand * public User getUserById(...) * ... * the command name will be: 'getUserById' * * * @return command key */ String commandKey() default ""; /** * The thread-pool key is used to represent a * HystrixThreadPool for monitoring, metrics publishing, caching and other such uses. * * @return thread pool key */ String threadPoolKey() default ""; /** * Specifies a method to process fallback logic. * A fallback method should be defined in the same class where is HystrixCommand. * Also a fallback method should have same signature to a method which was invoked as hystrix command. * for example: * * @HystrixCommand(fallbackMethod = "getByIdFallback") * public String getById(String id) {...} * * private String getByIdFallback(String id) {...} * * Also a fallback method can be annotated with {@link HystrixCommand} *

* default => see {@link com.netflix.hystrix.contrib.javanica.command.GenericCommand#getFallback()} * * @return method name */ String fallbackMethod() default ""; /** * Specifies command properties. * * @return command properties */ HystrixProperty[] commandProperties() default {}; /** * Specifies thread pool properties. * * @return thread pool properties */ HystrixProperty[] threadPoolProperties() default {}; /** * Defines exceptions which should be ignored. * Optionally these can be wrapped in HystrixRuntimeException if raiseHystrixExceptions contains RUNTIME_EXCEPTION. * * @return exceptions to ignore */ Class[] ignoreExceptions() default {}; /** * Specifies the mode that should be used to execute hystrix observable command. * For more information see {@link ObservableExecutionMode}. * * @return observable execution mode */ ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER; /** * When includes RUNTIME_EXCEPTION, any exceptions that are not ignored are wrapped in HystrixRuntimeException. * * @return exceptions to wrap */ HystrixException[] raiseHystrixExceptions() default {}; /** * Specifies default fallback method for the command. If both {@link #fallbackMethod} and {@link #defaultFallback} * methods are specified then specific one is used. * note: default fallback method cannot have parameters, return type should be compatible with command return type. * * @return the name of default fallback method */ String defaultFallback() default ""; }

 而使用中我们常常只指定fallbackMethod回退方法,而不会指定所有属性,从@HystrixCommand的源码注释来看

  • groupKey的默认值是使用@HystrixCommand标注的方法所在的类名

  • commandKey的默认值是@HystrixCommand标注的方法名,即每个方法会被当做一个HystrixCommand

Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)_第1张图片

  • threadPoolKey没有默认值

threadPoolKey却没有说明默认值,而threadPoolKey是和执行HystrixCommand的线程池直接相关的。

那么问题来了,threadPoolKey默认值是什么? 执行HystrixCommand的线程池又是怎么初始化的? 可以动态调整吗?

首先,被@HystrixCommand注解标注的方法会被AOP拦截,具体逻辑在 HystrixCommandAspect 类中。

/**
 * Copyright 2012 Netflix, Inc.
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.netflix.hystrix.contrib.javanica.aop.aspectj; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import com.netflix.hystrix.HystrixInvokable; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixException; import com.netflix.hystrix.contrib.javanica.command.CommandExecutor; import com.netflix.hystrix.contrib.javanica.command.ExecutionType; import com.netflix.hystrix.contrib.javanica.command.HystrixCommandFactory; import com.netflix.hystrix.contrib.javanica.command.MetaHolder; import com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException; import com.netflix.hystrix.contrib.javanica.exception.FallbackInvocationException; import com.netflix.hystrix.contrib.javanica.utils.AopUtils; import com.netflix.hystrix.contrib.javanica.utils.FallbackMethod; import com.netflix.hystrix.contrib.javanica.utils.MethodProvider; import com.netflix.hystrix.exception.HystrixBadRequestException; import com.netflix.hystrix.exception.HystrixRuntimeException; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import rx.Observable; import rx.functions.Func1; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; import java.util.concurrent.Future; import static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getDeclaredMethod; import static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getMethodFromTarget; import static com.netflix.hystrix.contrib.javanica.utils.AopUtils.getMethodInfo; import static com.netflix.hystrix.contrib.javanica.utils.EnvUtils.isCompileWeaving; import static com.netflix.hystrix.contrib.javanica.utils.ajc.AjcUtils.getAjcMethodAroundAdvice; /** * AspectJ aspect to process methods which annotated with {@link HystrixCommand} annotation. */ @Aspect public class HystrixCommandAspect { private static final Map META_HOLDER_FACTORY_MAP; /** * 初始化用于处理 HystrixCommand 和 HystrixCollapser 的 MetaHolderFactory * HystrixCommand -- CommandMetaHolderFactory * HystrixCollapser -- CollapserMetaHolderFactory */ static { META_HOLDER_FACTORY_MAP = ImmutableMap.builder() .put(HystrixPointcutType.COMMAND, new CommandMetaHolderFactory()) .put(HystrixPointcutType.COLLAPSER, new CollapserMetaHolderFactory()) .build(); } /** * HystrixCommand Pointcut切入点 */ @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)") public void hystrixCommandAnnotationPointcut() { } /** * HystrixCollapser Pointcut切入点 */ @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)") public void hystrixCollapserAnnotationPointcut() { } /** * HystrixCommand 和 HystrixCollapser 的环绕通知 */ @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()") public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable { Method method = getMethodFromTarget(joinPoint); Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint); if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) { throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " + "annotations at the same time"); } // 创建metaHolder,用于保存元数据 MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method)); MetaHolder metaHolder = metaHolderFactory.create(joinPoint); // 创建HystrixCommand,HystrixInvokable是父接口 HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder); ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ? metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType(); // 执行HystrixCommand Object result; try { if (!metaHolder.isObservable()) { result = CommandExecutor.execute(invokable, executionType, metaHolder); } else { result = executeObservable(invokable, executionType, metaHolder); } } catch (HystrixBadRequestException e) { throw e.getCause(); } catch (HystrixRuntimeException e) { throw hystrixRuntimeExceptionToThrowable(metaHolder, e); } return result; } //省略了部分代码 }

重点是methodsAnnotatedWithHystrixCommand()环绕通知的实现方法。

1、其中MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
根据joinPoint的信息创建元数据时肯定会有初始化默认groupKey、默认commandKey以及默认threadPoolKey的逻辑。

Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)_第2张图片

Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)_第3张图片

Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)_第4张图片

private static class CommandMetaHolderFactory extends MetaHolderFactory {
    @Override
    public MetaHolder create(Object proxy, Method method, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {
        HystrixCommand hystrixCommand = method.getAnnotation(HystrixCommand.class);
        ExecutionType executionType = ExecutionType.getExecutionType(method.getReturnType());
        
        // 创建MetaHolderBuilder
        MetaHolder.Builder builder = metaHolderBuilder(proxy, method, obj, args, joinPoint);
        if (isCompileWeaving()) {
            builder.ajcMethod(getAjcMethodFromTarget(joinPoint));
        }
        
        return builder.defaultCommandKey(method.getName())  //默认commandKey是方法名
                        .hystrixCommand(hystrixCommand)
                        .observableExecutionMode(hystrixCommand.observableExecutionMode())
                        .executionType(executionType)
                        .observable(ExecutionType.OBSERVABLE == executionType)
                        .build();
    }
}

/**
 * 再来看看创建MetaHolderBuilder - metaHolderBuilder()
 * MetaHolderFactory#metaHolderBuilder()
 */
MetaHolder.Builder metaHolderBuilder(Object proxy, Method method, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {
    MetaHolder.Builder builder = MetaHolder.builder()
            .args(args).method(method).obj(obj).proxyObj(proxy)
            .joinPoint(joinPoint);

    // 设置fallback方法
    setFallbackMethod(builder, obj.getClass(), method);
    // 设置默认配置
    builder = setDefaultProperties(builder, obj.getClass(), joinPoint);
    
    return builder;
}

// 设置默认配置 setDefaultProperties()
private static MetaHolder.Builder setDefaultProperties(MetaHolder.Builder builder, Class declaringClass, final ProceedingJoinPoint joinPoint) {
    // 根据@DefaultProperties注解获取配置
    Optional defaultPropertiesOpt = AopUtils.getAnnotation(joinPoint, DefaultProperties.class);
    // 设置默认groupKey为类名simpleName
    builder.defaultGroupKey(declaringClass.getSimpleName());
    
    // 如果存在@DefaultProperties,使用其指定的groupKey、threadPoolKey
    if (defaultPropertiesOpt.isPresent()) {
        DefaultProperties defaultProperties = defaultPropertiesOpt.get();
        builder.defaultProperties(defaultProperties);
        if (StringUtils.isNotBlank(defaultProperties.groupKey())) {
            builder.defaultGroupKey(defaultProperties.groupKey());
        }
        if (StringUtils.isNotBlank(defaultProperties.threadPoolKey())) {
            builder.defaultThreadPoolKey(defaultProperties.threadPoolKey());
        }
    }
    return builder;
}

由此可见,在构造metaHolder元数据时,通过@HystrixCommand标准方法所在的类名作为groupKey,通过方法名作为commandKey,但没有指定threadPoolKey。但执行HystrixCommand时是有默认threadPoolKey的,那么这个默认值从何而来,command又是怎么初始化线程池的呢?再来看下这个方法:

2、 HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);

Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)_第5张图片

通过metaHolder构造HystrixCommandBuilder,再创建GenericCommand

Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)_第6张图片

在创建HystrixCommandBuilder时,createGenericSetterBuilder(metaHolder)构造了Setter,是用于设置groupKey、commandKey、threadPoolKey的

Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)_第7张图片

查看从metaHolder如何获取threadPoolKey

Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)_第8张图片

如果使用了Command注解,从注解指定的threadPoolKey 和 defaultThreadPoolKey二选一,以前者为主。本例中,既没有通过注解指定threadPoolKey,也没有defaultThreadPoolKey

从上面看,HystrixCommandBuilder都构造完成了,还没有设置threadPoolKey。

在上面步骤中,通过metaHolder构造HystrixCommandBuilder,再创建GenericCommand。

所以我们再来看GenericCommand的类图:

Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)_第9张图片

可见GenericCommand集成关系,从AbstractHystrixCommand --> HystrixCommand --> AbstractCommand,最终他们都是HystrixInvokeable接口的实现了,即可被Hystrix调用的。向上进入父类构造,HystrixCommand(Setter setter)。

protected HystrixCommand(Setter setter) {
    // use 'null' to specify use the default
    this(setter.groupKey, setter.commandKey, setter.threadPoolKey, null, null, setter.commandPropertiesDefaults, setter.threadPoolPropertiesDefaults, null, null, null, null, null);
}

从setter中获取了groupKey、commandKey、threadPoolKey、commandPropertiesDefaults、threadPoolPropertiesDefaults,其它参数为null。

进入到 AbstractCommand构造方法,封装了构造一个HystrixCommand的基本上所有元素的逻辑。

protected AbstractCommand(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) {

    this.commandGroup = initGroupKey(group); //初始化commandGroupKey
    this.commandKey = initCommandKey(key, getClass()); //初始化commandKey
    this.properties = initCommandProperties(this.commandKey, propertiesStrategy, commandPropertiesDefaults); //初始化commandProperties
    this.threadPoolKey = initThreadPoolKey(threadPoolKey, this.commandGroup, this.properties.executionIsolationThreadPoolKeyOverride().get()); //初始化threadPoolKey
    this.metrics = initMetrics(metrics, this.commandGroup, this.threadPoolKey, this.commandKey, this.properties); //初始化metrics
    this.circuitBreaker = initCircuitBreaker(this.properties.circuitBreakerEnabled().get(), circuitBreaker, this.commandGroup, this.commandKey, this.properties, this.metrics); //初始化断路器
    this.threadPool = initThreadPool(threadPool, this.threadPoolKey, threadPoolPropertiesDefaults); //初始化线程池

    //Strategies from plugins
    this.eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
    this.concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
    HystrixMetricsPublisherFactory.createOrRetrievePublisherForCommand(this.commandKey, this.commandGroup, this.metrics, this.circuitBreaker, this.properties);
    this.executionHook = initExecutionHook(executionHook);

    this.requestCache = HystrixRequestCache.getInstance(this.commandKey, this.concurrencyStrategy);
    this.currentRequestLog = initRequestLog(this.properties.requestLogEnabled().get(), this.concurrencyStrategy);

    /* fallback semaphore override if applicable */
    this.fallbackSemaphoreOverride = fallbackSemaphore;

    /* execution semaphore override if applicable */
    this.executionSemaphoreOverride = executionSemaphore;
}

接下来主要看是如何初始化threadPoolKey,以及threadPool的
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
// threadpool doesn't have a global override, only instance level makes sense
this.executionIsolationThreadPoolKeyOverride = forString().add(propertyPrefix + ".command." + key.name() + ".threadPoolKeyOverride", null).build();

接着看 initThreadPoolKey() 方法内部

/*
 * 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在运行时动态覆盖
 */
private static HystrixThreadPoolKey initThreadPoolKey(HystrixThreadPoolKey threadPoolKey, HystrixCommandGroupKey groupKey, String threadPoolKeyOverride) {
    if (threadPoolKeyOverride == null) {
        // we don't have a property overriding the value so use either HystrixThreadPoolKey or HystrixCommandGroup
        if (threadPoolKey == null) {
            /* 
             * use HystrixCommandGroup if HystrixThreadPoolKey is null 
             * 如果HystrixThreadPoolKey为空,使用groupKey作为threadPoolKey
             */
            return HystrixThreadPoolKey.Factory.asKey(groupKey.name());
        } else {
            return threadPoolKey;
        }
    } else {
        // we have a property defining the thread-pool so use it instead
        return HystrixThreadPoolKey.Factory.asKey(threadPoolKeyOverride);
    }
}

可见,在最开始构造HystrixCommand时,threadPoolKeyOverride为null,且没有自己指定的threadPoolKey,也没有默认的threadPoolKey,那么将使用groupKey作为threadPoolKey。所以,默认使用groupKey作为threadPoolKey,而group默认值是标注了@HystrixCommand的类名。最后,看一下如何根据threadPoolKey,初始化threadPool。

// AbstractCommand#initThreadPool()
private static HystrixThreadPool initThreadPool(HystrixThreadPool fromConstructor, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults) {
    // fromConstructor为null,使用HystrixThreadPool.Factory创建线程池
    if (fromConstructor == null) {
        // get the default implementation of HystrixThreadPool
        return HystrixThreadPool.Factory.getInstance(threadPoolKey, threadPoolPropertiesDefaults);
    } else {
        return fromConstructor;
    }
}


// HystrixThreadPool.Factory#getInstance()  获取HystrixThreadPool实例
static HystrixThreadPool getInstance(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter propertiesBuilder) {
    // get the key to use instead of using the object itself so that if people forget to implement equals/hashcode things will still work
    String key = threadPoolKey.name();

    // this should find it for all but the first time
    // 从缓存threadPools中获取HystrixThreadPool,有则直接返回
    HystrixThreadPool previouslyCached = threadPools.get(key);
    if (previouslyCached != null) {
        return previouslyCached;
    }

    // if we get here this is the first time so we need to initialize
    // 第一次初始化HystrixThreadPool
    synchronized (HystrixThreadPool.class) {
        if (!threadPools.containsKey(key)) {
            threadPools.put(key, new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder));
        }
    }
    return threadPools.get(key);
}

先根据threadPoolKey尝试从threadPools这个ConcurrentHashMap中获取,即从线程池缓存中获取,有就直接返回previouslyCached之前的缓存,如果没有,synchromized对HystrixThreadPool类上锁后,再次判断还是没有threadPoolKey的缓存,就 new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder)。

// new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder)
public HystrixThreadPoolDefault(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter propertiesDefaults) {
    this.properties = HystrixPropertiesFactory.getThreadPoolProperties(threadPoolKey, propertiesDefaults); //threadPoolProperties
    HystrixConcurrencyStrategy concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy(); // 并发策略
    this.queueSize = properties.maxQueueSize().get(); // 线程池队列大小

    // 创建HystrixThreadPoolMetrics,其中concurrencyStrategy.getThreadPool()会创建线程池
    this.metrics = HystrixThreadPoolMetrics.getInstance(threadPoolKey,
            concurrencyStrategy.getThreadPool(threadPoolKey, properties),
            properties);
    this.threadPool = this.metrics.getThreadPool();
    this.queue = this.threadPool.getQueue();

    // strategy: HystrixMetricsPublisherThreadPool
    HystrixMetricsPublisherFactory.createOrRetrievePublisherForThreadPool(threadPoolKey, this.metrics, this.properties);
}


// HystrixConcurrencyStrategy#getThreadPool(HystrixThreadPoolKey, HystrixThreadPoolProperties)
// concurrencyStrategy.getThreadPool()时会创建ThreadPoolExecutor
public ThreadPoolExecutor getThreadPool(final HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {
    final ThreadFactory threadFactory = getThreadFactory(threadPoolKey);

    final boolean allowMaximumSizeToDivergeFromCoreSize = threadPoolProperties.getAllowMaximumSizeToDivergeFromCoreSize().get(); // 是否允许maximumSize生效
    final int dynamicCoreSize = threadPoolProperties.coreSize().get(); // 动态coreSize
    final int keepAliveTime = threadPoolProperties.keepAliveTimeMinutes().get(); // 大于coreSize的线程,未使用的保活时间
    final int maxQueueSize = threadPoolProperties.maxQueueSize().get(); // 线程队列最大值
    final BlockingQueue workQueue = getBlockingQueue(maxQueueSize);

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

至此,线程池创建完毕。

threadPoolKey的默认值是groupKey,而groupKey默认值是@HystrixCommand标注的方法所在类名。所以,默认是每个类中维护了一个线程池,类中的所有方法共用。

为了避免问题服务请求过多导致正常服务⽆法访问,Hystrix 不是采⽤增加线程数,⽽是单独的为每⼀个控制⽅法创建⼀个线程池的⽅式,这种模式叫做“舱壁模式",也是线程隔离的⼿段。配置如下:

@HystrixCommand(
		// 线程池标识保持唯一(单独使用一个线程池),和属性配置
		threadPoolKey = "myThreadPool",
		threadPoolProperties = {
				@HystrixProperty(name = "coreSize", value = "1"),// 线程数
				@HystrixProperty(name = "maxQueueSize", value = "20")// 等待队列长度
		}
)

Spring Cloud中@HystrixCommand注解 Hystrix舱壁模式(线程池隔离策略)_第10张图片 

 

你可能感兴趣的:(学习内容输出)