Ho riscontrato lo stesso problema durante l'aggiornamento da Tomcat 7 a 8: un flusso continuo di avvisi di registro sulla cache.
1. Risposta breve
Aggiungi questo all'interno Context
dell'elemento xml del tuo $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" />
Quindi il valore predefinito è 10240
(10 mbyte), quindi imposta una dimensione superiore a questa. Quindi sintonizzare per impostazioni ottimali in cui gli avvisi scompaiono. Tieni presente che gli avvisi potrebbero ripresentarsi in situazioni di traffico elevato.
1.1 La causa (breve spiegazione)
Il problema è causato dal fatto che Tomcat non è in grado di raggiungere la dimensione della cache di destinazione a causa di voci della cache inferiori al TTL di tali voci. Quindi Tomcat non aveva abbastanza voci di cache da poter scadere, perché erano troppo recenti, quindi non poteva liberare abbastanza cache e quindi emette avvisi.
Il problema non è apparso in Tomcat 7 perché Tomcat 7 semplicemente non ha emesso avvisi in questa situazione. (Inducendo te e me a utilizzare impostazioni della cache scadenti senza essere avvisati.)
Il problema si verifica quando si riceve una quantità relativamente grande di richieste HTTP di risorse (solitamente statiche) in un periodo di tempo relativamente breve rispetto alle dimensioni e al TTL della cache. Se la cache sta raggiungendo il suo massimo (10 MB per impostazione predefinita) con più del 95% delle sue dimensioni con nuove voci di cache (fresco significa meno di 5 secondi nella cache), riceverai un messaggio di avviso per ogni risorsa web che Tomcat prova da caricare nella cache.
1.2 Informazioni opzionali
Utilizzare JMX se è necessario ottimizzare cacheMaxSize su un server in esecuzione senza riavviarlo.
La soluzione più rapida sarebbe disabilitare completamente la cache <Resources cachingAllowed="false" />
:, ma non è ottimale, quindi aumenta cacheMaxSize come ho appena descritto.
2. Risposta lunga
2.1 Informazioni di base
Un WebSource è un file o una directory in un'applicazione web. Per motivi di prestazioni, Tomcat può memorizzare nella cache WebSources. Il massimo della cache delle risorse statiche (tutte le risorse in totale) è per impostazione predefinita 10240 kbyte (10 mbyte). Una webResource viene caricata nella cache quando viene richiesta la webResource (ad esempio quando si carica un'immagine statica), viene quindi chiamata una voce della cache. Ogni voce della cache ha un TTL (time to live), che è il tempo in cui la voce della cache può rimanere nella cache. Quando il TTL scade, la voce della cache può essere rimossa dalla cache. Il valore predefinito di cacheTTL è 5000 millisecondi (5 secondi).
C'è altro da dire sulla memorizzazione nella cache, ma questo è irrilevante per il problema.
2.2 La causa
Il codice seguente della classe Cache mostra i criteri di memorizzazione nella cache in dettaglio:
152 // Il contenuto non verrà memorizzato nella cache ma abbiamo ancora bisogno della dimensione dei metadati
153 long delta = cacheEntry. getSize ();
154 dimensioni. addAndGet (delta);
156 if (size. Get ()> maxSize) {
157 // Elabora risorse non ordinate per la velocità. Cache delle transazioni
158 // efficienza (le voci più giovani possono essere rimosse prima delle
159 // precedenti) per la velocità poiché si trova sul percorso critico per
160 // elaborazione della richiesta
161 long targetSize =
162 maxSize * (100 - TARGET_FREE_PERCENT_GET) / 100;
163 lungo newSize = EVICT (
164 . TargetSize, resourcecache valori (). Iterator ());
165 if (newSize> maxSize) {
166 // Impossibile creare spazio sufficiente per questa risorsa
167 // Rimuoverla dalla cache
168 removeCacheEntry (path);
169 log. warn (sm. getString ("cache.addFail", path));
170 }
171 }
Quando si carica un webResource, il codice calcola la nuova dimensione della cache. Se la dimensione calcolata è maggiore della dimensione massima predefinita, è necessario rimuovere una o più voci memorizzate nella cache, altrimenti la nuova dimensione supererà quella massima. Quindi il codice calcolerà un "targetSize", che è la dimensione sotto la quale la cache vuole rimanere (come ottimale), che è per impostazione predefinita il 95% del massimo. Per raggiungere questo targetSize, le voci devono essere rimosse / eliminate dalla cache. Questo viene fatto utilizzando il codice seguente:
215 private long evict ( long targetSize, Iterator < CachedResource > iter) {
217 long now = System. currentTimeMillis ();
219 lungo nuovoSize = size. get ();
221 while (newSize> targetSize && iter. HasNext ()) {
222 CachedResource resource = iter. successivo ();
224 // Non far scadere nulla che è stato controllato nel TTL
225 se (resource. GetNextCheck ()> now) {
226 continuare ;
227 }
229 // Rimuove la voce dalla cache
230 removeCacheEntry (resource. GetWebappPath ());
232 newSize = dimensione. get ();
233 }
235 return newSize;
236 }
Quindi una voce della cache viene rimossa quando il suo TTL è scaduto e targetSize non è stato ancora raggiunto.
Dopo il tentativo di liberare la cache rimuovendo le voci della cache, il codice farà:
165 if (newSize> maxSize) {
166 // Impossibile creare spazio sufficiente per questa risorsa
167 // Rimuoverla dalla cache
168 removeCacheEntry (path);
169 log. warn (sm. getString ("cache.addFail", path));
170 }
Quindi, se dopo il tentativo di liberare la cache, la dimensione supera ancora il massimo, verrà visualizzato il messaggio di avviso sull'impossibilità di liberare:
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 Il problema
Quindi, come dice il messaggio di avviso, il problema è
Spazio libero insufficiente disponibile dopo aver eliminato le voci della cache scadute: prendere in considerazione l'aumento della dimensione massima della cache
Se la tua applicazione web carica molte risorse web non memorizzate nella cache (circa il massimo della cache, per impostazione predefinita 10 MB) in breve tempo (5 secondi), riceverai l'avviso.
La parte confusa è che Tomcat 7 non ha mostrato l'avviso. Ciò è semplicemente causato da questo codice Tomcat 7:
1606 // Aggiungi nuova voce nella cache
1607 sincronizzato (cache) {
1608 // Controllare la dimensione della cache, e gli elementi di rimuovere, se troppo grande
1609 se ((cache. Lookup (nome) == nullo ) && cache. Allocare (entry.size) ) {
1610 cache. carico (entrata);
1611 }
1612 }
combinata con:
231 while (toFree> 0) {
232 if (tempt == maxAllocateIterations) {
233 // Rinuncia, non vengono apportate modifiche alla cache
234 corrente return false ;
235 }
Quindi Tomcat 7 semplicemente non emette alcun avviso quando non è in grado di liberare la cache, mentre Tomcat 8 emetterà un avviso.
Quindi, se stai utilizzando Tomcat 8 con la stessa configurazione di memorizzazione nella cache predefinita di Tomcat 7 e hai ricevuto avvisi in Tomcat 8, le tue (e mie) impostazioni di memorizzazione nella cache di Tomcat 7 funzionavano male senza preavviso.
2.4 Soluzioni
Esistono molteplici soluzioni:
- Aumenta la cache (consigliato)
- Abbassare il TTL (non consigliato)
- Elimina gli avvisi del registro della cache (non consigliato)
- Disabilitare la cache
2.4.1. Aumenta la cache (consigliato)
Come descritto qui: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html
Aggiungendo <Resources cacheMaxSize="XXXXX" />
all'interno Context
dell'elemento in $CATALINA_BASE/conf/context.xml
, dove "XXXXX" sta per una maggiore dimensione della cache, specificata in kbyte. L'impostazione predefinita è 10240 (10 mbyte), quindi imposta una dimensione superiore a questa.
Dovrai sintonizzarti per impostazioni ottimali. Tieni presente che il problema potrebbe ripresentarsi quando improvvisamente si verifica un aumento del traffico / delle richieste di risorse.
Per evitare di dover riavviare il server ogni volta che si desidera provare una nuova dimensione della cache, è possibile modificarla senza riavviare utilizzando JMX.
Per abilitare JMX , aggiungilo $CATALINA_BASE/conf/server.xml
all'interno Server
dell'elemento:
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" />
e scaricalo catalina-jmx-remote.jar
da https://tomcat.apache.org/download-80.cgi e inseriscilo $CATALINA_HOME/lib
. Quindi utilizzare jConsole (fornito per impostazione predefinita con Java JDK) per connettersi tramite JMX al server e controllare le impostazioni per le impostazioni per aumentare la dimensione della cache mentre il server è in esecuzione. Le modifiche a queste impostazioni dovrebbero avere effetto immediato.
2.4.2. Abbassare il TTL (non consigliato)
Abbassare il cacheTtl
valore di qualcosa al di sotto di 5000 millisecondi e regolare per impostazioni ottimali.
Per esempio: <Resources cacheTtl="2000" />
Ciò si riduce effettivamente ad avere e riempire una cache nella ram senza usarla.
2.4.3. Elimina gli avvisi del registro della cache (non consigliato)
Configurare la registrazione per disabilitare il logger per org.apache.catalina.webresources.Cache
.
Per maggiori informazioni sull'accesso a Tomcat: http://tomcat.apache.org/tomcat-8.0-doc/logging.html
2.4.4. Disabilitare la cache
È possibile disabilitare la cache impostando cachingAllowed
su false
.
<Resources cachingAllowed="false" />
Anche se posso ricordare che in una versione beta di Tomcat 8, stavo usando JMX per disabilitare la cache. (Non sono sicuro del perché esattamente, ma potrebbe esserci un problema con la disabilitazione della cache tramite server.xml.)