线程池优化实践

省流:通过线程池优化查询的业务逻辑,提高接口的效率,但需注意线程池的参数配置(阻塞队列大小,拒绝策略),避免带来其他的问题

问题背景:我们在使用系统的过程中,会遇到一些导出数据的场景,比如导出某个人最近一天的所有会议记录,以及会议的参会人信息

查询会议记录的业务逻辑

第一步 先根据用户查询查询用户的会议列

第二步 根据第一步查询出来的会议列表的会议信息,去循环查询每个会议的与会人信息

第三步 组合结果返回

业务代码(注:代码为模拟代码,并不涉及真实生产的代码)

并发为5时,请求耗时为平均在2000ms左右

并发50时,请求耗时为平均3000+ms左右

并发500时,请求耗时为平均4000+ms左右

随着并发量的上涨,查询数据的耗时越来越长,且并发为5时就已经达到2000ms左右了,耗时巨长

通过观察业务逻辑,循环查询每个会议的与会人信息的时候,并没有逻辑上的关联,也就是说,查询每个会议的与会人信息可以看作一个独立的过程,我们可以考虑用单独的线程去执行这个查询,通过并发来提高整体的效率。 改进后的流程为 第一步 先根据用户查询查询用户的会议列表 第二步 根据第一步查询出来的会议列表的会议信息,把每个会议的与会人查询提交到线程池当中去执行 第三步 组合结果返回

业务代码(注:代码为模拟代码,并不涉及真实生产的代码)
线程池参数

核心线程数为4(一般IO类型任务核心线程设为cpu * 2,计算类型任务时,核心线程设为cpu + 1,查询数据库或者访问第三方接口都数据IO类型的任务)

最大线程数设置为20

空闲线程存活时间 5分钟

任务队列大小 500

拒绝策略 直接拒绝

改进后 并发为5时,耗时为100+ms,速度得到质的提升

并发为50时,初期耗时为100ms,但是随着并发量的上升,后续的耗时逐渐开始变大 ,最大的时候为1000+ms,此时还出现阻塞队列中的任务,获取超时的问题,此时已经开始影响到了正常的业务,有部分的用户开始导出缺失的数据了

耗时增大 超时问题

并发为500时,也是同样的初期耗时较低,后续耗时变大,此时阻塞队列出现了大量超时的问题,大量用户已经开始导出空白的数据了,问题更加严重了

目前线程池出现的问题

问题一:后续耗时会变大?

问题二:阻塞队列已满,且出现大量队列中的任务超时问题,直接导致用户导出了空白的数据?

解决方案:
问题一 :耗时开始增大是正常的现象,因为当流量变大的时候,服务处理能力到最高后无法提升了,必然会有开始变慢的问题,影响不大,可通过限流或者是提醒用户稍等重试的方式较低影响
问题二 : 这个问题的本质是因为线程池参数设置得不合理

1、队列设置错误,该场景下,需要充分利用线程资源,将线程放入队列只会徒增等待的时间,导致等待队列里的任务全部超时抛出异常

2、拒绝策略设置错误,直接拒绝任务会抛出异常导致主流程中断,但此时主流程可能已经提交了部分任务,导致无效任务的提交

优化后参数

相比于之前,只修改了两个参数

1.把原来的任务队列设置为SynchronousQueue ,SynchronousQueue 是一个特殊的队列,其最大容量是1。也就是说,任何一次插入操作都必须等待一个相应的删除操作,反之亦然。如果没有相应的操作正在进行,则该线程将被阻塞,也就是说当线程池达到最大线程后,就不在接受新的任务了,解决阻塞队列内的任务超时的问题

2.拒绝策略改为CallerRunsPolicy,当阻塞队列满了,由提交任务的线程去完成执行,原来的流程中,主线程提交完任务后就阻塞等待了,浪费了主线程的线程资源,可利用主线程的资源,当阻塞队列满了,让主线程来执行当前任务,充分利用主线程的资源

执行 并发量为5时,执行耗时为100ms左右,和原来参数表现基本一致

并发量为50时,执行耗时为100+ms左右,最高也只到150ms,且没有出现任何异常

并发量为500时,执行耗时为300+ms左右,最高也只到500+ms,且没有出现任何异常

相关推荐
微信-since811927 分钟前
[ruby on rails] 安装docker
后端·docker·ruby on rails
代码吐槽菌2 小时前
基于SSM的毕业论文管理系统【附源码】
java·开发语言·数据库·后端·ssm
豌豆花下猫2 小时前
Python 潮流周刊#78:async/await 是糟糕的设计(摘要)
后端·python·ai
YMWM_2 小时前
第一章 Go语言简介
开发语言·后端·golang
码蜂窝编程官方2 小时前
【含开题报告+文档+PPT+源码】基于SpringBoot+Vue的虎鲸旅游攻略网的设计与实现
java·vue.js·spring boot·后端·spring·旅游
hummhumm3 小时前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
J老熊3 小时前
JavaFX:简介、使用场景、常见问题及对比其他框架分析
java·开发语言·后端·面试·系统架构·软件工程
AuroraI'ncoding3 小时前
时间请求参数、响应
java·后端·spring
好奇的菜鸟3 小时前
Go语言中的引用类型:指针与传递机制
开发语言·后端·golang
Alive~o.03 小时前
Go语言进阶&依赖管理
开发语言·后端·golang