抛出Tomcat 8-org.apache.catalina.webresources.Cache.getResource无法添加资源


111

我刚刚将Tomcat从7.0.52版本升级到8.0.14。

我得到了很多静态图像文件:

org.apache.catalina.webresources.Cache.getResource无法将[/base/1325/WA6144-150x112.jpg]处的资源添加到缓存中,因为收回过期的缓存条目后可用空间不足-请考虑增加最大大小缓存的

我没有指定任何特定的资源设置,而对于7.0.52我没有得到它。

我发现在启动时的错误报告中提到了这种情况,该错误报告应该已修复。对我来说,这不是在启动时发生的,而是在请求资源时不断发生的。

还有其他人遇到这个问题吗?

尝试至少仅禁用缓存,但是我找不到如何指定不使用缓存的示例。该属性已从Tomcat 8版的上下文中删除。尝试添加资源,但无法获得正确的配置。

<Resource name="file" 
    cachingAllowed="false"
    className="org.apache.catalina.webresources.FileResourceSet"
/>  

谢谢。


没有回复-我想我必须是这个问题的唯一人。
iainmac999


1
关于Tomcat 8上下文中缺少的属性,这是迁移指南(重点是我的摘录)的摘录:“ 资源的重构还导致许多属性从默认Context实现中删除(org.apache.catalina.core 现在可以通过“ Web应用程序使用的资源实现来配置以下属性。有关迁移指南的更多信息。
informatik01

@ iainmac999在两年后没有选择正确答案的情况下,我们可以同意它双向有效吗?
davidjmcclelland

Answers:



152

从Tomcat 7升级到8时,我遇到了同样的问题:有关缓存的日志警告不断泛滥。

1.简短答案

将其添加Context到您的xml元素中$CATALINA_BASE/conf/context.xml

<!-- The default value is 10240 kbytes, even when not added to context.xml.
So increase it high enough, until the problem disappears, for example set it to 
a value 5 times as high: 51200. -->
<Resources cacheMaxSize="51200" />

因此默认值是10240(10 MB),因此请设置更大的大小。调整一下警告消失的最佳设置。请注意,在交通流量较高的情况下,警告可能会再次出现。

1.1原因(简短说明)

此问题是由于由于缓存条目小于那些条目的TTL而导致Tomcat无法达到其目标缓存大小而引起的。因此,Tomcat没有足够的缓存条目使其过期,因为它们太新了,因此它无法释放足够的缓存并因此输出警告。

在Tomcat 7中没有出现该问题,因为在这种情况下Tomcat 7根本没有输出警告。(导致您和我使用不良的缓存设置而未收到通知。)

与缓存的大小和TTL相比,在相对较短的时间内收到相对大量的HTTP资源请求(通常是静态的)时,就会出现问题。如果高速缓存已达到其最大容量(默认为10mb),并且具有大于95%的大小(带有新鲜的高速缓存条目)(“新鲜”表示小于5秒的高速缓存),那么对于Tomcat尝试的每个webResource,您都会收到一条警告消息加载到缓存中。

1.2可选信息

如果需要在运行的服务器上调整cacheMaxSize而不重新引导它,请使用JMX。

最快的解决方法是完全禁用cache <Resources cachingAllowed="false" />:,但这不是最理想的,所以请增加我刚刚描述的cacheMaxSize。

2.长答案

2.1背景资料

一个WebSource是在Web应用程序中的文件或目录。出于性能原因,Tomcat可以缓存WebSource。默认情况下,静态资源缓存最大值(所有资源总计)为10240 KB(10 MB)。当请求webResource时(例如,加载静态图像时),会将webResource加载到缓存中,然后将其称为缓存条目。每个缓存条目都有一个TTL(生存时间),TTL是允许缓存条目保留在缓存中的时间。TTL过期后,可以从缓存中删除缓存条目。cacheTTL的默认值为5000毫秒(5秒)。

关于缓存,还有更多要说的,但这与问题无关。

2.2原因

Cache类中的以下代码详细显示了缓存策略:

152   //内容将不会被缓存,但是我们仍然需要元数据大小
153 long delta = cacheEntry。getSize();
154 尺寸。addAndGet(delta);
156 如果(大小。得到()> MAXSIZE){
157个 //处理资源无序速度。交易缓存
158 //效率(年轻的条目可以之前旧的逐出
159级 //的)速度,因为这是在关键路径上
160 //请求处理
161 的targetSize =
162 maxSize *(100-TARGET_FREE_PERCENT_GET)/ 100;
163 新尺寸= 逐出
164 的targetSize,resourceCache。()。迭代器());
165 if(newSize> maxSize){
166 //无法为此资源创建足够的空间
167 //从缓存中删除它
168 removeCacheEntry(path);
169个 日志。警告(SM。的getString( “cache.addFail”路径));
170 }
171 }

加载webResource时,代码将计算缓存的新大小。如果计算的大小大于默认的最大大小,则必须删除一个或多个缓存条目,否则新大小将超过最大大小。因此,代码将计算“ targetSize”,即缓存要保留的大小(最佳),默认为最大值的95%。为了达到此targetSize,必须从缓存中删除/删除条目。使用以下代码完成此操作:

215   私人 long evct (long targetSize,Iterator < CachedResource > iter){ 
217 long now =系统。currentTimeMillis();
219 long newSize =大小。得到();
221 (新尺寸>的targetSize && ITER。hasNext()){
222 CachedResource资源= ITER。next();
224 //不会过期已在TTL内检查什么
225 ,如果(资源。getNextCheck()>现在){
226 继续 ;
227 }
229 //从缓存中删除该条目
230 removeCacheEntry(资源。getWebappPath());
232 newSize =大小。得到();
233 }
235 返回 newSize;
236 }

因此,当TTL过期且尚未达到targetSize时,将删除一个缓存条目。

在尝试通过逐出缓存条目来释放缓存后,代码将执行以下操作:

165   if(newSize> maxSize){ 
166 //无法为此资源创建足够的空间
167 //从缓存中删除它
168 removeCacheEntry(path);
169个 日志。警告(SM。的getString( “cache.addFail”路径));
170 }

因此,如果尝试释放缓存后大小仍然超过最大值,它将显示有关无法释放的警告消息:

cache.addFail=Unable to add the resource at [{0}] to the cache for web application [{1}] because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache

2.3问题

因此,如警告消息所示,问题是

收回过期的缓存条目后可用空间不足-请考虑增加缓存的最大大小

如果您的Web应用程序在短时间内(5秒)内加载了许多未缓存的webResources(大约为最大缓存,默认为10mb),那么您将收到警告。

令人困惑的是,Tomcat 7没有显示警告。这仅仅是由Tomcat 7代码引起的:

1606   //添加新条目缓存
1607 同步(缓存){
1608 //检查缓存大小,和删除元素,如果过大
1609 ,如果((缓存。查找(名称)== )&&缓存。分配(entry.size) ){
1610 缓存。加载(输入);
1611 }
1612 }

结合:

231   while(toFree> 0){ 
232 if(attempts == maxAllocateIterations){
233 //放弃,对当前缓存不做任何更改
234 return false ;
235 }

因此,当Tomcat 7无法释放缓存时,它根本不会输出任何警告,而Tomcat 8则会输出警告。

因此,如果您使用的Tomcat 8具有与Tomcat 7相同的默认缓存配置,并且在Tomcat 8中收到警告,则Tomcat 7的(和我的)缓存设置会在没有警告的情况下表现不佳。

2.4解决方案

有多种解决方案:

  1. 增加缓存(推荐)
  2. 降低TTL(不推荐)
  3. 禁止缓存日志警告(不建议)
  4. 禁用缓存

2.4.1。增加缓存(推荐)

如此处所述:http : //tomcat.apache.org/tomcat-8.0-doc/config/resources.html

通过加入<Resources cacheMaxSize="XXXXX" />所述内Context中元件$CATALINA_BASE/conf/context.xml,其中“XXXXX”代表增加的高速缓存大小,在千字节指定。默认值为10240(10 MB),因此请设置更大的大小。

您必须调整以获得最佳设置。请注意,当您的流量/资源请求突然增加时,问题可能会再次出现。

为了避免每次要尝试新的缓存大小时都必须重新启动服务器,可以更改它而无需使用JMX重新启动。

启用JMX,这增加$CATALINA_BASE/conf/server.xml了内部Server元件: <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" />和下载 catalina-jmx-remote.jarhttps://tomcat.apache.org/download-80.cgi并把它$CATALINA_HOME/lib。然后使用jConsole(默认情况下Java JDK附带)通过JMX连接到服务器,并浏览设置的设置以在服务器运行时增加缓存大小。这些设置的更改应立即生效。

2.4.2。降低TTL(不推荐)

将该cacheTtl值降低至小于5000毫秒,然后进行调整以获得最佳设置。

例如: <Resources cacheTtl="2000" />

这实际上归结为在不使用ram的情况下拥有并填充了缓存。

2.4.3。禁止缓存日志警告(不建议)

配置日志记录以禁用的记录器org.apache.catalina.webresources.Cache

有关登录Tomcat的更多信息:http : //tomcat.apache.org/tomcat-8.0-doc/logging.html

2.4.4。禁用缓存

您可以通过设置cachingAllowed为禁用缓存false<Resources cachingAllowed="false" />

尽管我记得在Tomcat 8的Beta版中,但我使用的是JMX来禁用缓存。(不确定为什么会这样,但是通过server.xml禁用缓存可能会出现问题。)


增加缓存?我怀疑这是否行得通...我看到了:private long maxSize = 10 * 1024 * 1024; 在源中。grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/...
HoaPhan

您是否找到了为什么tomcat8会泛滥缓存警告的答案
PHP Avenger,

对于所有高速缓存,@ HoaPhan 10 * 1024 * 1024最多为10mb。根据网络应用的流量,可以在几秒钟内达到此目的。将其增加足够远将起作用。
Devabc

@PHPAvenger在此情况下,Tomcat 7完全没有发出警告,而Tomcat 8则发出了警告,因此可以将其视为警告功能。问题在于它不仅会警告一次,而且还会在每个要缓存的资源请求时发出警告。仅在达到一定时间或缓存目标命中后才发出警告,这将是一项改进。
Devabc

@Devabc完美的答案!如此经典!
拉夫

9

您有更多静态资源可供缓存使用。您可以执行以下操作之一:

  • 增加缓存的大小
  • 减少缓存的TTL
  • 禁用缓存

有关更多详细信息,请参阅这些配置选项的文档


1
感谢您的评论。我确实了解该异常的含义,当然我确实阅读了您链接到的文档,但是我不明白为什么在不进行配置更改的情况下将其从7更改为8。也就是说,为什么默认的文件系统资源处理程序在8到7之间有所不同,而没有引用任何更改,并且报告了启动错误并据称已修复,这令人怀疑。
iainmac999 2014年

1
也许,如果您已阅读迁移指南-特别是tomcat.apache.org/migration-8.html#Web_application_resources-情况将会更加清楚。
马克·托马斯

如果文档做得更多,这将对以下方面有所帮助:a)解释将哪些资源放入此缓存中,以及为什么(很多误解!)和b)不同设置可能产生什么影响(例如,仅盲目地设置每个webapp的缓存设置)很大会吃掉大量的内存),以及如何正确调整内存。如果在应用程序本身使用的缓存静态资源与用户代理请求的静态文件(仅由应用程序交付)之间的代码和配置方面存在区别,这也将有所帮助。
Volkerk

4

从某种意义上说,这不是解决方案,因为它不能解决导致消息出现在日志中的条件,但是可以通过将以下内容附加到来抑制消息conf/logging.properties

org.apache.catalina.webresources.Cache.level = SEVERE

这将过滤掉“警告”级别的“无法添加资源”日志。

在我看来,a WARNING不一定是需要解决的错误,而是在需要时可以忽略。


8
哈哈。这不能解决问题。它只是不显示它。WTF!
T3rm1 '18年

这解决了日志过多的问题,而日志本身可能是一个重大问题。它返回到以前的tomcat版本的行为,该行为对于许多人来说运行良好,因此从某种意义上说可以“解决”问题。它没有解决实际调整tomcat缓存的问题,devabc的答案很好地解决了这个问题。
Volkerk
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.