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 Context
elemencie 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ń:
- Zwiększ pamięć podręczną (zalecane)
- Obniż TTL (niezalecane)
- Pomiń ostrzeżenia dziennika pamięci podręcznej (niezalecane)
- 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 Context
elemencie 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.xml
wewnątrz Server
elementu:
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" />
i pobrania catalina-jmx-remote.jar
od 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ż cacheTtl
wartość 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 cachingAllowed
nafalse
.
<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).