# 106. 生产环境中的线程池自动扩容与缩容的动态资源分配经验
可能会出现一种情况,比如说我们的某个依赖在高峰期,需要耗费 100 个线程,但是在那个时间段,刚好其他的依赖的线程池其实就维持一两个就可以了
但是,如果我们都是设置死的,每个服务就给 10个 线程,那就很坑,可能就导致有的服务在高峰期需要更多的资源,但是没资源了,导致很多的 reject
但是其他的服务,每秒钟就易一两个请求,结果也占用了 10个 线程,占着茅坑不拉屎
可以利用 hystrix 的配置成弹性的线程资源调度的模式
通过以下测试方法
输出日志
三个被降级,因为一次只能最大 10 个线程,会发现所有的线程名称都是新的,
所以这里每一个 command 都是一个新的线程,但是在官网文档中又看到说,在空闲之后,
会把线程销毁。这个就看不太明白是怎么一回事情了
# 配置 withMaximumSize 无效解决
项目中实战 hystrix 的时候发现这里的配置老是不太对,
如下面这个配置,我给了最大线程 100,但是给 50 个并发线程就会大量的降级
这个问题困扰了我很长时间,后来跟踪源码,当 command 被拒绝的时候,会报错
进入源码后会发现,这里会先判定线程池队列大小是否已经超过了 queueSizeRejectionThreshold 大小;
在前面已经学到过该大小是可以动态调整的。含义是调整队列大小;
那么这里有一个疑问了,为什么会先判断是否已经超了?
会发现使用了 ThreadPoolExecutor.submit 方法;我在 debug 的时候看过了 ThreadPoolExecutor 的参数,的确是我们设置的;
之前不知道 ThreadPoolExecutor 的用法,所以根本想不到为什么。
百度之后,ThreadPoolExecutor 会检查队列,但是在这之前 hystrix 会先检查一次,所以就导致了还没有进入线程池就报错了;
那么问题是为什么队列里面有这么的线程,而且在日志中看不出来到底有几个线程在执行呢?最简单的回答就是 hystrix 包装了线程池;
最后找到一个根源问题:百度之后,创建 ThreadPoolExecutor 的时候,会传入一个 BlockingQueue,如果使用无限容量的阻塞队列(如 LinkedBlockingQueue)时,
不会创建临时线程(因为队列不会满),所以线程数保持 corePoolSize。 而刚好在 debug 时看到的队列就是 LinkedBlockingQueue;
这个时候就真相大白了;原因就是设置了队列大小!下面使用一个 ThreadPoolExecutor 的测试用例来浮现这个问题 当使用 LinkedBlockingDeque 时,运行后观察控制台,只会发现最多只有 20 个线程被复用;这里的队列大小是 20;
当使用 SynchronousQueue 时,就会瞬间出现 40 个线程
回到最初的问题:配置 withMaximumSize 偶尔有效偶尔无效
解决方案:想使用 withMaximumSize 动态调整线程数量的时候,就不要设置等待队列; 如下
TIP
前面和本章讲解的配置相关实践的内容,这些在 官网文档(opens new window) 中都有写到,老样子就是全部是英文文档