我的 Spring Boot 应用程序出现了一个奇怪的行为:
- 前端/客户端 - 角度 6
- 后端 - spring boot - spring MVC - 嵌入式 tomcat - Linux
重启后端后,对 Controller 的第一次调用大约需要 5 秒,以下相同的请求只需要 50 毫秒。这在 90% 的情况下是可重现的,有时甚至第一次调用也很快。
我确定,问题出在服务器上而不是客户端上。在浏览器上,我看到 TTFB 时间(到第一个字节的时间)增加到 5 秒。以下请求只需要 10ms 的 TTFB。
使用服务器上的监控工具(应用程序动态),我可以收集如此缓慢的服务器调用,并且在调用图上我可以看到:
org.apache.catalina.webresources.JarWarResourceSet:getArchiveEntries:117
需要 4916 毫秒。所以这是我的瓶颈,我想。但我不知道如何解决它。
我已经尝试过的:
- 从 hikaricp 切换到 apache tomcat jdbc 连接池
- 将 Spring Boot 从 2.0.0 升级到 2.0.5
- 将 java 升级到 1.8.0_181
- 属性 spring.jpa.tomcat.testOnBorrow = true
- 属性 spring.jpa.tomcat.validationQuery = 选择 1
一切都不会影响服务器延迟。
更新
由于war文件被多次扫描而导致时间丢失。
org.apache.catalina.webresources.CachedResource.validateResource 正在检查我们是否有一个 war 文件 (isPackedWarFile),这个检查返回 false。即使它是一个 war 文件。对于这种行为不端,我有一个解决方法。我将 tomcat.resource.cache-tt 设置为高值。
但是现在 org.apache.catalina.webresources.Cache.getResource 有一个 noCache 方法。在这种方法中,class 和 jar 文件被排除在缓存之外。这就是再次扫描war文件的原因。
扫描整个 war 文件大约需要 5 秒。而这个突破是一个停止世界的突破。而且这种扫描是完全没有必要的,因为war文件没有被炸开,所以它的内容也不能改变。
更新
如果我将 war 文件放入 tomcat 安装中,一切都会很快。嵌入式tomcat就是问题所在。
最佳答案
我想你已经这样做了,但如果你还没有,看看 https://cwiki.apache.org/confluence/display/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(...);
}
}
这样,您的客户端将不再遇到 5s 延迟。我知道这是一个 hack,所以如果你找到一种更简洁的方法来代替它。
关于spring - 性能 - Spring Boot - 服务器响应时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52648831/