我的Spring Boot应用程序有一个奇怪的行为:
重新启动后端后,对控制器的第一次调用大约需要5秒钟,随后的相同请求仅需50毫秒。在90%的情况下,这种情况是可以重现的,有时甚至是第一次通话都很快。
我敢肯定,问题出在服务器而不是客户端上。在浏览器上,我看到TTFB时间(到第一个字节的时间)增加到5秒。以下请求对TTFB只需10毫秒。
使用服务器上的监视工具(应用程序动态),我可以收集如此缓慢的服务器调用,而在调用图上,我可以看到:
GridPane
需要4916ms。我想这就是我的瓶颈。但是我不知道如何解决。
我已经尝试过的:
一切都不会影响服务器延迟。
更新
由于多次扫描war文件而浪费了时间。
org.apache.catalina.webresources.CachedResource.validateResource 正在检查我们是否有战争文件( isPackedWarFile ),并且此检查返回false。即使是战争文件。对于这种行为,我有一个解决方法。我将 tomcat.resource.cache-tt 设置为较高的值。
但是现在 org.apache.catalina.webresources.Cache.getResource 具有 noCache 方法。在这种方法中, class 和 jar 文件被排除在缓存之外。这就是再次扫描 war 文件的原因。
扫描整个war文件大约需要5秒钟。这个突破是世界突破的停顿。而且此扫描绝对是不必要的,因为war文件不会爆炸,因此其内容也无法更改。
更新
如果将war文件放入tomcat安装中,一切都会很快。嵌入式的tomcat就是问题所在。
答案 0 :(得分:1)
我想您已经做过,但是如果没有,请看看https://wiki.apache.org/tomcat/HowTo/FasterStartUp并实施那里建议的修复程序。
要在嵌入式tomcat中禁用扫描,请在https://github.com/spring-projects/spring-boot/issues/1610
的注释中提出建议如果以上建议均不能帮助您解决延迟问题,则可能的解决方法是在服务器启动时发出第一个请求(并从那里触发延迟)。
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
private RestTemplate template;
public static void main (String args[]){
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... strings) throws Exception {
// do an initial request from here to trigger scanning the war
template.exchange(...);
}
}
这样,您的客户将不再经历5秒的延迟。我知道这是一种黑客行为,因此,如果您找到一种更清洁的方法,请改用它。
答案 1 :(得分:1)
我面临类似的问题,即CPU使用率高和响应延迟。
org.apache.catalina.webresources.JarWarResourceSet:getArchiveEntries
扫描战争文件大约需要5秒钟。在扫描过程中,没有任何请求得到处理。
我已将Spring boot version
从1.4.2.RELEASE
更新为1.5.12.RELEASE
,从而解决了此问题。确实,似乎问题在于嵌入式Tomcat
在更高版本中已得到解决。
答案 2 :(得分:0)
使用可执行文件 JAR (而不是WAR)与嵌入式Tomcat一起运行可以为我解决此问题。这是recommended way,可以加快从可执行归档文件中加载资源的速度。
答案 3 :(得分:-1)
您所描述的是重新启动对使用大量数据库连接池的基础结构的典型影响。
根据您的数据,我最好的猜测是前两个步骤很慢,直到数据库池预热为止,您将遇到一些非常缓慢的查询。 可能的改进是: