Tomcat 线程池最大线程池数量被设置成 5 问题排查

一 现象

一个新的业务容器发布到测试环境之后,立马就触发了 Tomcat 线程池的告警通知:

告警显示 Tomcat 线程池线程数剩余只有5个了。这让我感到奇怪,Tomcat 线程池默认最大线程数量明明是200,而且我也没有修改默认配置,应用刚发布测试环境,也没有请求流量进来,怎么会就只有5个空闲线程了呢。

二 原因排查

首先进到该应用监控面板,看了一下 Tomcat 的监控,发现该应用线程池最大线程数是 5 而不是默认的 200。又看了其他应用,都是 200,所以可以确定不是监控的问题,应该是程序代码的问题,怀疑是引入的某个组件影响到了 Tomcat 线程池的设置。随后查看了该应用的pom文件,发现引入的公司中间件版本是最新的版本,与之前版本引入的应用都不一样。但是里面的 dependency 比较多,需要排查是哪个组件引起的。期间尝试修改 Tomcat 的最大线程池数量server.tomcat.threads.max 配置,发现也不生效,应用启动后,线程池最大数目仍然是 5。

咨询反馈给了同事,说有遇到过类似情况,指出如果启动类指定了扫描包路径,修改的小一些,可以解决这个问题。于是把@SpringBootApplication扫描包路径由公司的那一级改为到部门那一级,重启后 Tomcat 线程池最大线程数量恢复正常默认的 200。这说明确实是中间件中某个组件的配置被扫描到影响到了业务应用 Tomcat 的线程池配置了。

于是把Tomcat 线程池线程最大数量是 5 和 200 的启动日志复制出来,分析对比了一下。应用每次启动一共启动了两个 Tomcat 实例,一个是8080端口,先启动的,供业务使用的;另一个是8090端口,后启动的,供SpringBoot监控使用的(actuator 模块)。在两个Tomcat实例的启动之间,看到这样一条日志:

Creating shared instance of singleton bean 'com.xxx.boot.common.management.TomcatThreadChildContextConfiguration'

TomcatThreadChildContextConfiguration 类,看到名字,就大致可以猜到它应该是设置Tomcat线程池的,而且它所在的路径刚好就是公司中间件的包路径。在IDEA里面,全局搜索了这个类,注释功能是“设置management.server 的线程数(Tomcat)”,而且里面设置的默认最大线程数就是 5 。到这里,问题的直接原因就找到了。正是这个类影响到了 8080 端口对应 Tomcat 实例线程数配置的。

TomcatThreadChildContextConfiguration 类大致代码(源码不贴了):

@ManagementContextConfiguration(value = ManegementContextType.CHILD, proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionOnWebApplication.Type.ANY)
@ConditionOnClass(Tomcat.class)
public class TomcatThreadChildContextConfiguration {

     @Bean
     public TomcatThreadCustomizer tomcatThreadCustomizer() {

         return new TomcatThreadCustomizer();
     }

     static class TomcatThreadCustomizer implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {
        //修改线程池限制
        .........
    }
}

      但是新的疑问又出现了,这行日志是在8080端口Tomcat启动后打印的,难道TomcatThreadChildContextConfiguration 类在8080端口Tomcat启动之前就已经加载为bean生效了?搜索了一下当Tomcat 线程池线程最大数量是 5 启动时的日志,发现在启动最开始有一条日志:

[main] o.s.b.f.s.DefaultListableBeanFactory  : Creating shared instance of singleton bean 'tomcatThreadChildContextConfiguration'

再通过打断点,证实了上述结论。当缩小扫描包路径时,TomcatThreadChildContextConfiguration 类就不会在8080端口Tomcat启动之前实例化生效了。

三 结论

   问题根本原因就是设置的包扫描路径太大,导致引入的中间件组件修改监控所用Tomcat实例(本例中的8090端口)的线程配置类提前生效,导致把供业务所用的Tomcat实例(8080端口)线程池最大线程数也给修改了。解决方法就是修改包的扫描路径。最好的方法就是启动类扫描就是默认扫描的包路径,但是因为引入的一些老功能模块需要指定包的扫描路径,我们暂时这么做的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值