RSS feed
<< Komentarze po wyborach | Home | Instynkt >>

Java servlet - śledzenie sesji.

Artykuł techniczny

W ten ekstra długi weekend przysiadłem nad fotogaleriami.

Weekend jest wyjątkowo długi ponieważ dzisiaj w Irlandii jest urzędowo dzień wolny od pracy. Wiwat Bank Holiday!

Wykorzystuję ten wolny czas na grzebanie w fotogaleriach. Szykujemy się do przenosin na nowy serwer - powinno być niewspółmiernie szybciej, niezawodniej i spokój z miejscem na fotki na dobry rok.
Przy obecnym ruchu fotogalerie.pl koniecznie potrzebują silniejszego sprzętu i mocniejszego łącza.
plan

Przy tej okazji przeglądam kod, optymalizuję procedury itp.

Zaobserwowałem, że Tomcat zajmuje podejrzanie dużo pamięci w systemie.

plan

I tu od razu pytanie: dlaczego tak się dzieje? Niestety nie możliwe jest monitorowanie maszyny wirtualnej Java na której pracuje Tomcat produkcyjny - jest to proces koszmarnie spowalniający pracę aplikacji i nie mogę sobie pozwolić na takie ekstrawagancje...

Jako nędzną namiastkę debuggera przygotowałem prosty skrypt sprawdzający:
  • listę otwartych sesji
  • listę atrybutów w każdej z nich (session.setAttribute(...))
  • wartości atrybutów
Pierwsze wyniki mnie zaszokowały:
  • Lista otwartych sesji to średnio 2 tysiące!. Przy timeoucie ustawionym na 30 minut oznacza to, że nowa sesja zakładana jest średnio co sekundę! plan
  • To prawda że ruch na serwisie mam spory, ale główni "winowajcy"  takiego bombardowania działają z hostów i przedstawiają się jako:
    • TwengaBot/1.1 (+http://www.twenga.com/bot.html),
    • Yahoo! Slurp
    • i oczywiście Googebot
    • Mówiąc krótko - fotogalerie są bardzo indeksowane przez boty wyszukiwarek internetowych.
  • W każdej otwartej sesji jest kilkanaście atrybutów w tym 2-3 są stosunkowo duże Okazało się, że dawno temu planując obsługę informacji o zalogowanym użytkowniku (zwykły bean pełniący rolę Value Object) byłem bardzo hojny: każdy user obecny na stronie otrzymywał w swoim beanie komplet cech zawierających informacje o fotkach, które odwiedzał, na które głosował, które ignoruje itp...Te wszystkie informacje trzymane "pod ręką" w pamięci faktycznie są wygodne w użyciu natomiast konsumują znaczne ilości RAMu.

Porządki:

Odchudzenie atrybutów sesji
W ramach porządkowania przeglądam wszystkie większe atrybuty sesji (te pochodzące z java.util.Collections idą na pierwszy ogień) i w miarę możliwości uciekam z przetrzymywania ich w sesji. Przykład optymalizacji - rejestrowanie odsłon fotki:
Jak było dotychczas - już dawno zapomniałem o rejestrowaniu tej informacji w bazie w momencie otwierania strony fotki. Tablica z fotkami w SQL jest bardzo obleganym zasobem i tworzyły by się bloki co powodowałoby efekt kilkusekundowego oczekiwania na otwarcie strony www. Dlatego informację tą odkładałem do bocznej kolejki (Lista), którą osobny wątek-demon sukcesywnie przetwarzał. Dodatkowo w sesji usera zapisywałem info, że ta fotka była już odwiedzona. Jeśli user wrócił do niej ponownie w tej sesji to nie podbijał drugi raz statystyki.
W ramach optymalizacji postanowiłem zrezygnować z pamiętania w sesji historii odwiedzin. Teraz przy wejściu na stronę fotki sprawdzam czy user robotem sieciowym. Jeśli nie to odpalam osobny wątek, w którym uruchamiam proces update SQL w tablicy fotek. Uruchamiam go w trybie LOW_PRIORITY i jak zaobserwowałem jeden update może trwać nawet kilkanaście sekund(!). Nie jest to problem - wcześniej informacja była zapisywana w ciągu kolejnych 10 minut... Najważniejsze jest, że nie trzymam już historii klików w sesji i nie rejestruję odwiedzin botów.

Zmniejszenie ilości otwartych sesji
Kolejnym krokiem optymalizacji jest "gorsze" traktowanie botów wyszukiwarek internetowych. Zasada zarządzania sesjami jest taka, że wszyscy nowi wchodzący na stronę otrzymują od kontenera WWW swoją sesję - taki wirtualny pojemnik, w której można przechowywać informacje związane z tym konkretnym gościem witryny. Czas życia sesji to 30 minut - jeśli przez ten okres właściciel sesji nie wykaże żadnej aktywności to sesja jest usuwana z puli.
Zdałem sobie sprawę, że boty wyszukiwarek to goście jednorazowi - wchodzą na stronę, skanują treść tej strony i znikają. Oczywiście za sekundę wchodzą na kolejną stronę - ale nie jest to już ta sama sesja. Inaczej mówiąc - trzymanie przez 30 minut sesji, która wcale przez bota nie jest wykorzystywana to zwykłe marnotrawienie pamięci serwera.
Dlatego jeśli wykrywam że nowa sesja jest tworzona dla bota to ustawiam czas życia sesji na 10 sekund - i pozamiatane ;-)


Przy okazji tego zagłębiłem się w temat śledzenia otwartych sesji:
Tradycyjnie zarejestrowałem w aplikacji obiekt pełniący rolę "monitora zdarzeń" implementujący Interface HttpSessionListener. Obiekt ten jest powiadamiany przez kontener w momencie tworzenia nowej sesji (z tą sesją przekazywaną w powiadomieniu) lub w czasie usuwania z puli wygaśniętej sesji.

Monitor sesji.
Z tego było już bardzo niedaleko do podłączenia na stronie galerii prostego zestawienia kto aktualnie klika po stronie?.
Oto efekt: lista userów online

Wygląda przeciętnie ale od spodu:
  • wielowątkowość i synchronizacja (obiekt przetrzymujący listę sesji modyfikowany nieustannie przez wątki serwera tworzące i zabijające przestarzałe sesje)
  • sortowanie Setów danych
  • klasy anonimowe - czyli ulubione moje anonymous classes ;-)
  • no i to przegrzebywanie internetu aby znaleźć odpowiednie ikonki reprezentujące aktywność userów ;-)
Wracając do optymalizacji kodu fotogalerii. Przede mną dalsze czyszczenie sesji z ciężkich atrybutów. Mam nadzieję, że to wyjdzie na dobre serwisowi.



Add a comment Send a TrackBack