Pregunta Lanzamiento de Tomcat 8 - org.apache.catalina.webresources.Cache.getResource No se puede agregar el recurso


Acabo de actualizar Tomcat de la versión 7.0.52 a la 8.0.14.

Estoy obteniendo esto para muchos archivos de imagen estáticos:

org.apache.catalina.webresources.Cache.getResource No se puede agregar el   recurso en [/base/1325/WA6144-150x112.jpg] a la memoria caché porque hay   no había suficiente espacio libre disponible después de desalojar el caché caducado   entradas: considere aumentar el tamaño máximo de la memoria caché

No he especificado ninguna configuración de recursos particular, y no obtuve esto para 7.0.52.

He encontrado mención de que esto sucedía al inicio en un informe de error que supuestamente se solucionó. Para mí, esto no está sucediendo al inicio, sino constantemente cuando se solicita el recurso.

¿Alguien más tiene este problema?

Tratando de al menos desactivar la memoria caché, pero no puedo encontrar un ejemplo de cómo especificar que no se use la memoria caché. Los atributos han pasado del contexto en Tomcat versión 8. Han intentado agregar un recurso pero no pueden obtener la configuración correcta.

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

Gracias.


73
2017-11-12 17:49


origen


Respuestas:


En tus $CATALINA_BASE/conf/context.xml agregue el bloque a continuación antes </Context>

<Resources cachingAllowed="true" cacheMaxSize="100000" />

Para más información: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html


125
2018-06-23 08:38



Tuve el mismo problema al actualizar de Tomcat 7 a 8: una gran inundación continua de advertencias de registro sobre la memoria caché.

Solución (TL; DR)

La mejor solución es aumentar la caché agregando

<Resources cacheMaxSize="XXXXX" />

dentro de Context elemento en $CATALINA_BASE/conf/context.xml, donde "XXXXX" representa un tamaño de caché aumentado, especificado en kbytes. El valor predeterminado es 10240 (10 mbyte), por lo que debe establecer un tamaño superior a este. Luego sintonice las configuraciones óptimas donde las advertencias desaparecen. Tenga en cuenta que las advertencias pueden reaparecer en situaciones de mucho tráfico.

Use JMX si necesita sintonizar un servidor en ejecución sin reiniciarlo.

La solución más rápida sería desactivar completamente el caché: <Resources cachingAllowed="false" />, pero eso no es óptimo, entonces increméntelo como acabo de describir.

Causa (breve)

El problema se debe a que Tomcat no puede alcanzar su tamaño de caché de destino debido a las entradas de caché que son menores que el TTL de esas entradas. Así que Tomcat no tenía suficientes entradas de caché que podría caducar, porque estaban demasiado frescas, por lo que no podía liberar suficiente memoria caché y, por lo tanto, emitía advertencias.

El problema no apareció en Tomcat 7 porque Tomcat 7 simplemente no emitió advertencias en esta situación. (Causando que tú y yo utilicemos configuraciones de caché deficientes sin que nos avisen).

El problema aparece cuando se recibe una cantidad relativamente grande de solicitudes HTTP de recursos (normalmente estáticos) en un período de tiempo relativamente corto en comparación con el tamaño y el TTL de la memoria caché. Si la memoria caché está alcanzando su máximo (10 MB de forma predeterminada) con más del 95% de su tamaño con nuevas entradas de caché (Fresh significa menos de menos de 5 segundos en caché), entonces recibirá un mensaje de advertencia para cada webResource que Tomcat intentará para cargar en el caché.

Información de fondo

UN WebSourcees un archivo o directorio en una aplicación web. Por razones de rendimiento, Tomcat puede almacenar en caché WebSources. los máximo de la memoria caché de recursos estáticos (todos los recursos en total) es por defecto 10240 kbyte (10 mbyte). Un webResource se carga en el caché cuando se solicita el webResource (por ejemplo, cuando se carga una imagen estática), luego se denomina entrada de caché. Cada entrada de caché tiene un TTL (tiempo de vida), que es el momento en que se permite que la entrada de la memoria caché permanezca en la memoria caché. Cuando expira el TTL, la entrada de caché es elegible para eliminarse de la caché. El valor predeterminado de cacheTTL es 5000 milisegundos (5 segundos).

Hay más que contar sobre el almacenamiento en caché, pero eso es irrelevante para el problema.

La causa (detallada)

El siguiente código de la Clase de caché muestra la política de almacenamiento en caché en detalle:

152  // El contenido no se almacenará en caché, pero aún necesitamos el tamaño de los metadatos
153   largo delta = cacheEntry.getSize();
154  tamaño.addAndGet(delta);
156   Si (tamaño.obtener()> maxSize) {
157      // Procesar los recursos desordenados para la velocidad. Memoria caché
158      // eficiencia (las entradas más jóvenes pueden ser desalojadas antes que las anteriores)
159      // ones) para velocidad ya que está en la ruta crítica para
160      // solicitud de procesamiento
161       largo targetSize =
162              maxSize * (100 - TARGET_FREE_PERCENT_GET) / 100;
163       largo newSize = desalojar(
164              targetSize, resourceCache.valores().iterador());
165       Si (newSize> maxSize) {
166          // No se puede crear suficiente espacio para este recurso
167          // Eliminarlo del caché
168           removeCacheEntry(camino);
169          Iniciar sesión.advertir(sm.getString("cache.addFail", ruta));
170      }
171  }

Al cargar un webResource, el código calcula el nuevo tamaño de la caché. Si el tamaño calculado es mayor que el tamaño máximo predeterminado, se deben eliminar una o más entradas en caché, de lo contrario, el nuevo tamaño superará el máximo. Por lo tanto, el código calculará un "tamaño de destino", que es el tamaño en el que el caché desea permanecer (como óptimo), que es por defecto el 95% del máximo. Para alcanzar este targetSize, las entradas deben ser eliminadas / desalojadas de la memoria caché. Esto se hace usando el siguiente código:

215   privado  largo desalojar(largo targetSize, Iterador<CachedResource> iter) {
217       largo ahora = Sistema.currentTimeMillis();
219       largo newSize = tamaño.obtener();
221       mientras(newSize> targetSize && iter.hasNext()) {
222           CachedResource recurso = iter.siguiente();
224          // No caduque nada que haya sido verificado dentro del TTL
225           Si (recurso.getNextCheck()> ahora) {
226               continuar;
227          }
229          // Eliminar la entrada del caché
230           removeCacheEntry(recurso.getWebappPath());
232          newSize = tamaño.obtener();
233      }
235       regreso newSize;
236  }

Por lo tanto, se elimina una entrada de caché cuando su TTL ha expirado y aún no se ha alcanzado targetSize.

Después del intento de liberar el caché desalojando las entradas del caché, el código hará:

165   Si (newSize> maxSize) {
166      // No se puede crear suficiente espacio para este recurso
167      // Eliminarlo del caché
168       removeCacheEntry(camino);
169      Iniciar sesión.advertir(sm.getString("cache.addFail", ruta));
170  }

Entonces, si después del intento de liberar el caché, el tamaño aún excede el máximo, se mostrará el mensaje de advertencia sobre la imposibilidad de liberar:

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

El problema

Entonces, como dice el mensaje de advertencia, el problema es

espacio libre insuficiente disponible después de desalojar las entradas caché expiradas; considere aumentar el tamaño máximo de la memoria caché

Si su aplicación web carga una gran cantidad de recursos web no almacenados en caché (aproximadamente un máximo de caché, por defecto 10mb) en un corto período de tiempo (5 segundos), entonces recibirá la advertencia.

La parte confusa es que Tomcat 7 no mostró la advertencia. Esto es simplemente causado por este código de Tomcat 7:

1606  // Agregar nueva entrada a la memoria caché
1607   sincronizado (caché) {
1608      // Compruebe el tamaño de la caché y elimine los elementos si es demasiado grande
1609       Si ((cache.buscar(nombre) == nulo) && cache.asignar(entry.size)) {
1610          cache.carga(entrada);
1611      }
1612  }

combinado con:

231   mientras (a Libre> 0) {
232       Si (intenta == maxAllocateIterations) {
233          // Renunciar, no se realizan cambios en el caché actual
234           regreso  falso;
235      }

Por lo tanto, Tomcat 7 simplemente no genera ninguna advertencia cuando no puede liberar el caché, mientras que Tomcat 8 mostrará una advertencia.

Entonces, si está utilizando Tomcat 8 con la misma configuración de almacenamiento en caché predeterminada que Tomcat 7, y recibió advertencias en Tomcat 8, entonces su (y la mía) configuración de caché de Tomcat 7 tuvo un rendimiento deficiente sin previo aviso.

Soluciones

Hay múltiples soluciones:

  1. Aumentar el caché (recomendado)
  2. Baje el TTL (no recomendado)
  3. Suprime las advertencias de registro de caché (no recomendado)
  4. Deshabilitar caché

1. Aumentar el caché (recomendado)

Como se describe aquí: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html

Añadiendo <Resources cacheMaxSize="XXXXX" /> dentro de Context elemento en $CATALINA_BASE/conf/context.xml, donde "XXXXX" representa un tamaño de caché aumentado, especificado en kbytes. El valor predeterminado es 10240 (10 mbyte), por lo que debe establecer un tamaño superior a este.

Tendrás que sintonizar ajustes óptimos. Tenga en cuenta que el problema puede reaparecer cuando de repente tiene un aumento en las solicitudes de tráfico / recursos.

Para evitar tener que reiniciar el servidor cada vez que quiera probar un nuevo tamaño de caché, puede cambiarlo sin reiniciar utilizando JMX.

A habilitar JMX, agrega esto a $CATALINA_BASE/conf/server.xml dentro de Server elemento: <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" /> y descargar catalina-jmx-remote.jar de https://tomcat.apache.org/download-80.cgi y ponerlo en $CATALINA_HOME/lib. Luego use jConsole (se envía por defecto con Java JDK) para conectarse a través de JMX al servidor y revise las configuraciones para aumentar el tamaño de la memoria caché mientras el servidor se está ejecutando. Los cambios en estas configuraciones deben tener efecto inmediatamente.

2. Baje el TTL (no recomendado)

Bajar el cacheTtl valor por algo inferior a 5000 milisegundos y sintonizar ajustes óptimos.

Por ejemplo: <Resources cacheMaxSize="2000" />

Esto se reduce a tener y llenar un caché en memoria RAM sin usarlo.

3. Suprimir las advertencias de registro de caché (no recomendado)

Configurar el registro para deshabilitar el registrador para org.apache.catalina.webresources.Cache.

Para obtener más información sobre cómo iniciar sesión en Tomcat: http://tomcat.apache.org/tomcat-8.0-doc/logging.html

4. Deshabilitar el caché

Puede deshabilitar la memoria caché estableciendo cachingAllowed a false. <Resources cachingAllowed="false" />

Aunque puedo recordar que en una versión beta de Tomcat 8, estaba usando JMX para desactivar el caché. (No estoy seguro de por qué exactamente, pero puede haber un problema al deshabilitar el caché a través de server.xml).


67
2017-12-04 17:54



Tiene más recursos estáticos para los que el caché tiene espacio. Puede hacer una de las siguientes cosas:

  • Aumenta el tamaño de la memoria caché
  • Disminuir el TTL para el caché
  • Desactivar el almacenamiento

Para más detalles, vea el documentación para estas opciones de configuración.


7
2017-11-13 21:46



En caso de que ayude a alguien más, la única forma en que pude resolver este problema fue adjuntar lo siguiente a conf/logging.properties:

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

Esto filtra los registros "No se puede agregar el recurso", que están en el nivel ADVERTENCIA.


6
2018-04-26 23:06