关于threadPoolKey默认值的疑问
使用SpingCloud必然会用到Hystrix做熔断降级,也必然会用到@HystrixCommand
注解,@HystrixCommand
注解可以配置的除了常用的groupKey、commandKey、fallbackMethod等,还有一个很关键的就是threadPoolKey,就是使用Hystrix线程隔离策略时的线程池Key
/**
* 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.
* <p/>
* default => the runtime class name of annotated method
*
* @return group key
*/
String groupKey() default "";
/**
* Hystrix command key.
* <p/>
* default => the name of annotated method. for example:
* <code>
* ...
* @HystrixCommand
* public User getUserById(...)
* ...
* the command name will be: 'getUserById'
* </code>
*
* @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 "";
......省略
}
而使用中我们常常只指定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问题解决
线程池配置
hystrix.threadpool.default.coreSize = 2
hystrix.threadpool.default.maximumSize = 2
hystrix.threadpool.default.maxQueueSize = -1
线程池的coreSize
和maximumSize
都设置为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 java.util.concurrent.FutureTask@6d72dcf rejected from java.util.concurrent.ThreadPoolExecutor@431bfebc[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方法才会共用线程池