Java 为什么当我增加CPU核心数量时,使用Freemarker的SpringWebApp速度会变慢?

Java 为什么当我增加CPU核心数量时,使用Freemarker的SpringWebApp速度会变慢?,java,performance,tomcat,freemarker,scalability,Java,Performance,Tomcat,Freemarker,Scalability,我正在使用Freemarker开发SpringWebApp,当我增加服务器上的CPU内核数量时,我面临性能/可伸缩性问题 在生产中,我们的服务器具有以下配置: 英特尔至强E5-2690 8个物理核心 2.9GHz至3.8GHz,带涡轮增压 超读启用 我们购买了新服务器,用以下配置替换旧服务器: 英特尔至强黄金6254 18个物理核心 3.4GHz至4GHz,带涡轮增压 超读障碍 问题是:在具有18个物理内核的新服务器中,当我们加载500个jmeter线程时,我们的webapp比具有16个

我正在使用Freemarker开发SpringWebApp,当我增加服务器上的CPU内核数量时,我面临性能/可伸缩性问题

在生产中,我们的服务器具有以下配置:

  • 英特尔至强E5-2690
  • 8个物理核心
  • 2.9GHz至3.8GHz,带涡轮增压
  • 超读启用
我们购买了新服务器,用以下配置替换旧服务器:

  • 英特尔至强黄金6254
  • 18个物理核心
  • 3.4GHz至4GHz,带涡轮增压
  • 超读障碍
问题是:在具有18个物理内核的新服务器中,当我们加载500个jmeter线程时,我们的webapp比具有16个内核(8个物理+超线程)的旧服务器慢

因此,我们使用Yourkit分析了我们的应用程序,并发现当freemarker处理模板并写入输出时,大多数tomcat ajp线程在尝试获取tomcat SynchronizedQueue(或SynchronizedStack)上的锁时被阻塞:

问题是:为什么要设置这些锁?我们如何避免或限制它们对性能的影响?

版本:

  • Tomcat 9.0.14
  • 春季4.3.22
  • Freemarker 2.3.28

我找到了两种解决方案来显著减少我的Web应用程序上被阻塞的线程:

  • 我禁用了freemarker autoflush调用
    setAutoFlush(false)
    ()
  • 我优化了处理freemarker模板的方式。在此之前,我的processTemplate方法是:
public void processTemplate(模板模板模板、映射模型、编写器)抛出TemplateException、IOException{
put(AbstractTemplateView.SPRING_宏_请求_上下文_属性,新请求上下文(请求、响应、servletContext、模型));
模板。流程(模型、编写器);
}
每次处理模板时,都会初始化一个新的RequestContext:在调用构造函数时放置一个锁

现在,在FreemarkerProcessor的构造函数中,每个请求只初始化RequestContext一次:

公共FreeMarkerProcessor(HttpServletRequest请求、HttpServletResponse响应、ServletContext ServletContext、freemarker.template.Configuration freemarkerConfiguration){
this.freemarkerConfiguration=freemarkerConfiguration;
requestContext=newRequestContext(请求、响应、servletContext、newHashMap());
}
public void processTemplate(模板模板、映射模型、编写器)抛出TemplateException、IOException{
requestContext.getModel().clear();
requestContext.getModel().putAll(模型);
put(AbstractTemplateView.SPRING\u宏\u请求\u上下文\u属性,requestContext);
模板。流程(模型、编写器);
}  

您是否使用Apache Tomcat APR本机库?我认为(但我不确定)新处理器是NUMA处理器,而旧处理器不是。这意味着可能有一些跨区域的内存访问会减慢你的速度。。。如果问题是这样的话,只使用一个NUMA区域中的内核/内存或者拥有一个完全支持NUMA的软件堆栈应该可以解决速度减慢的问题。@JoachimSauer我使用了“lscpu”命令,我在旧服务器上有“NUMA node0 CPU:0-15”,在新服务器上有“NUMA node0 CPU:0-35”。所以,他们在这一点上似乎是相似的。@ThibautMallet:很公平。但是,我真的不知道这是确切的证据,还是仅仅表明Linux内核还不知道区域;-)您有单插槽主板还是双插槽主板?如果是双存储器,是否只填充slot0 DRAM?为什么不在系统上运行应用程序之前对其进行基准测试?