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

问题描述 投票:96回答:4

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

谢谢。

caching resources tomcat8
4个回答
146
投票

在你的$CATALINA_BASE/conf/context.xml添加块下面</Context>之前

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

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


103
投票

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

1. Short Answer

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

最快的修复方法是完全禁用缓存:<Resources cachingAllowed="false" />,但这不是最理想的,所以如我刚才所述增加cacheMaxSize。

2. Long Answer

2.1背景资料

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

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

2.2原因

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

152  // Content will not be cached but we still need metadata size
153 long delta = cacheEntry.getSize();
154 size.addAndGet(delta);
156 if (size.get() > maxSize) {
157 // Process resources unordered for speed. Trades cache
158 // efficiency (younger entries may be evicted before older
159 // ones) for speed since this is on the critical path for
160 // request processing
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 // Unable to create sufficient space for this resource
167 // Remove it from the cache
168 removeCacheEntry(path);
169 log.warn(sm.getString("cache.addFail", path));
170 }
171 }

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

215  private long evict(long targetSize, Iterator<CachedResource> iter) {
217 long now = System.currentTimeMillis();
219 long newSize = size.get();
221 while (newSize > targetSize && iter.hasNext()) {
222 CachedResource resource = iter.next();
224 // Don't expire anything that has been checked within the TTL
225 if (resource.getNextCheck() > now) {
226 continue;
227 }
229 // Remove the entry from the cache
230 removeCacheEntry(resource.getWebappPath());
232 newSize = size.get();
233 }
235 return newSize;
236 }

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

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

165  if (newSize > maxSize) {
166 // Unable to create sufficient space for this resource
167 // Remove it from the cache
168 removeCacheEntry(path);
169 log.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  // Add new entry to cache
1607 synchronized (cache) {
1608 // Check cache size, and remove elements if too big
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 // Give up, no changes are made to the current cache
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. Increase cache (recommended)

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

通过在<Resources cacheMaxSize="XXXXX" />中的Context元素中添加$CATALINA_BASE/conf/context.xml,其中“XXXXX”代表增加的高速缓存大小,以kbytes为单位。默认值为10240(10 MB),因此请设置大于此值的大小。

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

为避免每次要尝试新的高速缓存大小时都必须重新启动服务器,可以使用JMX在不重新启动的情况下进行更改。

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

2.4.2. Lower the TTL (not recommended)

cacheTtl值降低到低于5000毫秒的值并调整以获得最佳设置。

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

这有效地归结为在ram中使用和填充缓存而不使用它。

2.4.3. Suppress cache log warnings (not recommended)

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

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

2.4.4. Disable cache

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

虽然我记得在Tomcat 8的测试版中,我使用JMX来禁用缓存。 (不确定原因,但是通过server.xml禁用缓存可能存在问题。)


8
投票

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

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

有关更多详细信息,请参阅documentation以获取这些配置选项。


6
投票

如果它帮助其他人,我能够解决这个问题的唯一方法是将以下内容附加到conf/logging.properties

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

这会过滤掉“无法添加资源”日志,这些日志处于警告级别。

© www.soinside.com 2019 - 2024. All rights reserved.