I had the same problem when upgrading from Tomcat 7 to 8: a continuous large stream of cache log warnings.
TL; DR (too long, unreadable)
Decision
The best solution is to increase the cache by adding
<Resources cacheMaxSize="XXXXX" />
inside the Context element in $CATALINA_BASE/conf/context.xml , where "XXXXX" means the increased cache size specified in kilobytes. The default value is 10240 (10 megabytes), so set the size above this. Then configure the optimal settings in which the warnings disappear. Please note that alerts may appear in high traffic situations.
Use JMX if you need to configure the current server without restarting it.
The quickest fix would be to completely disable the cache: <Resources cachingAllowed="false" /> , but this is suboptimal, so increase it as I just described.
Cause
The problem is that Tomcat cannot reach its target cache cache due to cache entries that are less than the TTL of these entries. Thus, Tomcat did not have enough cache entries that could expire because they were too fresh, so it could not free enough cache and thus generated warnings.
The problem did not appear in Tomcat 7, because Tomcat 7 simply did not give warnings in this situation. (Due to the fact that you and I use poor cache settings without notification.)
The problem arises when receiving a relatively large number of HTTP requests for resources (usually static) in a relatively short period of time compared to the size and TTL of the cache. If the cache reaches its maximum (default 10 MB) with more than 95% of its size with fresh cache entries (fresh means less than 5 seconds in the cache), you will receive a warning message for every web resource that Tomcat is trying to load into the cache .
Background Information
A WebSource is a file or directory in a web application. For performance reasons, Tomcat can cache WebSources. The maximum cache of a static resource (all resources in general) by default is 10,240 kbytes (10 megabytes). WebResource is loaded into the cache when the webResource is requested (for example, when loading a static image), then it is called a cache entry. Each cache entry has a TTL (lifetime), which is the time that the cache entry remains in the cache. When the TTL expires, the cache entry can be removed from the cache. The default cacheTTL default value is 5000 milliseconds (5 seconds).
We talk more about caching, but this is not related to the problem.
Cause
The following code from the cache class details the cache policy:
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. Trade cache
158 // efficiency (younger entries may be evicted before old age
159 // for speed, as this is on a critical path for
160 // processing request
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 enough space for this resource
167 // Delete It From The Cache
168 removeCacheEntry (path);
169 magazine. warn (see getString ("cache.addFail", path));
170 }
171 }
When loading webResource, the code calculates the new cache size. If the calculated size is larger than the default maximum size, you must delete one or more cached entries, otherwise the new size will exceed the maximum. Thus, the code will calculate "targetSize", which is a cache that wants to remain under (as optimal), which by default is 95% of the maximum. To achieve this targetSize, entries must be deleted / cached. This is done using the following code:
215 closed long evict ( long targetSize, Iterator < CachedResource > iter) {
217 currentTimeMillis ();
219 long newSize = size. get ();
"http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/8.0.24/org/apache/catalina/webresources/Cache.java#221" rel = " noreferrer "> 221 while (newSize> targetSize & iter. hasNext ()) {
222 CachedResource resource = iter. next ();
224 // Do not expire anything that was checked in TTL
225 if (resource getNextCheck ()>) {
226 continue ;
227 }
229 // Delete entry from cache
230 removeCacheEntry (resource getWebappPath ());
232 newSize = si ze. get ();
233 }
235 return newSize;
236 }
Thus, the cache entry is deleted when the TTL expires, and targetSize has not yet been reached.
After attempting to free the cache, displacing the cache entries, the code will do:
165 if (newSize> maxSize) {
166 // Unable to create enough space for this resource
167 // Delete It From The Cache
168 removeCacheEntry (path);
169 . warn (see getString ("cache.addFail", path);
170 } So, if after trying to free the cache, the size still exceeds the maximum, it will show a warning about the impossibility of freeing:
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
Problem
As the warning message says, the problem is
Insufficient free space available after evicting expired cache entries - consider increasing the maximum cache size
If your web application loads a lot of unencrypted web resources (about the maximum cache, by default 10 MB) in a short time (5 seconds), you will receive a warning.
The confusing part is that Tomcat 7 did not display a warning. This is simply caused by this Tomcat 7 code:
1606 // Add a new entry to the cache
1607 synchronized (cache) {
1608 // Check cache size and delete items if they are too large
1609 if ((cache. Lookup (name) == null ) && cache. Allocate (entry.size)) {
1610 cache. load (write); 1611 }
1612 }
in conjunction with:
231 while (toFree> 0) {
232 if (attempts == maxAllocateIterations) {
233 // Refuse, no changes have been made to the current cache
234 return false ;
235 }
So, Tomcat 7 just does not display any warnings when it cannot free the cache, while Tomcat 8 issues a warning.
So, if you use Tomcat 8 with the same default caching configuration as Tomcat 7, and you get warnings in Tomcat 8, and your (and mine) Tomcat 7 caching settings performed poorly without warning.
Decision
There are several solutions:
- Increase cache (recommended)
- Lower TTL (not recommended)
- Disable warnings in logbook (not recommended)
- Disable cache
1. Increase cache (recommended)
As described here: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html
By adding <Resources cacheMaxSize="XXXXX" /> to the Context element in $CATALINA_BASE/conf/context.xml , where "XXXXX" means the increased cache size specified in kilobytes. The default value is 10240 (10 megabytes), so set the size above this.
You need to configure the optimal settings. Please note that the problem may occur when there is a sudden increase in traffic / resource requests.
In order not to restart the server every time you want to try a new cache size, you can change it without restarting using JMX.
To enable JMX , add this to $CATALINA_BASE/conf/server.xml in the Server element: <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" /> and download catalina-jmx-remote.jar from https://tomcat.apache.org/download-80.cgi and put it in $CATALINA_HOME/lib . Then use jConsole (supplied by default with the Java JDK) to connect via JMX to the server and view the settings to increase the cache size while the server is running. Changes to these settings should immediately affect.
2. Lower the TTL (not recommended)
Lower the cacheTtl value to less than 5000 milliseconds and tune to the optimal settings.
For example: <Resources cacheMaxSize="2000" />
This effectively depends on the presence and filling of the cache in ram without using it.
3. Disable warnings in the logbook (not recommended)
Set up logging to disable logging for org.apache.catalina.webresources.Cache .
Learn more about registering with Tomcat: http://tomcat.apache.org/tomcat-8.0-doc/logging.html
4. Disable cache
You can disable the cache by setting cachingAllowed to false . <Resources cachingAllowed="false" />
Although I remember that in Tomcat 8 beta I used JMX to disable the cache. (I donβt know why, but there may be a problem with disabling the cache through server.xml.)