Tomcat 8 wirft - org.apache.catalina.webresources.Cache.getResource Die Ressource kann nicht hinzugefügt werden


111

Ich habe gerade Tomcat von Version 7.0.52 auf 8.0.14 aktualisiert.

Ich bekomme dies für viele statische Bilddateien:

org.apache.catalina.webresources.Cache.getResource Die Ressource unter [/base/1325/WA6144-150x112.jpg] kann nicht zum Cache hinzugefügt werden, da nach dem Entfernen abgelaufener Cache-Einträge nicht genügend freier Speicherplatz verfügbar ist. Erhöhen Sie möglicherweise die maximale Größe des Caches

Ich habe keine bestimmten Ressourceneinstellungen angegeben und diese für 7.0.52 nicht erhalten.

Ich habe erwähnt, dass dies beim Start in einem Fehlerbericht passiert, der angeblich behoben wurde. Für mich geschieht dies nicht beim Start, sondern ständig, wenn die Ressource angefordert wird.

Hat noch jemand dieses Problem?

Ich habe versucht, zumindest nur den Cache zu deaktivieren, aber ich kann kein Beispiel dafür finden, wie angegeben werden soll, dass der Cache nicht verwendet werden soll. Die Attribute wurden aus dem Kontext in Tomcat Version 8 entfernt. Ich habe versucht, eine Ressource hinzuzufügen, kann jedoch die Konfiguration nicht richtig ausführen.

<Resource name="file" 
    cachingAllowed="false"
    className="org.apache.catalina.webresources.FileResourceSet"
/>  

Vielen Dank.


Keine Antworten - Ich denke, ich muss die einzige Person mit diesem Problem sein.
Iainmac999


1
In Bezug auf das fehlende Attribut im Tomcat 8-Kontext finden Sie hier einen Auszug aus dem Migrationshandbuch (Schwerpunkt Mine): " Das Refactoring von Ressourcen hat auch dazu geführt, dass eine Reihe von Attributen aus der Standardkontextimplementierung (org.apache.catalina.core) entfernt wurden .StandardContext). Die folgenden Attribute können jetzt über die von der Webanwendung verwendete Ressourcenimplementierung konfiguriert werden . " Weitere Informationen finden Sie in der zugehörigen Migrationsanleitung .
informatik01

@ iainmac999 Nachdem wir nach 2 Jahren noch nie eine richtige Antwort ausgewählt haben, können wir uns darauf einigen, dass sie in beide Richtungen funktioniert?
Davidjmcclelland

Antworten:



152

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 ContextXML-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:

  1. Cache vergrößern (empfohlen)
  2. Senken Sie die TTL (nicht empfohlen)
  3. Cache-Protokoll-Warnungen unterdrücken (nicht empfohlen)
  4. 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 ContextElements 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.xmldas ServerElement ein: <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" />und laden Sie es catalina-jmx-remote.jarvon 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 cacheTtlWert 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 cachingAllowedzu 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.)


Cache erhöhen? Ich bezweifle, dass es funktionieren würde ... Ich habe Folgendes gesehen: private long maxSize = 10 * 1024 * 1024; in der Quelle. grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/…
HoaPhan

Haben Sie die Antwort gefunden, warum Tomcat8 Cache-Warnungen überflutet
PHP Avenger

@HoaPhan 10 * 1024 * 1024 ist maximal 10 MB für den gesamten Cache. Abhängig vom Datenverkehr der Webanwendung kann dies innerhalb von Sekunden erreicht werden. Es weit genug zu erhöhen, wird funktionieren.
Devabc

@PHPAvenger Tomcat 7 hat in dieser Situation überhaupt nicht gewarnt, während Tomcat 8 dies tut, sodass es als Warnfunktion angesehen werden kann. Das Problem ist, dass es nicht nur einmal, sondern bei jeder Ressourcenanforderung zum Zwischenspeichern warnt. Es wäre eine Verbesserung, nur nach einer bestimmten Zeit zu warnen oder Zieltreffer zwischenzuspeichern.
Devabc

@ Devabc makellose Antwort! Ein SO Klassiker!
Gaurav

9

Sie haben mehr statische Ressourcen, für die der Cache Platz bietet. Sie können eine der folgenden Aktionen ausführen:

  • Erhöhen Sie die Größe des Caches
  • Verringern Sie die TTL für den Cache
  • Caching deaktivieren

Weitere Informationen finden Sie in der Dokumentation zu diesen Konfigurationsoptionen.


1
Danke für den Kommentar. Ich verstehe die Bedeutung der Ausnahme und habe natürlich die Dokumentation gelesen, auf die Sie verlinkt haben. Ich verstehe jedoch nicht, warum sich dies ohne Konfigurationsänderungen von 7 auf 8 ändern würde. Das heißt, warum sollte sich der Standard-Handler für Dateisystemressourcen in 8 bis 7 unterscheiden, ohne auf Änderungen Bezug zu nehmen, und es ist verdächtig, dass ein Startfehler gemeldet und angeblich behoben wurde.
Iainmac999

1
Wenn Sie den Migrationsleitfaden gelesen hätten - insbesondere tomcat.apache.org/migration-8.html#Web_application_resources -, wären die Dinge möglicherweise klarer.
Mark Thomas

Es wäre hilfreich, wenn die Dokumentation etwas mehr dazu beitragen würde, a) zu erklären, welche Ressourcen in diesen Cache gelangen und warum (es gibt viele Missverständnisse!) Und b) welche Auswirkungen unterschiedliche Einstellungen haben können (z. B. die Cache-Einstellungen der einzelnen Webanwendungen blind zu machen) ziemlich groß kann eine Menge Speicher verbrauchen) und wie man dies richtig einstellt. Es wäre auch hilfreich, wenn in Code und Konfiguration zwischen dem Zwischenspeichern statischer Ressourcen, die von der Anwendung selbst verwendet werden, und statischen Dateien, die von Benutzeragenten angefordert und lediglich von der Anwendung bereitgestellt werden, unterschieden würde.
volkerk

4

Dies ist keine Lösung in dem Sinne, dass die Bedingungen, unter denen die Nachricht in den Protokollen angezeigt wird, nicht behoben werden. Die Nachricht kann jedoch unterdrückt werden, indem Folgendes an Folgendes angehängt wird conf/logging.properties:

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

Dadurch werden die Protokolle "Ressource kann nicht hinzugefügt werden" herausgefiltert, die sich auf der Ebene WARNUNG befinden.

Aus meiner Sicht WARNINGist a nicht unbedingt ein Fehler, der behoben werden muss, sondern kann auf Wunsch ignoriert werden.


8
Haha. Dies löst das Problem nicht. Es zeigt es einfach nicht. WTF!
T3rm1

Dies löst das Problem der übermäßigen Protokollierung, die für sich genommen ein erhebliches Problem darstellen kann. Es kehrt zum Verhalten früherer Tomcat-Versionen zurück, bei denen die Dinge für viele ausreichend gut funktionierten, sodass das Problem in diesem Sinne "gelöst" wird. Das Problem der tatsächlichen Optimierung des Tomcat-Cache wird nicht angesprochen, was in der Antwort von devabc sehr gut behandelt wird.
volkerk
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.