Ich hatte das gleiche Problem beim Upgrade von Tomcat 7 auf 8: eine kontinuierlich große Flut von Protokollwarnungen über den Cache.
1. Kurze Antwort
Fügen Sie dies in das Context
XML-Element Ihres $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" />
Der Standardwert ist also 10240
(10 MB). Stellen Sie daher eine höhere Größe ein. Stellen Sie dann die optimalen Einstellungen ein, bei denen die Warnungen verschwinden. Beachten Sie, dass die Warnungen in Situationen mit höherem Verkehr möglicherweise wieder auftreten.
1.1 Die Ursache (kurze Erklärung)
Das Problem wird dadurch verursacht, dass Tomcat die Ziel-Cache-Größe aufgrund von Cache-Einträgen, die unter der TTL dieser Einträge liegen, nicht erreichen kann. Daher hatte Tomcat nicht genügend Cache-Einträge, die ablaufen konnten, weil sie zu frisch waren, sodass nicht genügend Cache freigegeben werden konnte, und gab daher Warnungen aus.
Das Problem trat in Tomcat 7 nicht auf, da Tomcat 7 in dieser Situation einfach keine Warnungen ausgab. (Verursacht, dass Sie und ich schlechte Cache-Einstellungen verwenden, ohne benachrichtigt zu werden.)
Das Problem tritt auf, wenn in relativ kurzer Zeit eine relativ große Anzahl von HTTP-Anforderungen für Ressourcen (normalerweise statisch) empfangen wird, verglichen mit der Größe und TTL des Caches. Wenn der Cache mit mehr als 95% seiner Größe mit neuen Cache-Einträgen sein Maximum erreicht (standardmäßig 10 MB) (frisch bedeutet weniger als 5 Sekunden im Cache), erhalten Sie für jede von Tomcat versuchte webResource eine Warnmeldung in den Cache laden.
1.2 Optionale Informationen
Verwenden Sie JMX, wenn Sie cacheMaxSize auf einem laufenden Server optimieren müssen, ohne ihn neu zu starten.
Die schnellste Lösung wäre, den Cache vollständig zu deaktivieren: <Resources cachingAllowed="false" />
aber das ist nicht optimal. Erhöhen Sie also cacheMaxSize, wie ich es gerade beschrieben habe.
2. Lange Antwort
2.1 Hintergrundinformationen
Eine WebSource ist eine Datei oder ein Verzeichnis in einer Webanwendung. Aus Leistungsgründen kann Tomcat WebSources zwischenspeichern. Das Maximum des statischen Ressourcencaches (alle Ressourcen insgesamt) beträgt standardmäßig 10240 KByte (10 MByte). Eine webResource wird in den Cache geladen, wenn die webResource angefordert wird (z. B. beim Laden eines statischen Bildes). Sie wird dann als Cache-Eintrag bezeichnet. Jeder Cache-Eintrag verfügt über eine TTL (Time to Live). Dies ist die Zeit, zu der der Cache-Eintrag im Cache verbleiben darf. Wenn die TTL abläuft, kann der Cache-Eintrag aus dem Cache entfernt werden. Der Standardwert von cacheTTL beträgt 5000 Millisekunden (5 Sekunden).
Es gibt mehr über das Caching zu erzählen, aber das ist für das Problem irrelevant.
2.2 Die Ursache
Der folgende Code aus der Cache-Klasse zeigt die Caching-Richtlinie im Detail:
152 // Inhalt wird nicht zwischengespeichert, aber wir benötigen noch Metadatengröße
153 long delta = cacheEntry. getSize ();
154 Größe. addAndGet (Delta);
156 if (size. Get ()> maxSize) {
157 // Verarbeite Ressourcen ungeordnet nach Geschwindigkeit. Trades Cache
158 // Effizienz (jüngere Einträge können vor älteren
159 // entfernt werden) für Geschwindigkeit, da dies auf dem kritischen Pfad für
160 // Anforderungsverarbeitung
161 long targetSize =
162 maxSize * (100 - TARGET_FREE_PERCENT_GET) / 100 ist;
163 lange newSize = evict (
164 . TargetSize, resourceCache Werte (). Iterator ());
165 if (newSize> maxSize) {
166 // Es kann nicht genügend Speicherplatz für diese Ressource erstellt werden
167 // Aus dem Cache entfernen
168 removeCacheEntry (path);
169 log. warn (sm. getString ("cache.addFail", Pfad));
170 }
171 }
Beim Laden einer webResource berechnet der Code die neue Größe des Caches. Wenn die berechnete Größe größer als die standardmäßige maximale Größe ist, müssen ein oder mehrere zwischengespeicherte Einträge entfernt werden, andernfalls überschreitet die neue Größe das Maximum. Der Code berechnet also eine "Zielgröße", dh die Größe, unter der der Cache bleiben soll (als Optimum), was standardmäßig 95% des Maximums entspricht. Um diese Zielgröße zu erreichen, müssen Einträge aus dem Cache entfernt / entfernt werden. Dies erfolgt mit dem folgenden Code:
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 // Läuft nichts ab, was in der TTL
225 überprüft wurde, wenn (resource. GetNextCheck ()> now) {
226 weiter ;
227 }
229 // Entferne den Eintrag aus dem Cache
230 removeCacheEntry (resource. GetWebappPath ());
232 newSize = Größe. get ();
233 }
235 return newSize;
236 }
Ein Cache-Eintrag wird also entfernt, wenn seine TTL abgelaufen ist und die Zielgröße noch nicht erreicht wurde.
Nach dem Versuch, den Cache durch Entfernen von Cache-Einträgen freizugeben, führt der Code Folgendes aus:
165 if (newSize> maxSize) {
166 // Es kann nicht genügend Speicherplatz für diese Ressource erstellt werden
167 // Aus dem Cache entfernen
168 removeCacheEntry (path);
169 log. warn (sm. getString ("cache.addFail", Pfad));
170 }
Wenn also nach dem Versuch, den Cache freizugeben, die Größe immer noch das Maximum überschreitet, wird die Warnmeldung angezeigt, dass die Freigabe nicht möglich ist:
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 Das Problem
Wie die Warnmeldung sagt, ist das Problem
Nach dem Entfernen abgelaufener Cache-Einträge ist nicht genügend freier Speicherplatz verfügbar. Erhöhen Sie möglicherweise die maximale Größe des Caches
Wenn Ihre Webanwendung innerhalb kurzer Zeit (5 Sekunden) viele nicht zwischengespeicherte webResources (maximal Cache, standardmäßig 10 MB) lädt, wird die Warnung angezeigt.
Der verwirrende Teil ist, dass Tomcat 7 die Warnung nicht angezeigt hat. Dies wird einfach durch diesen Tomcat 7-Code verursacht:
1606 // Neuer Eintrag in den Cache
1607 synchronisiert (Cache) {
1608 // überprüfen Cache - Größe, und entfernen Elemente , wenn sie zu groß
1609 , wenn ((Cache. Lookup (name) == null ) && Cache. Zuteilen (entry.size) ) {
1610 Cache. Laden (Eintrag);
1611 }
1612 }
kombiniert mit:
231 while (toFree> 0) {
232 if (Versuche == maxAllocateIterations) {
233 // Aufgeben, es werden keine Änderungen am aktuellen Cache vorgenommen
234 return false ;
235 }
Daher gibt Tomcat 7 einfach überhaupt keine Warnung aus, wenn der Cache nicht freigegeben werden kann, während Tomcat 8 eine Warnung ausgibt.
Wenn Sie also Tomcat 8 mit derselben Standard-Caching-Konfiguration wie Tomcat 7 verwenden und Warnungen in Tomcat 8 erhalten haben, waren Ihre (und meine) Caching-Einstellungen von Tomcat 7 ohne Warnung schlecht.
2.4 Lösungen
Es gibt mehrere Lösungen:
- Cache vergrößern (empfohlen)
- Senken Sie die TTL (nicht empfohlen)
- Cache-Protokoll-Warnungen unterdrücken (nicht empfohlen)
- Cache deaktivieren
2.4.1. Cache vergrößern (empfohlen)
Wie hier beschrieben: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html
Durch Hinzufügen <Resources cacheMaxSize="XXXXX" />
innerhalb des Context
Elements in $CATALINA_BASE/conf/context.xml
, wobei "XXXXX" für eine erhöhte Cache-Größe steht, die in KB angegeben wird. Der Standardwert ist 10240 (10 MB). Stellen Sie daher eine höhere Größe ein.
Sie müssen sich auf optimale Einstellungen einstellen. Beachten Sie, dass das Problem möglicherweise erneut auftritt, wenn plötzlich mehr Verkehrs- / Ressourcenanforderungen auftreten.
Um zu vermeiden, dass der Server jedes Mal neu gestartet werden muss, wenn Sie eine neue Cache-Größe ausprobieren möchten, können Sie ihn ohne Neustart mithilfe von JMX ändern.
Um JMX zu aktivieren , fügen Sie dies in $CATALINA_BASE/conf/server.xml
das Server
Element ein:
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" />
und laden Sie es catalina-jmx-remote.jar
von https://tomcat.apache.org/download-80.cgi herunter und fügen Sie es ein $CATALINA_HOME/lib
. Verwenden Sie dann jConsole (standardmäßig mit dem Java JDK geliefert), um über JMX eine Verbindung zum Server herzustellen, und durchsuchen Sie die Einstellungen nach Einstellungen, um die Cache-Größe zu erhöhen, während der Server ausgeführt wird. Änderungen an diesen Einstellungen sollten sofort wirksam werden.
2.4.2. Senken Sie die TTL (nicht empfohlen)
Verringern Sie den cacheTtl
Wert um weniger als 5000 Millisekunden und stellen Sie optimale Einstellungen ein.
Beispielsweise: <Resources cacheTtl="2000" />
Dies kommt effektiv darauf an, einen Cache im RAM zu haben und zu füllen, ohne ihn zu verwenden.
2.4.3. Cache-Protokoll-Warnungen unterdrücken (nicht empfohlen)
Konfigurieren Sie die Protokollierung, um den Logger für zu deaktivieren org.apache.catalina.webresources.Cache
.
Weitere Informationen zum Anmelden in Tomcat finden Sie unter http://tomcat.apache.org/tomcat-8.0-doc/logging.html
2.4.4. Cache deaktivieren
Sie können , indem Sie den Cache deaktivieren cachingAllowed
zu false
.
<Resources cachingAllowed="false" />
Obwohl ich mich daran erinnern kann, dass ich in einer Beta-Version von Tomcat 8 JMX verwendet habe, um den Cache zu deaktivieren. (Ich weiß nicht warum genau, aber möglicherweise liegt ein Problem beim Deaktivieren des Caches über server.xml vor.)