【问题标题】:Tomcat 8 throwing - org.apache.catalina.webresources.Cache.getResource Unable to add the resourceTomcat 8 抛出 - org.apache.catalina.webresources.Cache.getResource 无法添加资源
【发布时间】:2015-01-09 16:17:03
【问题描述】:

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

谢谢。

【问题讨论】:

  • 没有回复 - 我想我一定是唯一遇到这个问题的人。
  • 解决方案在这里:serverfault.com/questions/644415/…
  • 关于 Tomcat 8 上下文中缺少的属性,这里是迁移指南的摘录(重点是我的):“资源的重构也导致了的属性数量从默认上下文实现中删除 (org.apache.catalina.core.StandardContext)。以下属性现在可以通过Web应用程序使用的资源实现配置“ .更多信息在相关migration guid
  • @iainmac999 在 2 年后从未选择过正确的答案,我们可以同意它是双向的吗?

标签: caching resources tomcat8


【解决方案1】:

从 Tomcat 7 升级到 8 时,我遇到了同样的问题:关于缓存的大量日志警告持续泛滥。

1。简答

$CATALINA_BASE/conf/context.xmlContext 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。

最快的解决方法是完全禁用缓存:&lt;Resources cachingAllowed="false" /&gt;,但这不是最理想的,所以按照我刚才的描述增加 cacheMaxSize。

2。长答案

2.1 背景资料

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

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

2.2 原因

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

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

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

215 private long evict(long targetSize, IteratorCachedResource> iter) {
@987654357 @ long now = System.currentTimeMillis();
219 long newSize = size.get();
221 while (newSize > targetSize && iter.hasNext()) {
222 CachedResource resource = iter.next();
224 // 不要' t 过期 TTL 内检查的任何内容
225 if (resource.getNextCheck() > now) {
226 continue ;
227 }
229 // 从缓存中删除条目
230 removeCacheEntry(resource.getWebappPath());
232 newSize = size .get();
233 }
235 返回 newSize;
236 }

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

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

165 if (newSize > maxSize) {
166 // 无法为该资源创建足够的空间
167 // 将其从缓存中移除168removeCacheEntry(路径);
169log.warn(sm.getString("cache.addFail", path));
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 if ((cache.lookup(name) == null) && cache.allocate(entry.size)) {
1610 cache.load(entry);
1611 }
1612 }

结合:

231 while (toFree > 0) {
232 if (attempts == maxAllocateIterations) {
233 // 给up,不会对当前缓存做任何更改
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

通过在$CATALINA_BASE/conf/context.xmlContext 元素中添加&lt;Resources cacheMaxSize="XXXXX" /&gt;,其中“XXXXX”代表增加的缓存大小,以千字节为单位。默认值为 10240(10 mbyte),因此请设置比此更大的大小。

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

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

对于enable JMX,将其添加到$CATALINA_BASE/conf/server.xmlServer 元素中: &lt;Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" /&gt; 并从https://tomcat.apache.org/download-80.cgi 下载catalina-jmx-remote.jar 并将其放入$CATALINA_HOME/lib。 然后使用 jConsole(默认情况下随 Java JDK 提供)通过 JMX 连接到服务器,并在服务器运行时查看设置以增加缓存大小。这些设置的更改应立即生效。

2.4.2。降低 TTL(不推荐)

cacheTtl 的值降低小于 5000 毫秒并调整为最佳设置。

例如:&lt;Resources cacheTtl="2000" /&gt;

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

2.4.3。禁止缓存日志警告(不推荐)

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

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

2.4.4。禁用缓存

您可以通过将cachingAllowed 设置为false 来禁用缓存。 &lt;Resources cachingAllowed="false" /&gt;

虽然我记得在 Tomcat 8 的 beta 版本中,我使用 JMX 来禁用缓存。 (不知道为什么,但是通过 server.xml 禁用缓存可能会出现问题。)

【讨论】:

  • 增加缓存?我怀疑它会起作用......我看到了这个: private long maxSize = 10 * 1024 * 1024;在源头。 grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/…
  • 你找到tomcat8为什么会泛滥缓存警告的答案了吗
  • @HoaPhan 10*1024*1024 是所有缓存总共最大 10mb。根据 webapp 的流量,这可以在几秒钟内达到。将它增加到足够多,将起作用。
  • @PHPAvenger Tomcat 7 在这种情况下根本没有发出警告,而 Tomcat 8 发出了警告,因此可以将其视为警告功能。问题是它不仅会发出警告,而且会在每次缓存资源请求时发出警告。仅在一定时间或缓存目标命中后才发出警告将是一种改进。
  • @Devabc 完美答案!太经典了!
【解决方案2】:

在您的$CATALINA_BASE/conf/context.xml 之前的&lt;/Context&gt; 之前添加块

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

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

【讨论】:

  • 个别读者可能希望将 cacheMaxSize 值调整为小于 100 兆。
  • 到目前为止,错误消息正在淹没我的控制台日志。现在很清楚了。谢谢
【解决方案3】:

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

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

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

【讨论】:

  • 感谢您的评论。我确实理解异常的含义,当然我确实阅读了您链接到的文档,但是我不明白为什么这会在没有配置更改的情况下从 7 更改为 8。也就是说,为什么默认的文件系统资源处理程序在 8 到 7 中会有所不同,没有参考任何更改,并且报告了启动错误并据称已修复是可疑的。
  • 也许如果您阅读了迁移指南 - 特别是 tomcat.apache.org/migration-8.html#Web_application_resources - 事情会更清楚。
  • 如果文档对 a) 解释哪些资源进入此缓存以及为什么(对此存在很多误解!)以及 b) 不同设置可能产生的影响(例如,只是盲目地使每个 webapp 的缓存设置相当大会消耗大量内存)以及如何正确调整它。如果在缓存应用程序本身使用的静态资源与用户代理请求并仅由应用程序交付的静态文件之间存在代码和配置差异,这也会有所帮助。
【解决方案4】:

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

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

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

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

【讨论】:

  • 哈哈。这并不能解决问题。它只是没有显示出来。见鬼!
  • 这解决了过度记录的问题,这本身就是一个严重的问题。它返回到以前的 tomcat 版本的行为,对于许多人来说,事情已经足够好,所以从这个意义上说,它“解决”了问题。它没有解决实际调整 tomcat 缓存的问题,devabc 的回答很好地涵盖了这个问题。
猜你喜欢
  • 2017-10-13
  • 1970-01-01
  • 2020-03-22
  • 2014-06-02
  • 2017-05-16
  • 1970-01-01
  • 2012-08-10
  • 2014-08-02
  • 1970-01-01
相关资源
最近更新 更多