最近我们将应用程序从运行在tomcat中的Web应用程序移植到带有嵌入式tomcat的spring启动应用程序。
运行应用程序几天后,内存和CPU使用率已达到100%。 在堆转储分析中,出现了一堆未被销毁的http会话对象。
我可以在调试中看到使用配置的超时值创建的会话,比方说,5分钟。但在此之后,不会触发失效。只有在超时期限后再次请求时才会调用它。
我已将此行为与在tomcat中运行的app进行比较,我可以看到会话失效由ContainerBackgroungProcessor线程[StandardManager(ManagerBase).processExpires()]
触发我在Spring启动应用程序中没有看到这个后台线程。
根据一些建议做了什么:
在application.properties中设置的会话超时: server.session.timout = 300 或者在EmbeddedServletContainerCustomizer @Bean中: factory.setSessionTimout(5,TimeUnit.MINUTES)
添加了HttpSessionEventPublisher和SessionRegistry bean
没有任何帮助,会话在到期时间内没有失效。
有关这方面的一些线索?
答案 0 :(得分:4)
经过一些调试和文档阅读之后,这就是原因和解决方案:
在tomcat中,有一个代表root容器生成的线程,它定期扫描容器及其子容器会话池并使它们无效。每个容器/子容器可以配置为具有自己的后台处理器来完成工作或依赖其主机的后台处理器。 这由Conext.backgroundProcessorDelay
控制Apache Tomcat 8 Configuration Reference
backgroundProcessorDelay -
此值表示在此引擎上调用backgroundProcess方法与其子容器(包括所有主机和上下文)之间的延迟(以秒为单位)。如果延迟值不是负数(这意味着他们使用自己的处理线程),则不会调用子容器。将此值设置为正值将导致生成线程。等待指定的时间后,线程将在此引擎及其所有子容器上调用backgroundProcess方法。如果未指定,则此属性的默认值为10,表示延迟10秒。
在嵌入式tomcat的spring启动应用程序中 有TomcatEmbeddedServletContainerFactory.configureEngine(),它为StandardEngine [Tomcat]设置了这个属性-1,这是tomcat层次结构中的根容器,据我所知。 包括Web应用程序在内的所有子容器也将此参数设置为-1。 这意味着他们都依赖别人来完成这项工作。 春天不这样做,没有人这样做。
我的解决方案是为app上下文设置此参数:
@Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
TomcatEmbeddedServletContainerFactory factory = (TomcatEmbeddedServletContainerFactory) container;
TomcatContextCustomizer contextCustomizer = new TomcatContextCustomizer() {
@Override
public void customize(Context context) {
context.setBackgroundProcessorDelay(10);
}
};
List<TomcatContextCustomizer> contextCustomizers = new ArrayList<TomcatContextCustomizer>();
contextCustomizers.add(contextCustomizer);
factory.setTomcatContextCustomizers(contextCustomizers);
customizeTomcat(factory);
}
}