Rzucanie Tomcat 8 - org.apache.catalina.webresources.Cache.getResource Nie można dodać zasobu

111

Właśnie zaktualizowałem Tomcat z wersji 7.0.52 do 8.0.14.

Otrzymuję to dla wielu statycznych plików graficznych:

org.apache.catalina.webresources.Cache.getResource Nie można dodać zasobu o lokalizacji [/base/1325/WA6144-150x112.jpg] do pamięci podręcznej, ponieważ po usunięciu wygasłych wpisów pamięci podręcznej było za mało wolnego miejsca - rozważ zwiększenie maksymalnego rozmiaru pamięci podręcznej

Nie określiłem żadnych konkretnych ustawień zasobów i nie otrzymałem tego w wersji 7.0.52.

Znalazłem wzmiankę o tym podczas uruchamiania w zgłoszeniu błędu, który rzekomo został naprawiony. U mnie dzieje się to nie podczas uruchamiania, ale ciągle, gdy żądany jest zasób.

Czy ktoś jeszcze ma ten problem?

Próbuję przynajmniej wyłączyć pamięć podręczną, ale nie mogę znaleźć przykładu, jak określić, aby nie używać pamięci podręcznej. Atrybuty zniknęły z kontekstu w Tomcat w wersji 8. Próbowałem dodać zasób, ale nie mogę uzyskać poprawnej konfiguracji.

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

Dzięki.

iainmac999
źródło
Brak odpowiedzi - chyba jedyna osoba ma ten problem.
iainmac999
2
Rozwiązanie jest tutaj: serverfault.com/questions/644415/ ...
Dmitry
1
Odnośnie brakującego atrybutu w kontekście Tomcat 8, oto fragment przewodnika migracji (wyróżnienie moje): „ Refaktoryzacja zasobów spowodowała również usunięcie wielu atrybutów z domyślnej implementacji kontekstu (org.apache.catalina.core .StandardContext). Następujące atrybuty można teraz skonfigurować za pośrednictwem implementacji zasobów używanej przez aplikację internetową ”. Więcej informacji w powiązanym przewodniku migracji .
informatik01
@ iainmac999 po 2 latach nigdy nie wybrałeś poprawnej odpowiedzi, możemy się zgodzić, że działa to w obie strony?
davidjmcclelland

Odpowiedzi:

161

W Twoim $CATALINA_BASE/conf/context.xmlbloku dodawania poniżej</Context>

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

Więcej informacji: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html

Destroyica
źródło
11
Poszczególni czytelnicy prawdopodobnie będą chcieli dostosować wartość cacheMaxSize do mniej niż 100 megabajtów.
Eric Spiegelberg
do tej pory komunikat o błędzie zalał moje dzienniki konsoli. Teraz jest jasne. Dzięki
Abubacker Siddik
152

Miałem ten sam problem podczas aktualizacji z Tomcat 7 do 8: ciągłe duże zalewanie ostrzeżeń dziennika o pamięci podręcznej.

1. Krótka odpowiedź

Dodaj to w Contextelemencie xml swojego $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" />

Więc wartość domyślna to 10240(10 MB), więc ustaw rozmiar większy niż ten. Następnie dostrój optymalne ustawienia, w których ostrzeżenia znikają. Należy pamiętać, że ostrzeżenia mogą pojawić się ponownie w warunkach dużego natężenia ruchu.

1.1 Przyczyna (krótkie wyjaśnienie)

Problem jest spowodowany tym, że Tomcat nie może osiągnąć docelowego rozmiaru pamięci podręcznej z powodu wpisów pamięci podręcznej, które są mniejsze niż TTL tych wpisów. Więc Tomcat nie miał wystarczającej liczby wpisów w pamięci podręcznej, aby mógł wygasnąć, ponieważ były zbyt świeże, więc nie mógł zwolnić wystarczającej ilości pamięci podręcznej i dlatego wyświetla ostrzeżenia.

Problem nie pojawił się w Tomcat 7, ponieważ Tomcat 7 po prostu nie wyświetlał ostrzeżeń w tej sytuacji. (Powoduje, że ty i ja używamy złych ustawień pamięci podręcznej bez powiadomienia).

Problem pojawia się, gdy otrzymuje się stosunkowo dużą liczbę żądań HTTP dotyczących zasobów (zwykle statycznych) w stosunkowo krótkim czasie w porównaniu do rozmiaru i TTL pamięci podręcznej. Jeśli pamięć podręczna osiąga maksimum (domyślnie 10 MB) z ponad 95% jej rozmiaru ze świeżymi wpisami pamięci podręcznej (świeże oznacza mniej niż 5 sekund w pamięci podręcznej), otrzymasz komunikat ostrzegawczy dla każdego webResource, którego próbuje Tomcat załadować do pamięci podręcznej.

1.2 Informacje opcjonalne

Użyj JMX, jeśli musisz dostroić cacheMaxSize na działającym serwerze bez ponownego uruchamiania go.

Najszybszym rozwiązaniem byłoby całkowite wyłączenie pamięci podręcznej: <Resources cachingAllowed="false" />ale to nieoptymalne, więc zwiększ wartość cacheMaxSize, jak właśnie opisałem.

2. Długa odpowiedź

2.1 Informacje ogólne

WebSource jest plik lub katalog w aplikacji internetowej. Ze względu na wydajność Tomcat może buforować WebSources. Maksymalnie cache zasobów statycznych (wszystkie zasoby w całości) jest domyślnie 10240 kB (10 MB). Element webResource jest ładowany do pamięci podręcznej, gdy żądany jest element webResource (na przykład podczas ładowania obrazu statycznego), a następnie nazywany jest wpisem pamięci podręcznej. Każdy wpis pamięci podręcznej ma TTL (czas życia), czyli czas, przez który wpis pamięci podręcznej może pozostać w pamięci podręcznej. Po wygaśnięciu TTL wpis pamięci podręcznej kwalifikuje się do usunięcia z pamięci podręcznej. Domyślna wartość cacheTTL to 5000 milisekund (5 sekund).

Jest więcej do powiedzenia na temat buforowania, ale nie ma to znaczenia dla problemu.

2.2 Przyczyna

Poniższy kod z klasy Cache przedstawia szczegółowo zasady buforowania:

152   // Treść nie będzie buforowana, ale nadal potrzebujemy metadanych o rozmiarze 
153 long delta = cacheEntry. getSize ();
154 rozmiar. addAndGet (delta);
156 , jeżeli (rozmiar. Dostać ()> maxSize) {
157 zasoby // procesowe nieuporządkowane dla prędkości. Pamięć podręczna transakcji
158 // wydajność (młodsze wpisy mogą być eksmitowane przed starszymi
159 //) dla szybkości, ponieważ jest to ścieżka krytyczna dla
160 // przetwarzania żądań
161 long targetSize =
162 maxSize * (100 - TARGET_FREE_PERCENT_GET) / 100;
163 długi newSize = eksmitować (
164 . TargetSize, resourceCache wartości (). Iteracyjnej ());
165 if (newSize> maxSize) {
166 // Nie można stworzyć wystarczającej ilości miejsca dla tego zasobu
167 // Usuń go z pamięci podręcznej
168 removeCacheEntry (path);
169 log. warn (sm. getString ("cache.addFail", ścieżka));
170 }
171 }

Podczas ładowania elementu webResource kod oblicza nowy rozmiar pamięci podręcznej. Jeśli obliczony rozmiar jest większy niż domyślny rozmiar maksymalny, należy usunąć jeden lub więcej wpisów w pamięci podręcznej, w przeciwnym razie nowy rozmiar przekroczy maksymalny. Zatem kod obliczy „targetSize”, czyli rozmiar, w jakim pamięć podręczna chce pozostać (optymalnie), czyli domyślnie 95% wartości maksymalnej. Aby osiągnąć ten targetSize, wpisy muszą zostać usunięte / eksmitowane z pamięci podręcznej. Odbywa się to za pomocą następującego kodu:

215   prywatnych  długich eksmisji ( long targetSize, iter Iterator < CachedResource >) { 
217 long now = System. currentTimeMillis ();
219 długi newSize = size. get ();
221 while (newSize> targetSize && iter. HasNext ()) {
222 CachedResource resource = iter. next ();
224 // Nie wygasaj niczego, co zostało sprawdzone w TTL
225 if (resource. GetNextCheck ()> now) {
226 kontynuować ;
227 }
229 // Usuń wpis z pamięci podręcznej
230 removeCacheEntry (resource. GetWebappPath ());
232 newSize = size. get ();
233 }
235 zwraca newSize;
236 }

Tak więc wpis pamięci podręcznej jest usuwany, gdy jego TTL wygasło, a targetSize nie został jeszcze osiągnięty.

Po próbie zwolnienia pamięci podręcznej przez eksmisję wpisów z pamięci podręcznej kod wykona:

165   if (newSize> maxSize) { 
166 // Nie można stworzyć wystarczającej ilości miejsca dla tego zasobu
167 // Usuń go z pamięci podręcznej
168 removeCacheEntry (path);
169 log. warn (sm. getString ("cache.addFail", ścieżka));
170 }

Jeśli więc po próbie zwolnienia pamięci podręcznej rozmiar nadal przekracza maksymalny, wyświetli się ostrzeżenie o niemożności zwolnienia:

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 Problem

Więc jak mówi komunikat ostrzegawczy, problem jest

niewystarczająca ilość wolnego miejsca po usunięciu wygasłych wpisów pamięci podręcznej - rozważ zwiększenie maksymalnego rozmiaru pamięci podręcznej

Jeśli Twoja aplikacja internetowa ładuje wiele niebuforowanych zasobów webResources (około maksimum pamięci podręcznej, domyślnie 10 MB) w krótkim czasie (5 sekund), otrzymasz ostrzeżenie.

Mylące jest to, że Tomcat 7 nie pokazał ostrzeżenia. Jest to po prostu spowodowane tym kodem Tomcat 7:

1606   // Dodaj nowy wpis do pamięci podręcznej 
1607 zsynchronizowane (cache) {
1608 // sprawdza rozmiar pamięci podręcznej oraz elementy usunąć, jeśli zbyt dużego
1609 czy ((cache. Lookup (nazwa) == NULL ) && cache. Alokacji (entry.size) ) {
1610 pamięci podręcznej. ładunek (wejście);
1611 }
1612 }

w połączeniu z:

231   while (toFree> 0) { 
232 if (próby == maxAllocateIterations) {
233 // Poddaj się, żadne zmiany nie są dokonywane w bieżącej pamięci podręcznej
234 return false ;
235 }

Dlatego Tomcat 7 po prostu nie wyświetla żadnego ostrzeżenia, gdy nie jest w stanie zwolnić pamięci podręcznej, podczas gdy Tomcat 8 wyświetli ostrzeżenie.

Więc jeśli używasz Tomcat 8 z tą samą domyślną konfiguracją buforowania co Tomcat 7 i otrzymałeś ostrzeżenia w Tomcat 8, to twoje (i moje) ustawienia buforowania Tomcat 7 działały słabo bez ostrzeżenia.

2.4 Rozwiązania

Istnieje wiele rozwiązań:

  1. Zwiększ pamięć podręczną (zalecane)
  2. Obniż TTL (niezalecane)
  3. Pomiń ostrzeżenia dziennika pamięci podręcznej (niezalecane)
  4. Wyłącz pamięć podręczną

2.4.1. Zwiększ pamięć podręczną (zalecane)

Jak opisano tutaj: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html

Dodając <Resources cacheMaxSize="XXXXX" />w Contextelemencie in $CATALINA_BASE/conf/context.xml, gdzie „XXXXX” oznacza zwiększony rozmiar pamięci podręcznej, określony w kilobajtach. Wartość domyślna to 10240 (10 MB), więc ustaw rozmiar większy niż ten.

Będziesz musiał dostroić się do optymalnych ustawień. Pamiętaj, że problem może powrócić, gdy nagle zwiększy się liczba żądań ruchu / zasobów.

Aby uniknąć konieczności ponownego uruchamiania serwera za każdym razem, gdy chcesz wypróbować nowy rozmiar pamięci podręcznej, możesz go zmienić bez ponownego uruchamiania za pomocą JMX.

Aby włączyć JMX , dodać to do $CATALINA_BASE/conf/server.xmlwewnątrz Serverelementu: <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" />i pobrania catalina-jmx-remote.jarod https://tomcat.apache.org/download-80.cgi i umieścić go w $CATALINA_HOME/lib. Następnie użyj jConsole (dostarczanego domyślnie z Java JDK), aby połączyć się przez JMX z serwerem i przejrzeć ustawienia, aby zwiększyć rozmiar pamięci podręcznej podczas pracy serwera. Zmiany w tych ustawieniach powinny zostać wprowadzone natychmiast.

2.4.2. Obniż TTL (niezalecane)

Obniż cacheTtlwartość o coś mniejszego niż 5000 milisekund i dostrój optymalne ustawienia.

Na przykład: <Resources cacheTtl="2000" />

Skutecznie sprowadza się to do posiadania i wypełniania pamięci podręcznej w pamięci RAM bez jej używania.

2.4.3. Pomiń ostrzeżenia dziennika pamięci podręcznej (niezalecane)

Skonfiguruj rejestrowanie, aby wyłączyć rejestrator dla org.apache.catalina.webresources.Cache.

Więcej informacji na temat logowania do Tomcat: http://tomcat.apache.org/tomcat-8.0-doc/logging.html

2.4.4. Wyłącz pamięć podręczną

Możesz wyłączyć pamięć podręczną, ustawiając cachingAllowednafalse . <Resources cachingAllowed="false" />

Chociaż pamiętam, że w wersji beta Tomcat 8 używałem JMX do wyłączenia pamięci podręcznej. (Nie wiem dokładnie dlaczego, ale może wystąpić problem z wyłączeniem pamięci podręcznej za pośrednictwem server.xml).

Devabc
źródło
Zwiększyć pamięć podręczną? Wątpię, żeby to zadziałało ... Widziałem to: private long maxSize = 10 * 1024 * 1024; w źródle. grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/…
HoaPhan
czy znalazłeś odpowiedź, dlaczego tomcat8 zalewa ostrzeżenia pamięci podręcznej
PHP Avenger
@HoaPhan 10 * 1024 * 1024 to maksymalnie 10 MB dla całej pamięci podręcznej. W zależności od ruchu w aplikacji internetowej można to osiągnąć w ciągu kilku sekund. Zwiększenie go na tyle daleko, zadziała.
Devabc,
@PHPAvenger Tomcat 7 w ogóle nie ostrzegał w tej sytuacji, podczas gdy Tomcat 8 tak, więc można to postrzegać jako funkcję ostrzegawczą. Problem polega na tym, że ostrzega nie tylko raz, ale przy każdym żądaniu zasobu do pamięci podręcznej. Byłoby ulepszeniem, gdyby ostrzegać tylko po pewnym czasie lub trafieniu w cel w pamięci podręcznej.
Devabc
@Devabc bezbłędna odpowiedź! TAKI klasyk!
gaurav
9

Masz więcej statycznych zasobów niż pamięć podręczna. Możesz wykonać jedną z następujących czynności:

  • Zwiększ rozmiar pamięci podręcznej
  • Zmniejsz TTL dla pamięci podręcznej
  • Wyłącz buforowanie

Aby uzyskać więcej informacji, zapoznaj się z dokumentacją tych opcji konfiguracji.

Mark Thomas
źródło
1
Dziękuję za komentarz. Rozumiem znaczenie wyjątku i oczywiście przeczytałem dokumentację, do której podałeś link, jednak nie rozumiem, dlaczego zmieniłoby się to z 7 na 8 bez zmian w konfiguracji. To jest, dlaczego domyślny program obsługi zasobów systemu plików miałby być inny w 8 do 7, bez odniesienia do jakichkolwiek zmian, i jest podejrzane, że został zgłoszony błąd podczas uruchamiania i rzekomo naprawiony.
iainmac999
1
Być może gdybyś przeczytał przewodnik po migracji - a konkretnie tomcat.apache.org/migration-8.html#Web_application_resources - wszystko byłoby jaśniejsze.
Mark Thomas
Pomogłoby, gdyby dokumentacja zrobiła trochę więcej, aby a) wyjaśnić, jakie zasoby trafiają do tej pamięci podręcznej i dlaczego (jest tego wiele nieporozumień!) Oraz b) jaki wpływ mogą mieć różne ustawienia (np. Po prostu ślepe wprowadzanie ustawień pamięci podręcznej każdej aplikacji internetowej dość duży może zjadać mnóstwo pamięci) i jak to odpowiednio dostroić. Pomogłoby również, gdyby istniało rozróżnienie w kodzie i konfiguracji między buforowaniem zasobów statycznych używanych przez samą aplikację a plikami statycznymi żądanymi przez agentów użytkownika i jedynie dostarczanymi przez aplikację.
volkerk
4

Nie jest to rozwiązanie w tym sensie, że nie rozwiązuje warunków, które powodują, że komunikat pojawia się w dziennikach, ale komunikat można pominąć, dołączając następujące elementy do conf/logging.properties:

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

Spowoduje to odfiltrowanie dzienników „Nie można dodać zasobu”, które są na poziomie OSTRZEŻENIE.

Moim zdaniem WARNINGniekoniecznie jest to błąd, którym należy się zająć, ale raczej można go zignorować w razie potrzeby.

Geoffrey Booth
źródło
8
Ha ha. to nie rozwiązuje problemu. Po prostu tego nie pokazuje. WTF!
T3rm1
To rozwiązuje problem nadmiernego rejestrowania, które samo w sobie może stanowić poważny problem. Powraca do zachowania poprzednich wersji tomcat, gdzie dla wielu rzeczy działały wystarczająco dobrze, więc w tym sensie „rozwiązuje” problem. Nie rozwiązuje problemu faktycznego dostrojenia pamięci podręcznej tomcat, co bardzo ładnie rozwiązuje odpowiedź devabc.
volkerk