Aplikacja zwalnia z czasem

0

Mam taki problem, dostaje tablice byte po Socket'ach TCP. Dane te parsuje przez refleksje na konkretne obiekty które następnie trafiają do bazy.

  1. Watek odbiera dane z TCP wrzuca te dane na kolejkę dyskowa
  2. Watek ściąga z kolejki dyskowej parsuje dane refkleksja zapisuje
    Problem jest taki ze jak system przez dłuższy czas jest mocno obciążony to z czasem co raz bardziej zwalnia mimo ze intensywność wysyłania danych do tej aplikacji jest ciągle taka sama.
    Wycieków pamięci brak...

Na co zwrócić uwagę?

1

Wycieków pamięci brak...

press X to doubt ;)

Trudno coś poradzić nie widząc w ogole kodu. Odpal sobie VisualVM i zobacz czy faktycznie gdzieś coś nie cieknie. Zalecałbym też używać metryk w kodzie, jakiś micrometer czy coś w tym stylu. Jeśli to jakaś produkcyjna aplikacja to warto mieć! Wrzucasz sobie w interesujące miejsce jakieś timery i widzisz gołym okiem na ładnych wykresach w grafanie które czasy rosną chociażby.
Może masz gdzieś jakieś liniowe przeszukiwanie / operacje zależne od ilości przetworzonych danych?

refleksje na konkretne obiekty

Ale nie robisz tam jakichś cudow w stylu tworzenia klas (nie obiektów) w runtime na przykład? Bo to by mogło mieć takie efekty.

Przy okazji, czemu nie jakiś protobuf albo jakaś bardziej ludzka metoda zamiast ręcznego dziergania refleksją?

0

Co do VisualVM i tym podobnych już były wykorzystane. Co do kodu niestety nie mogę go ujawniać (firmowy kod).
Dekodowanie tych danych niestety mamy załatwione refleksją w krokach:

  1. Znajdź delimiter w odebranych danych
  2. Na podstawie delimitera wiem jaki to obiekt
  3. Tworze instancję obiektu
  4. Lecimy refleksją po polach obiektu i wyciagamy wartości pól z odebranych danych
  5. Jeśli pole jest listą obiektów to lecimy 1,2,3,.. pseudo "rekurencja" (oczywiście długość list mamy w wartości int pola poprzedzającego liste itd.
    Dane które przychodzą po tcp mają swój określony format tzn wartość pola INT nie koniecznie musi być zapisana na 4 bajtach a np. jedynie na 2 itp. zaleznie od deklaracji ilosci bajtow w konrketnym obiekcie (taki mamy narzut :P )
1

Można wróżyć z fusów, ja bym sprawdził:

  1. Indeksy i locki na bazie
  2. Co robią wątki? Jeśli jest lock na bazie to będą czekać na I/O. Może wątki są zajęte, ale zadania trafiają na kolejkę puli wątków.
  3. gc logi - ile czasu aplikacja spędza na GC, czy nie ma wycieku pamięci
0
Charles_Ray napisał(a):

Można wróżyć z fusów, ja bym sprawdził:

  1. Indeksy i locki na bazie
  2. Co robią wątki? Jeśli jest lock na bazie to będą czekać na I/O. Może wątki są zajęte, ale zadania trafiają na kolejkę puli wątków.
  3. gc logi - ile czasu aplikacja spędza na GC, czy nie ma wycieku pamięci

1,2 - Zapis juz sprawdzony (jest wąskie gardło ale czas zapisu jest ciagle na jednym poziomie)
3. Sprawdzone brak wycieków, GC na bieżąco czyści pamięć, czasy różne ale raczej nie przekraczają 1s

0

Może jeszcze jakieś synchronized dzikie w kodzie?

1

No to ja dalej postuluje wrzucenie timerów do kodu. Przyda wam się i tak bo fajnie mieć jakieś metryki ;) Takie timery przynajmniej pokażą konkretnie gdzie coś zwalnia i będzie wiadomo gdzie patrzeć.

0

Jedną z rzeczy jaką zauważyłem w visualVM że JPA przy wykonywaniu persist dostając gotowy obiekt do zapisu wywołuje domyślny konstruktor tej klasy i widać że tworzy jakąś swoją instancję tego obiektu.
Po co to robi jak dostaje gotowy obiekt? Pytam bo w konstruktorze mamy dość skomplikowaną logikę która niepotrzebnie jest odpalana przy zapisie i podwyższa zużycie procka...

1

@volau bo JPA najpierw robi obiekt który jest attached do sesji bazy danych, bo przecież przekazujesz coś w stanie detached. Nie może użyc tego obiektu który przekazałeś, bo jakby tam był jakiś współbieżny dostęp to by wszystko mogło wybuchnąć dość spektakularnie. Tak jest wg specyfikacji JPA -> zobacz że merge w EntityManagerze zwraca ci obiekt -> to jest właśnie ta kopia w stanie attached. Nie da sie tego za bradzo obejść, bo tak to po prostu zostało zaprojektowane.

1

A propos JPA jeszcze, to nie puchnie Ci persistence context? Nie wczytujesz dużej liczby obiektów w jednej transakcji?

0
Charles_Ray napisał(a):

A propos JPA jeszcze, to nie puchnie Ci persistence context? Nie wczytujesz dużej liczby obiektów w jednej transakcji?

Mieliśmy jakiś czas temu że odkładało sporo w cache'u JPA ale teraz mamy clear po kazdym zapisie paczki.
Po zrzucie pamięci nie wygląda obecnie żeby jakoś to puchło.
W zachowaniu GC widać że pamieć dochodzi do jakiegoś poziomu i wchodzi GC i pamieć spada. Używamy GC1 z flagą server.
Jeśli chodzi o odczyt to akurat w tej aplikacji go nie ma jest ona odpowiedzilna za walidacje odebranych danych i tylko zapis na baze.

0
volau napisał(a):

Co do VisualVM i tym podobnych już były wykorzystane.

Zrobiliście CPU profiling visualvm-em i nadal nie wiadomo co jest konkretnie powolne?
Potencjalnie możliwe, ale naprawdę trzeba by mieć niezłego pecha, zwłaszcza w tak prostej aplikacji.
Zdecydowanie polecam nie wstawianie własnych timerów tylko naukę / praktyckę cpu profilingu.
timery kłamią bardzo, szczególnie w aplikacjach wielowątkowych,
cpu profilery kłamią również bardzo, ale da się je na tym kłamstwie przyłapać (ustawiając rózne starting points, oraz porównując z CPU samplingiem).

1 użytkowników online, w tym zalogowanych: 0, gości: 1