Po wrzuceniu aplikacji na serwer obserwuje że wzrasta mocno pamiec zużywana przez aplikacje, od 52 mb na starcie do 300mb i aplikacja tak zamula że musze ją resetować. Jak można sprawdzić co to powoduje ? Podejrzewam jakiś gem ponieważ nie zmieniałem nic w kodzie ostatnio.
Pozwól że zajrzę do swojej szklanej kuli…
Jak zauważył Tomash podałeś za mało informacji. Co to jest za aplikacja? Aplikacja railsowa odpalona na rackowym serwerze, deamon, coś innego?
Możesz próbować robić sobie statystyki przy pomocy:
ObjectSpace.count_objects
GC.stat
plus pojechać dtrace/systemtap lub strace i zobaczyć co się dzieje w środku.
Sprawdź też inną wersję rubego (inna wersja np. 1.9.2 -> 1.9.3 - o ile to możliwe) oraz inną wersja patcha/release 1.9.3-p286 -> 1.9.3-p194. Często pomiędzy wydaniami pojawiają się różnego rodzaju błędy jak wycieki pamięci, problemy z wątkami, timerami oraz rzeczami, które trudniej testować. Sprawdź też bugtracka, czy nie ma żadnych krytycznych błędów dla Twojego wydania rubego.
PS. Oczywiście pomijam sytuacje kiedy w kodzie masz kwiatki Model.all.size itp.
E tam szklana kula, pytanie było: “jak można sprawdzić”, a nie “dlaczego tak się dzieje”
Możesz obczaić memprofa, ale wtedy musisz to jakoś zreprodukować u siebie.
https://scoutapp.com/ ma raportowanie zużycia pamięci, nie jestem pewien jak jest z new relic, ale też powinno być.
Są też różne narzędzia, które wstawiają info o zużyciu pamięci do logów, np.: https://github.com/noahd1/oink
Jeżeli masz szczęście i to jest jedna (lub kilka) z akcji, to prawdopodobnie łatwo znajdziesz wyciek używając, którejś aplikacji do monitorowania lub raportowania do logów. Jeżeli to będzie w miarę równomiernie rozłożone, to pewnie będziesz musiał się więcej pobawić memprofem lub ewentualnie to co Yeti napisał.
+1 dla NewRelic
Która wersja Rails, która wersja Ruby, jakie gemy?
Np. zestaw Ruby 1.8 + Rails 3.1.x + activeadmin lubi pocieknąć pamięć nawet w trybie produkcyjnym.
@Artur79 - sprawdź czy zatrzymuje się przy 300MB czy cały czas rośnie. Jeśli się zatrzymuje to nie masz wycieku tylko po prostu dużo ładujesz (np. Model.all ładujący tysiące rekordów z bazy w którymś miejscu). Dziwne, że zamula, brzmi jakbyś miał mniej dostępnej pamięci niż te 300MB i zaczyna swapować (popatrz czy rośnie wtedy iowait).
Jeśli to faktycznie wyciek i nie dasz rady go zlokalizować memprofem to możesz spróbować odpalić aplikację u siebie na Rubiniusie (rvm install rbx-head) i skorzystać z heap_dump’a do analizy pamięci. Nie jest to często łatwe zadanie dlatego zawsze możesz zastosować metodę udawania, że problem nie istnieje czyli restart aplikacji jeśli użycie pamięci przekroczy jakiś próg X. Passenger Enterprajz ma nawet taką opcję wbudowaną, musisz tylko go kupić (w Rubim zarabiać można nawet na wyciekach pamięci )
Przypomniałem sobie też o Kiji - jeżeli używasz 1.8.7, to twitter w swoim forku zaimplementował trochę narzędzi do debugowania takich rzeczy: http://engineering.twitter.com/2011/05/faster-ruby-kiji-update.html
@Tomash: Zadałem ostatnio pytanie o wyciek pamięci w pewnej aplikacji na pewnej liście dyskusyjnej i dostałem 4 odpowiedzi: wszystkie sugerowały użycie fork’a do rozwiązania problemu wycieku - z czego część osób napisała “faktycznie, użyłem fork’a i problem został rozwiązany”. Zasada najmniejszego wysiłku. Takie czasy.
To nie jest kwestia tylko i wyłącznie czasów i lenistwa. Specyfika MRI i jego GC jest taka, że z czasem po prostu puchnie i pamięć nigdy nie jest zwraca do systemu. Wynika to z defragmentacji pamięci (obiekty nigdy nie są przesuwane w pamięci).
Ale o której wersji MRI piszesz? Z tego co wiem, to w 1.9 ten efekt już nie występuje. Może Hosiawak się wypowie? (swego czasu miał bardzo ciekawą prezentację na temat GC w MRI i Rubiniusie).
Inna kwestia, o której pisano na Ruby Inside dotyczy 1.9.3 i GC::Profile.
dzięki za wszystkie komentarze, wygląda na to że pomogła zmiana rubyego 1.9.2-p320 na 1.9.3-p327
Zrobię kapitana analnego, ale generalnie radziłbym nie mylić zjawiska ze zjawiskiem przeciwnym.
Tak jak podejrzewałem. Swoją drogą w 1.9.3-p327 poprawili dużo baboli w tym 7 błędów z wyciekiem pamięci od wątków po I/O oraz dość upierdliwy błąd (szczególnie jak ktoś nas nie lubi z błędem z Hashami.
http://svn.ruby-lang.org/repos/ruby/tags/v1_9_3_327/ChangeLog
Jeśli chodzi o rubego i MRI to ja mam zasadę, że jak coś mi działa na konkretnym patchu rubego i nie mam z tym żadnych problemów to nie robię upgradów. Dla przykładu mam jeden krytyczny dla mnie soft, który działa w oparciu o ruby-1.8.7-p249. Jeśli zrobię upgrade do wyższej wersji 1.8.7 to mam raz na kilka dni segmentation fault, a nie mam już siły na siedzenie po nocach z gdb
To nie takie proste. Bywa że dorzucisz gema (ActiveAdmin) i nagle się okaże że aplikacja cieknie w produkcji, a problem rozwiązuje przejście na 1.9.3.
Poza tym 1.8.7 jeszcze niedawno (p352 to chyba ostatnia affected wersja) potrafił segfaultować w Marshal.c przy nie takiej egzotycznej kombinacji (headless Selenium/Webdriver + SASS): http://bugs.ruby-lang.org/issues/4339
TL;DR mamy rok 2012, nie ma żadnych powodów żeby wciąż pracować w 1.8.7 (sprawdzić czy nie projekt na Rails 2.x)
Też mam z tym problem - właśnie z Marshalem. Przy serializacji obiektów w wątkach potrafi sypnąć segmentation fault. Właśnie tylko na 1.8.7-p249 nie mam tego problemu. Problem o tyle trudny do debuggowania, że aplikacja działa sobie prawidłowo przez rand(3.days) i nagle boom z errorami w różnych miejscach.
Kiedyś (2010) próbowałem to odpalić na 1.9.2 i wtedy Marshal działał prawidłowo, ale się wysypywało co innego - z tego co pamiętam to Timeout#timeout i znowu segmentation fault. Zostawiłem to z p249 i śmiga bez żadnych problemów od 2010 roku.
Gdybym oczywiście pisał od zera, to od razu ruszyłbym na 1.9.3. Problem jednak w tym, że mam trochę kodu, który musi działać non-stop (down-time to góra 10 minut później jest ciepło) i moim zdaniem koszt debuggowania segmentation fault-ów, wstawania w nocy po telefonach z powodu awarii jest dużo większy niż dodanie kilku nowych, drobnych funkcjonalności.
Co do tego, że nie ma żadnych powodów, aby wciąż pracować na 1.8.7… Moim zdaniem jest:
- w tym konkretnym przypadku - “U mnie działa”
Uważam, że 1.8.7-p249 jest stabilny i całkiem dobrze go wytestowałem
- wydajnościowo 1.8.7 daje radę, nie potrzeba mi ficzerów, ani wydajności 1.9.3
- gemy, z których korzystam są kompatybilne z 1.8.7
Ruby 1.8.7 - 1.9.2 (MRI) nauczył mnie, aby patrzeć z dużym dystansem na kolejne, nowe wersje rubego. Czasem, gdy czytam changeloga, albo przeglądam bugtracka to włos na głowie się jeży
W moim przypadku jest też trochę inna specyfika używania. Ja nie korzystam tam z railsów, dużo używam wątków oraz bibliotek pisanych w ffi. Wydania 1.8.7 oraz 1.9.2 moim zdaniem posiadały baaaardzo dużo bugów z wątkami. Mam wrażenie, że to jest trochę pięta achillesowa rubego.
O 1.9.3 się nie wypowiadam, ponieważ nie mam go aż tak dobrze sprawdzonego w boju. Na razie przy nowych projektach sprawuje się bardzo dobrze. Gdy będę mieć więcej wolnego czasu to odpalę sobie na becie wersję w 1.9.3 i dokładnie wytestuję.
Tzn. nikt Ci nie broni pozostawać w roku 2010. Chociaż za jakiś czas się zorientujesz że gemy, których chciałeś użyć, już nie chcą być kompatybilne z 1.8, i wtedy będzie bolało.