商品
的信息,那么我们需要将商品维度
的⼀系列信息如商品的价格
、优惠
、库存
、图⽚
等等聚合起来,展示给⽤户。离线的计算任务
,计算量很大,像大型的统计报表,其实我们希望的是来快速生成报表不需要瞬时完成
,而是关注如何使用有限的资源尽可能在单位时间处理更多的任务,也就是强调吞吐量。这种情况下应该设置队列去缓冲并发任务,调整合适的corePoolSize,这里,设置的线程数过多可能会引发线程上下文切换频繁,也会降低处理任务的速度,减低吞吐量。线程池使用面临的核心问题在于:线程池的参数不好配置:线程池执行的情况和任务类型相关性很大,IO、cpu密集型任务执行起来的情况差异非常大。
事故描述一:xxx 页面展示接口大量调用降级:队列设置正常,核心线程过小
。
事故原因:该服务展示接口内部逻辑使用线程池并行计算,由于没有预估好调用的流量,导致最大核心数设置偏小,大量抛出RejectedExecutionException,触发接口降低。
事故描述二:服务不可用:任务堆积
,线程池队列⻓度设置过⻓、corePoolSize设置过⼩导致任务执⾏速度低;线程来不及处理任务造成大量任务堆积,导致任务执行时间过长,会导致下游服务的大量调用超时失败。
思考:那线程池参数有计算呢公式吗?
其实很难有一个准确的公式来计算出核心线程、最大线程数的,往往实际场景是根据压测、tps等来大概估算的,但实际中有时候流量是正常的,有时候流量往往是随机的,其实也不符合实际场景,那既然不能一下子算出来,那可以通过动态线程池参数,实现参数的动态化。
那问题来了:怎样将修改线程池参数的成本降下来?
在成本可控的情况下,在发生故障时可以快速调整从而缩短故障恢复的时间?如何缩短时间?线程池参数的动态感知------> 分布式配置中心,实现线程池参数动态配置即时生效。
线程池参数动态化:分布式配置中心,参数的更新。
动态调参:JDK提供的原生的ThreadPoolExecutor提供了对核心线程数、最大线程数、拒绝策略等的set方法,在运行期使用方调用此方法设置corePoolSize之后,线程池会直接覆盖原来的corePoolSize值,并且会基于当前值和原始值的比较结果采取不同的处理策略。对于当前值小于当前工作线程的情况,说明有多余的工作线程,这时会向工作线程发起中断请求以实现回收;对于当前值大于原始值并且队列中有待执行任务,则线程池会创建新的工作线程来执行队列任务。
那怎样实现动态线程池:获取到当前程序中的ThreadPoolExecutor实例------> 进而获取到当前程序的线程池参数-----> 之后上报到redis中,基于redis发布订阅,实现动态参数更新。
对于JDK提供的这些set方法,线程池内部会处理好当前状态做到平滑处理。只要维护ThreadPoolExecutor实例,在需要修改的时候修改参数即可。
问题一:实际投入项目使用时,使用redis作为线程池的注册中心,项目本身是不是还需要额外定义redis客户端实例?要和starter里面的实例 区分开来使用?
问题二:为什么redisson 定义的时候 不用默认的配置,而是自己定义的redis的配置类
问题三:如果想这个starter 既要支持redis 又要支持nacos?
首先要将本地采集到的线程池数据进行上报,采用redis作为注册中心,将采集到的线程池配置信息上传到redis(这是是用spring定时任务,定时采集线程池配置信息进行上报的);动态更新线程池配置参数,是根据redis发布订阅来实现的,将需要动态更新的消息发布到topic,在消费者这一端(订阅了该topic)就会监听到这个消息,然后将变更的消息设置到当前应用的对应的ThreadPoolExecutor实例上(应用本地有一个Map
问:spring采集线程池配置信息怎么做的?
Map
上报到redis中的信息包括什么:包括线程池的名字、标识、配置参数。