我刚刚将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"
/>
谢谢。
在你的$CATALINA_BASE/conf/context.xml
添加块下面</Context>
之前
<Resources cachingAllowed="true" cacheMaxSize="100000" />
有关更多信息:http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html
从Tomcat 7升级到8时,我遇到了同样的问题:关于缓存的连续大量日志警告。
在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),所以设置一个比这更高的大小。然后调整以获得警告消失的最佳设置。请注意,警告可能会在更高的交通情况下返回。
问题是由于缓存条目小于这些条目的TTL而导致Tomcat无法达到其目标缓存大小。所以Tomcat没有足够的缓存条目可以过期,因为它们太新鲜了,所以它无法释放足够的缓存,从而输出警告。
问题没有出现在Tomcat 7中,因为Tomcat 7在这种情况下根本没有输出警告。 (导致你和我在没有得到通知的情况下使用较差的缓存设置。)
与缓存的大小和TTL相比,在相对较短的时间内收到相对大量的资源HTTP请求(通常是静态)时会出现问题。如果缓存达到其最大值(默认为10mb),其大小的95%以上具有新缓存条目(新缓存意味着缓存中的时间少于5秒),那么您将收到Tomcat尝试的每个webResource的警告消息加载到缓存中。
如果需要在正在运行的服务器上调整cacheMaxSize而不重新启动它,请使用JMX。
最快的修复方法是完全禁用缓存:<Resources cachingAllowed="false" />
,但这不是最理想的,所以如我刚才所述增加cacheMaxSize。
WebSource是Web应用程序中的文件或目录。出于性能原因,Tomcat可以缓存WebSource。 maximum of the static resource cache(所有资源总共)默认为10240千字节(10 MB)。在请求webResource时(例如,在加载静态图像时)将webResource加载到缓存中,然后将其称为缓存条目。每个缓存条目都有一个TTL(生存时间),这是允许缓存条目保留在缓存中的时间。当TTL到期时,缓存条目有资格从缓存中删除。 cacheTTL的默认值为5000毫秒(5秒)。
还有更多关于缓存的信息,但这与问题无关。
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
因此,正如警告信息所述,问题是
驱逐过期的缓存条目后可用空间不足 - 考虑增加缓存的最大大小
如果您的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的(和我的)缓存设置在没有警告的情况下表现不佳。
有多种解决方案:
如下所述: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连接到服务器并查看设置设置以在服务器运行时增加缓存大小。这些设置的更改应立即生效。
将cacheTtl
值降低到低于5000毫秒的值并调整以获得最佳设置。
例如:<Resources cacheMaxSize="2000" />
这有效地归结为在ram中使用和填充缓存而不使用它。
配置日志记录以禁用org.apache.catalina.webresources.Cache
的记录器。
有关登录Tomcat的更多信息:http://tomcat.apache.org/tomcat-8.0-doc/logging.html
您可以通过将cachingAllowed
设置为false
来禁用缓存。 <Resources cachingAllowed="false" />
虽然我记得在Tomcat 8的测试版中,我使用JMX来禁用缓存。 (不确定原因,但是通过server.xml禁用缓存可能存在问题。)
如果它帮助其他人,我能够解决这个问题的唯一方法是将以下内容附加到conf/logging.properties
:
org.apache.catalina.webresources.Cache.level = SEVERE
这会过滤掉“无法添加资源”日志,这些日志处于警告级别。