2 回答
TA贡献1911条经验 获得超7个赞
35 毫秒听起来像是涉及磁盘访问时间,这表明操作系统缓存存在问题。
类路径上是否有任何目录/非 jar 条目可能会减慢速度。此外,如果资源不存在于检查的第一个位置。
ClassLoader.getResource
如果您可以通过配置(我已经多年没有接触 tomcat)或只是设置线程上下文类加载器,则可以覆盖Thread.setContextClassLoader
。
TA贡献1852条经验 获得超7个赞
我可以再花 30 分钟来调试这个问题,并研究 Tomcat 如何进行资源缓存。
我特别CachedResource.validateResources感兴趣(可以在上面的火焰图中找到)。true如果CachedResource仍然有效则返回:
protected boolean validateResources(boolean useClassLoaderResources) {
long now = System.currentTimeMillis();
if (this.webResources == null) {
...
}
// TTL check here!!
if (now < this.nextCheck) {
return true;
} else if (this.root.isPackedWarFile()) {
this.nextCheck = this.ttl + now;
return true;
} else {
return false;
}
}
看起来CachedResource实际上有一个生存时间 (ttl)。实际上Tomcat中有一种方法可以配置cacheTtl ,但你只能增加这个值。资源缓存配置看起来并不那么灵活。
所以我的Tomcat配置了默认值5000毫秒。这在进行性能测试时欺骗了我,因为我的请求之间有 5 秒多一点的时间(查看图表和其他内容)。这就是为什么我的所有请求基本上都在没有缓存的情况下运行,并且ZipFile.open
每次都会触发如此繁重的操作。
因此,由于我对 Tomcat 配置并不是很有经验,所以我还不确定什么是正确的解决方案。增加cacheTTL可以使缓存更长,但从长远来看并不能解决问题。
概括
我认为这里实际上有两个罪魁祸首。
FactoryFinder 类不重用 ServiceLoader。他们不重复使用它们可能是有正当理由的——但我实在想不出一个原因。
Tomcat 在固定时间后驱逐 Web 应用程序资源的缓存(类路径中的文件 - 就像
ServiceLoader
配置)
再加上没有为 ServiceLoader 类定义系统属性,您每秒都会收到一次缓慢的 FactoryFinder 调用cacheTtl
。
现在我可以忍受将cacheTtl 增加到更长的时间。我也可能会看看 Tom Hawtins 的重写建议,Classloader.getResources
即使我认为这是摆脱性能瓶颈的一种严厉方式。不过,这可能值得一看。
添加回答
举报