动态线程池Starter设计
动态线程池Starter设计实现
为什么引入动态线程池
实际项目中在配置项目时通常根据业务场景评估io密集型和cpu密集型,然后根据不同的类型使用经验公式设置线程数量,虽然这种方式可以应对大部分场景,但是线上流量常常是无规律可言,突发的流量可能使io密集型任务计算任务延长,导致其他任务无法按时产出结果,生产环境中上版本周期长,并且如果只是因为修改线程池参数问题进行版本变更,很难应对以后的突发情况,并且不能有效利率cpu资源;
针对这种情况,如果可以实时监控项目中线程池使用情况,任务挤压情况,可以很方便的对线程参数进行调整,以有效的应对突发场景;线程池动态调整又是一个高度通用的功能,所以通过将线程池设计为一个动态的组件,不同项目中通过依赖的方式使用,就可以很方便的监控项目中线程池的实时使用情况,方便做应急处理;
那些业务场景需要引入动态线程池管理
生产中通常存在两种使用场景:
- 快速响应用户的请求数据,如果用户在查询一个商品详情时,如果使用单线程处理,这种串行处理会极大的降低用户体验,在用户可接受的范围内不一定能及时得到响应,因此如果采用多线程处理用户的请求可以达到并行处理,不同线程处理不同的请求;
- 跑批任务场景,跑批可以分为io密集型和计算密集型,不管是任何类型,突发的流量或者数据量都有可能使响应变慢和跑批任务延迟,因此对这种突发场景如果能及时修改线程池中线程池个数,可以有效抵抗这种流量激增致使服务出现问题的场景;
动态线程池设计
动态线程池总体设计包括几个模块,如下:
应用线程池
一个应用可以配置多个线程池,因此应用只需要在配置中配置线程池核心参数并且开启动态功能,即可使用线程池客户端动态的操作线程池核心参数。
线程池核心starter组件
实现线程监控,管理的核心starter,应用依赖该starter,即可通过线程池客户端管理配置应用线程池;
配置中心
配置中心负责维护不同应用中的线程池参数,线程池starter会定时将应用中的线程池参数信息上报到配置中心,有配置中心维护管理;
线程池参数动态刷新
在使用线程池过程中,通常需要配置多个参数,但是实际上我们只需要灵活配置好corePoolSize(核心线程数),maximumPoolSize(最大线程数),workQueue(队列长度)这三个核心参数就可以应对大部分场景了;
修改运行中的线程池参数
线程池的核心实现类ThreadPoolExecutor提供了改变corePoolSize,maximumPoolSize的两个快捷方法:
(1)setCorePoolSize(int corePoolSize)
(2)setMaximumPoolSize(int maximumPoolSize)
我们只需要通过RPC或者HTTP的方式将想要变更的参数传递到应用再利用上述方法设置进去即可;而队列长度的变更却相对麻烦点,因为我们常使用的阻塞队列LinkedBlockingQueue将队列大小设置为成了一个final类型的变量,我们无法快捷变更,那该怎么办呢,其中一个思想就是自定义一个LinkedBlockQueue,修改capacity为非final类型,增加一个capacity设置方法,同时考虑并发问题对其中涉及到的方法进行修改;