Tomcat 8 throwing - org.apache.catalina.webresources.Cache.getResource Невозможно добавить ресурс

Я только что обновил Tomcat с версии 7.0.52 до 8.0.14.

Я получаю это для большого количества файлов статического изображения:

org.apache.catalina.webresources.Cache.getResource Невозможно добавить ресурс в [/base/1325/WA6144-150x112.jpg] в кеш, потому что было недостаточно свободного места после выселения истекшего кеша записи - рассмотрим увеличение максимального размера кеша

Я не указал никаких конкретных настроек ресурса, и я не получил это для 7.0.52.

Я нашел упоминание об этом при запуске в отчете об ошибке, который предположительно был исправлен. Для меня это происходит не при запуске, а постоянно, когда запрашивается ресурс.

У кого-нибудь еще такая проблема?

Попытка хотя бы просто отключить кеш, но я не могу найти пример того, как указать не использовать кеш. Атрибуты перешли из контекста в Tomcat версии 8. Попробовали добавить ресурс, но не смогли получить правильную конфигурацию.

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

Спасибо.

Ответ 1

В блоке добавления $CATALINA_BASE/conf/context.xml ниже перед </Context>

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

Для получения дополнительной информации: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html

Ответ 2

У меня возникла та же проблема при обновлении с Tomcat 7 до 8: постоянный большой поток предупреждений журнала о кеше.

1. Короткий ответ

Добавьте это в элемент Context xml вашего $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" />

Таким образом, по умолчанию установлено значение 10240 (10 мегабайт), поэтому установите размер выше этого. Чем настроить для оптимальных настроек, где предупреждения исчезают. Обратите внимание, что предупреждения могут возвращаться в условиях повышенной интенсивности движения.

1.1 Причина (краткое объяснение)

Проблема вызвана тем, что Tomcat не может достичь своего целевого размера кэша из-за записей кэша, которые меньше, чем TTL этих записей. Таким образом, у Tomcat не было достаточно записей в кеше, которые могли бы истечь, потому что они были слишком свежими, поэтому он не мог освободить достаточно кеша и, следовательно, выводить предупреждения.

Проблема не появилась в Tomcat 7, потому что Tomcat 7 просто не выводил предупреждения в этой ситуации. (Причинение вам и мне использовать плохие настройки кэша без уведомления.)

Проблема возникает при получении относительно большого количества HTTP-запросов на ресурсы (обычно статических) за относительно короткий промежуток времени по сравнению с размером и TTL кэша. Если кэш достигает своего максимума (по умолчанию 10 МБ) с более чем 95% его размера со свежими записями в кэше ("свежий" означает, что в кэше менее 5 секунд), вы получите предупреждающее сообщение для каждого веб-ресурса, который пытается использовать Tomcat. загрузить в кеш.

1.2 Дополнительная информация

Используйте JMX, если вам нужно настроить cacheMaxSize на работающем сервере без перезагрузки.

Самым быстрым решением было бы полностью отключить кеш: <Resources cachingAllowed="false" />, но это неоптимально, поэтому увеличьте cacheMaxSize, как я только что описал.

2. Длинный ответ

2.1 Справочная информация

WebSource - это файл или каталог в веб-приложении. По соображениям производительности Tomcat может кэшировать веб-источники. Максимум статического кеша ресурсов (всего ресурсов) по умолчанию составляет 10240 кбайт (10 мегабайт). WebResource загружается в кэш, когда запрашивается webResource (например, при загрузке статического изображения), затем он называется записью в кэше. Каждая запись в кэше имеет TTL (время жизни), то есть время, в течение которого записи в кэше разрешено оставаться в кэше. По истечении TTL запись в кэше может быть удалена из кэша. Значение по умолчанию cacheTTL составляет 5000 миллисекунд (5 секунд).

Есть еще что рассказать о кешировании, но это не имеет отношения к проблеме.

2.2 Причина

Следующий код из класса Cache подробно описывает политику кэширования:

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. Trades cache
158 // efficiency (younger entries may be evicted before older
159 // ones) for speed since this is on the critical path for
160 // request processing
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 sufficient space for this resource
167 // Remove it from the cache
168 removeCacheEntry(path);
169 log.warn(sm.getString("cache.addFail", path));
170 }
171 }

При загрузке веб-ресурса код вычисляет новый размер кэша. Если вычисленный размер больше, чем максимальный размер по умолчанию, необходимо удалить одну или несколько кэшированных записей, иначе новый размер превысит максимальный. Таким образом, код будет вычислять "targetSize", то есть размер, под которым кеш хочет остаться (как оптимальный), который по умолчанию составляет 95% от максимального. Чтобы достичь этого targetSize, записи должны быть удалены/удалены из кэша. Это делается с помощью следующего кода:

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 // Don't expire anything that has been checked within the TTL
225 if (resource.getNextCheck() > now) {
226 continue;
227 }
229 // Remove the entry from the cache
230 removeCacheEntry(resource.getWebappPath());
232 newSize = size.get();
233 }
235 return newSize;
236 }

Таким образом, запись в кэше удаляется, когда истекает срок ее действия, а целевой размер еще не достигнут.

После попытки освободить кеш путем удаления записей из кеша, код будет делать:

165  if (newSize > maxSize) {
166 // Unable to create sufficient space for this resource
167 // Remove it from the cache
168 removeCacheEntry(path);
169 log.warn(sm.getString("cache.addFail", path));
170 }

Таким образом, если после попытки освободить кэш размер все равно превысит максимальный, появится предупреждение о невозможности освобождения:

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 Проблема

Итак, как говорится в предупреждающем сообщении, проблема заключается в

Недостаточно свободного места после удаления устаревших записей кэша - рассмотрите возможность увеличения максимального размера кэша

Если ваше веб-приложение загружает много некэшированных веб-ресурсов (около максимума кэша, по умолчанию 10 МБ) в течение короткого времени (5 секунд), вы получите предупреждение.

Смущает то, что Tomcat 7 не показывал предупреждение. Это просто вызвано этим кодом Tomcat 7:

1606  // Add new entry to cache
1607 synchronized (cache) {
1608 // Check cache size, and remove elements if too big
1609 if ((cache.lookup(name) == null) && cache.allocate(entry.size)) {
1610 cache.load(entry);
1611 }
1612 }

в сочетании с:

231  while (toFree > 0) {
232 if (attempts == maxAllocateIterations) {
233 // Give up, no changes are made to the current cache
234 return false;
235 }

Таким образом, Tomcat 7 просто не выводит никаких предупреждений, когда не может освободить кэш, тогда как Tomcat 8 выводит предупреждение.

Поэтому, если вы используете Tomcat 8 с той же конфигурацией кэширования по умолчанию, что и Tomcat 7, и вы получили предупреждения в Tomcat 8, то ваши (и мои) настройки кэширования Tomcat 7 работали плохо без предупреждения.

2.4 Решения

Есть несколько решений:

  1. Увеличить кеш (рекомендуется)
  2. Понизьте TTL (не рекомендуется)
  3. Подавлять предупреждения журнала кэша (не рекомендуется)
  4. Отключить кеш

2.4.1. Увеличить кеш (рекомендуется)

Как описано здесь: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html

Добавляя <Resources cacheMaxSize="XXXXX" /> в элемент Context в $CATALINA_BASE/conf/context.xml, где "XXXXX" обозначает увеличенный размер кэша, указанный в килобайтах. По умолчанию установлено значение 10240 (10 мегабайт), поэтому установите размер больше этого.

Вам придется настроить для оптимальных настроек. Обратите внимание, что проблема может вернуться, когда у вас внезапно увеличится количество запросов трафика/ресурсов.

Чтобы избежать перезапуска сервера каждый раз, когда вы хотите попробовать новый размер кэша, вы можете изменить его без перезапуска с помощью JMX.

Чтобы включить JMX, добавьте это в $CATALINA_BASE/conf/server.xml внутри элемента Server: <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" /> и загрузите catalina-jmx-remote.jar из https://tomcat.apache.org/download-80.cgi и поместите его в $CATALINA_HOME/lib. Затем используйте jConsole (поставляется по умолчанию с Java JDK), чтобы подключиться через JMX к серверу и просмотреть настройки параметров, чтобы увеличить размер кэша во время работы сервера. Изменения в этих настройках должны вступить в силу немедленно.

2.4.2. Понизьте TTL (не рекомендуется)

Уменьшите значение cacheTtl примерно на 5000 миллисекунд и настройте его для оптимальных настроек.

Например: <Resources cacheMaxSize="2000" />

Это эффективно сводится к наличию и заполнению кэша в оперативной памяти без его использования.

2.4.3. Подавлять предупреждения журнала кэша (не рекомендуется)

Сконфигурируйте ведение журнала, чтобы отключить регистратор для org.apache.catalina.webresources.Cache.

Для получения дополнительной информации о входе в Tomcat: http://tomcat.apache.org/tomcat-8.0-doc/logging.html

2.4.4. Отключить кеш

Вы можете отключить кэш, установив cachingAllowed на false. <Resources cachingAllowed="false" />

Хотя я помню, что в бета-версии Tomcat 8 я использовал JMX для отключения кеша. (Не знаю почему, но может быть проблема с отключением кеша через server.xml.)

Ответ 3

У вас больше статических ресурсов, к которым у кеша есть место. Вы можете выполнить одно из следующих действий:

  • Увеличить размер кеша
  • Уменьшить TTL для кеша
  • Отключить кеширование

Подробнее об этом можно узнать в документации.

Ответ 4

Это не решение в том смысле, что оно не разрешает условия, которые приводят к появлению сообщения в журналах, но это сообщение можно подавить, добавив следующее к conf/logging.properties:

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

Это отфильтровывает журналы "Невозможно добавить ресурс", которые находятся на уровне ПРЕДУПРЕЖДЕНИЕ.

На мой взгляд, WARNING не обязательно является ошибкой, которую необходимо устранить, а скорее можно игнорировать при желании.