Ulimit

Mam problem, sytuacja wygląda następująco:

Kilka serwerów, różne aplikacje Rails 2.3 działające na passengerze. Od czasu do czasu któraś z aplikacji zajmuje całą pamięć serwera (w kilka sekund - to nie jest wolny wyciek pamięci który trwa tygodniami) i serwer pada. Ciężko dowiedzieć się która bo problem nie występuje na dev/staging i nic nie jest logowane nigdzie (nie ma zasobów żeby cokolwiek logować) . Aplikacje korzystają z innych procesów (np. java, wkhtmltopdf, imagemagick) więc to niekoniecznie wina Ruby (chociaż to jest najbardziej prawdopodobne).

Passenger nie posiada wbudowanej opcji monitorowania pamięci więc odpada. God/monit - z tego co wiem monitorują procesy co jakiś czas a z tego co zauważyłem położenie serwera z 8GB pamięci zabiera kilka sekund.

Rozważam opcję ustawienia limitu na pamięć/proces przy pomocy ulimit. Z wstępnego rozeznania wynika, że działa to dobrze, zaimplementowane jest w jądrze więc bedzie działać dopóki jądro nie padnie. Jeśli np. ustawię limit max 500MB/proces i aplikacja zacznie mocno alokować pamięć to Ruby rzuci wyjątkiem “Cannot allocate memory” - dowiem się w końcu która to aplikacja i serwer powinien wciąż działać.

Jeśli ktoś ma jakąś opinię na ten temat (albo zna inne lepsze rozwiązanie) to chętnie usłyszę.

Z góry dzięki.

Kiedyś była taka opcja w passengerze, ale niestety to wyrzucili…

Co do ulimit to nie próbowałem, ale jak miałem kiedyś tego typu problem (bardzo szybki wyciek, kilka sekund i trzeba restartować serwer), to chodziło o rekurencyjne wyciąganie rekordów. Jeżeli masz gdzieś coś takiego, to sprawdź czy przypadkiem 2 rekordy nie są zlinkowane nawzajem.

Jakby ulimit nie dało rady jest jeszcze softlimit z daemontools http://cr.yp.to/daemontools/softlimit.html

Dzięki. Obczajam jeszcze cgroups

Określenie “od czasu do czasu” jest deterministyczne, czy aplikacje działają dobrze powiedzmy tydzień i w losowym momencie boom? Jeśli masz wycieki pamięci i serwer “pada” to w dmesgu powinny być komunikaty kernela, że nie mógł zaalokować pamięci wraz z informacją o nazwie procesu + pid. Jeśli jesteś w stanie odtworzyć problem w krótkim czasie (np. przez kilka minut serwery działają i nagle trach) to w myśl zasady “taśmą i sznurkiem klejącym”:

(while true; do top -b -n1 >> /tmp/top.output; sleep 1; done)&

i później analizować co najwięcej ramu żarło.

Odnośnie tego co pisał @drogus to ja kiedyś natomiast miałem przypadek, że programista napisał

@count = User.find(:all).size

I leciał milion rekordów z bazy :wink:

PS. Jeszcze przyszło mi do głowy. Piszesz, że portale korzystają z innych binarek (java, wkhtmltopdf). Gdy zrobisz np.:

[y3ti@mbp ~]$ ruby -e ‘sleep 100

to ps Ci powie, że

27814 ttys004 0:00.02 ruby -e sleep 100
27815 ttys004 0:00.00 sleep 100

więc ruby się nie wywali tylko wywali się proces, który odpalił ruby

U nas produkcyjnie korzystamy z cgroups(nowsze i fajniejsze)/ulimit jeśli potrzeba. Niestety tak jak napisałeś -> god/monitd jest bardzo słaby do monitorowania takich rzeczy (nie da się ustawić sensownego interwału aby wyłapać “peak” a potem jest już za późno).

Problem rozwiązany chociaż znalezienie rozwiązania zajęło sporo czasu i nerwów.

Problem pomogło namierzyć zainstalowanie atop’a i jego logi. Po OOM można odtworzyć sytuację na serwerze minuta po minucie i zobaczyć jaki był stan serwera w danym momencie (list procesów, zajęcie pamięci przez każdy z nich).

Okazało się, że jedna z aplikacji woła:

java -cp Multivalent.jar -layout x,x

Co mniej więcej oznacza “utwórz dokument pdf z 2 slotami na stronie - oba puste, utwórz następną stronę do momentu aż wypełnisz czymś wszystkie sloty etc.” - w praktyce powstawał “dokument z niekończącymi się stronami w pamięci”, działo się to dosyć szybko ale atop zdążył zawsze to wyłapać - więc polecam dopisanie atop’a do listy bardzo przydatnych narzędzi.

Jeżeli masz gdzieś coś takiego, to sprawdź czy przypadkiem 2 rekordy nie są zlinkowane nawzajem.