131

我刚刚将 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"
/>  

谢谢。

4

4 回答 4

204

从 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 mbyte),所以设置一个比这个大的大小。然后调整到警告消失的最佳设置。请注意,警告可能会在交通繁忙的情况下再次出现。

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 kbyte (10 mbyte)。当请求 webResource 时(例如加载静态图像时),将 webResource 加载到缓存中,然后将其称为缓存条目。每个缓存条目都有一个TTL(生存时间),即允许缓存条目留在缓存中的时间。当 TTL 过期时,缓存条目有资格从缓存中删除。cacheTTL 的默认值为 5000 毫秒(5 秒)。

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

2.2 原因

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

152   // 内容不会被缓存,但我们仍然需要元数据大小
153 long delta = cacheEntry. 获取大小();
154 尺寸。addAndGet(增量);
156 if ( size.get () > maxSize) {
157 // 处理资源无序以提高速度。交易缓存
158 // 效率(较旧的条目可能在较旧的
159 // 之前被驱逐)以提高速度,因为这是
160 // 请求处理的关键路径
161 long targetSize =
162 maxSize * (100 - TARGET_FREE_PERCENT_GET) / 100;
163 long newSize = evict (
164 targetSize, resourceCache.values ( ). iterator ()); 165 if (newSize > maxSize) { 166 // 无法为该资源创建足够的空间167 // 将其从缓存中移除168 removeCacheEntry (path); 169 日志。警告sm.getString(“cache.addFail”,路径));170 } 171 }







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

215   private  long evict( long targetSize, Iterator < CachedResource > iter) { 
217 long now = System. 当前时间米利斯();
219 newSize = 大小。得到();
221 while (newSize > targetSize && iter.hasNext ( )) {
222 CachedResource资源 = iter. 下一个();
224 // 不要过期在 TTL
225内检查过的任何内容 if (resource.getNextCheck ( ) > now) {
226 继续
227 }
229 // 从缓存中移除条目
230 removeCacheEntry (resource.getWebappPath ( ));
第232得到();
233 }
235 返回新尺寸;
第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 synchronized (cache) {
1608 // 检查缓存大小,如果太大则删除元素
1609 if ( (cache.lookup (name) == null ) && cache.allocate ( entry.size ) ) { 1610 缓存。加载(条目);1611 } 1612 }



结合:

231   while (toFree > 0) { 
232 if (attempts == maxAllocateIterations) {
233 // 放弃,不改变当前缓存
234 return false ;
第235

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

因此,如果您使用具有与 Tomcat 7 相同的默认缓存配置的 Tomcat 8,并且在 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 兆字节),因此请设置比此更大的大小。

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

为避免每次要尝试新的缓存大小时都必须重新启动服务器,您可以使用 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" />

这实际上归结为在不使用内存的情况下在内存中拥有和填充缓存。

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 禁用缓存可能会出现问题。)

于 2014-12-04T17:54:49.420 回答
169

在您$CATALINA_BASE/conf/context.xml之前的添加块中</Context>

<Resources cachingAllowed="true" cacheMaxSize="100000" />

更多信息:http: //tomcat.apache.org/tomcat-8.0-doc/config/resources.html

于 2016-06-23T08:38:16.067 回答
10

你有更多的静态资源,缓存有空间。您可以执行以下操作之一:

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

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

于 2014-11-13T21:46:24.247 回答
6

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

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

这会过滤掉级别为 WARNING 的“无法添加资源”日志。

在我看来,aWARNING不一定是需要解决的错误,但如果需要可以忽略。

于 2016-04-26T23:06:25.537 回答