Jak mogę ustalić przyczynę pozornego wycieku pamięci w mojej aplikacji internetowej opartej na Apache / PHP?

18

Mniej więcej raz w tygodniu, ale czasem nawet kilka razy dziennie po kilku dniach pracy, moje instancje EC2 przestają reagować. Wykresy pamięci Munina opowiadają dość prostą historię: pamięć przydzielana „aplikacjom” zaczyna rosnąć i nie zatrzymuje się, dopóki swap nie zostanie w pełni wykorzystany i instancja zostanie skutecznie sprowadzona na kolana. Kolejny niestandardowy wykres pokazuje, że stale rosnącym procesem jest apache2.

Korzystam ze standardowej konfiguracji Apache w trybie prefork z mod_php i kilkoma skryptami PHP. Jak widać na poniższym wykresie, dzieje się coś, co powoduje, że procesy apache2 zaczynają zużywać coraz więcej pamięci. Pierwszy zielony skok, który złapałem na czas i ponownie uruchomiłem Apache, zanim sprawy wymknęły się spod kontroli. Drugi skok nieco się przesunął i instancja musiała zostać ponownie uruchomiona od razu.

Wykres pamięci Munina

Zastanawiam się, jak najlepiej to debugować. Jak skonfigurować PHP z FastCGI i uruchomić go we własnych procesach, co jest dobrym sposobem, aby dowiedzieć się, czy to Apache, czy kombinacja PHP i mojego kodu powoduje nadmierne zużycie pamięci? Jakie kroki podjęlibyście, aby wyśledzić ten problem?


AKTUALIZACJA: Byłem w stanie wyśledzić wyciek po zaangażowaniu strace, jak sugerował Matt poniżej.

Po znalezieniu procesu apache2, który stopniowo i stale powiększał się w pamięci, dodałem jeszcze kilka wywołań error_log () do mojego skryptu PHP, który wypisał całkowitą ilość RSS używaną w różnych momentach jego wykonywania (używając wyjścia ps). To jednak okazało się mylące - chociaż wydawało się, że RSS podskoczyło dopiero po uruchomieniu mojego skryptu, późniejsze debugowanie ujawniło, że tak nie było. Bądź ostrożny!

Na szczęście wszystkie te wywołania error_log () okazały się przydatne na końcu. Kiedy uruchomiłem strace ( strace -p <pid> -tt -o trace.log -s 256), zobaczyłem, że dla każdego żądania proces alokował około 400k pamięci (poszukaj wywołania systemowego „brk” i odejmij parametr pierwszego wywołania od ostatniego wywołania - kilka zwykle przychodzi w jednym po kolejnym). Następnie szukałem najnowszego wywołania systemowego „zapisz”, które zawierało komunikat o błędzie error_log (), który powiedział mi, w którym momencie skryptu przydzielana jest pamięć. Z kilkoma bardziej strategicznie umieszczonymi wywołaniami error_log () w celu dokładniejszego wskazania lokalizacji, w końcu znalazłem winowajcę.

Pamięć wyciekała, gdy wywołaliśmy curl_exec () z naszego skryptu PHP. Niektóre zawinięte kody związane z obsługą połączenia SSL robią coś źle - wyciek zniknął, kiedy przełączyłem się na HTTP. Dziennik zmian Curl odwołuje się do kilku wycieków pamięci SSL, które zostały naprawione w 7.19.5 (byliśmy na 7.18.2), więc spróbuję to później.

W międzyczasie pracuję z bardzo niskim MaxRequestsPerChild, który utrzymuje Apache w rozsądnych granicach. Dziękuję wszystkim!

ondrej
źródło
Jak zmienia się liczba procesów potomnych Apache w tym samym okresie?
SimonJ
@ Simon Simon, świetne pytanie, liczba pozostaje prawie taka sama, plus minus kilka procesów. Unosi się wokół 60, gdy serwery mają problemy, a także gdy są w spoczynku. Jednak skonfiguruję wykres Munin, aby był w 100% pewny.
ondrej
Nie jest to rozwiązanie, ale jeśli jedna z aplikacji jest znana z tego, że zjada pamięć RAM jak szalona, ​​to lepiej pozostawić swap wyłączony: gdy jądro wykryje brak pamięci RAM, zabije największe świnie pamięci (apache). Po włączeniu wymiany jądro zabije niektóre procesy znacznie później, ponieważ zamiana jest znacznie wolniejsza niż pamięć RAM. Bez zamiany - szybsze odzyskiwanie, mniejsze przestoje. (Próbowałem tylko wyłączenie swapa w podobnym przypadku na maszynie z 8GiB RAM, więc YMMW.)
Chronos

Odpowiedzi:

5

Wyśledzenie, CO powoduje problem, może być uciążliwe. Pierwszą rzeczą, którą bym zrobił, gdybym miał taki problem, jest zredukowanie MaxRequestsPerChilddo agresywnie niskiej liczby (~ 100-200) i sprawdzenie, czy to robi różnicę. Jeśli tak, to prawdopodobnie masz gdzieś w pętli kod, który będzie przeciekał, i będziesz chciał przeprowadzić audyt kodu.

Inną rzeczą, na którą warto spojrzeć, jest pełny status Apache'a, sprawdź, czy możesz dowiedzieć się, jakie konkretne żądanie powoduje wyciek pamięci. Uzyskaj identyfikatory PID podejrzanych procesów i przeprowadź śledzenie ich.

matowy
źródło
Dzięki Matt. „ps aux | grep apache2 'mówi mi, że z około 60 aktywnych procesów około tuzin zużywa dużo więcej pamięci niż powinno (> 100 MB w RSS). Przyjrzałem się wynikom / proc / <pid> / smaps i stwierdziłem, że każde ma dokładnie jedno anonimowe mapowanie, które zajmuje 95% + miejsca. Próbuję teraz dowiedzieć się, co i kiedy przydzieliłem ten ogromny fragment pamięci. Zajrzę do strace - dzięki za podpowiedź.
ondrej
2

Piątek o dokładnie 23:00? Czy to odpowiada czasowi tworzenia kopii zapasowej? Czy twój system ma dostępne wejścia / wyjścia do obsługi procesów i kopii zapasowych w tym czasie? Czy oprogramowanie, które zyskujesz na popularności, ma tendencję do # procs, a nawet tablicy wyników apache, co powiesz na dyskowe operacje we / wy?

Pierwszą rzeczą, którą chciałbym zrobić byłoby obliczyć, ile każdy mem proc trwa, a następnie ustawić rozsądny limit MaxRequests w apache tak, że $ procmem * $ procuje nie może przekraczać dostępnej pamięci RAM. Podejrzewam, że twoja instancja musi zostać zrestartowana, ponieważ OOM rozpoczyna polowanie na czarownice, które prawdopodobnie (często) nie jest zbyt owocne. Ci potrzebne , aby zapewnić pole może obsługiwać te ciężkie czasy pozostając w jej granicach i nie iść do wymiany i na pewno nie OOM. Jest to trudniejsze, jeśli masz uruchomione cronjobs, i niezwykle trudne, jeśli wspomniane cronjobs uruchamiają się jednostronnie, nie upewniając się, że jest bezpieczny do uruchomienia (tj. Co 5 minut skrypt nie sprawdza, czy ostatni 5 minut nadal działa).

Teraz, gdy masz pewność, że nawet jeśli coś pójdzie nie tak, nie będziesz musiał ponownie uruchamiać komputera, wszystko zacznie działać lepiej. Będziesz mógł zalogować się w tych ciężkich czasach i dowiedzieć się, co się dzieje przy użyciu top, dstat, free-m, iostat itp.

Metoda Matta może być warta wypróbowania, ale powinna być używana tylko jako narzędzie do rozwiązywania problemów, nie zalecam pozostawania w ten sposób, ponieważ znacznie trudniej będzie znaleźć ogólny problem przy następnym szukaniu. To powiedziawszy, to naprawdę tylko drażni problemy z apache / modułami, a nie z niczym w twoim kodzie. Myślę, że zgodzisz się, że szanse są spore, to nie jest jakiś wyciek pamięci w module apache (zakładając, że używasz renomowanej dystrybucji).

fimbulvetr
źródło
0

Pierwsze pytanie, jakie należy zadać, to jaka aplikacja działa za pośrednictwem Apache?

Czy to napisana przez Ciebie aplikacja czy aplikacja innej firmy?

Do jakich innych komponentów / pakietów się odwołuje?

Czy jesteś na bieżąco ze swoimi paczkami?

Coś konkretnego w twoich httpd.confplikach związanych z wydajnością?

królikarnia
źródło
0

Jeśli twój problem jest spowodowany aplikacją PHP i jeśli sam napisałeś oprogramowanie, polecam skorzystanie z profilera, np. PHP Quick Profiler . Jeśli dzieje się wiele transakcji w bazie danych, oprogramowanie takie jak np. Kontrollbase może pomóc w znalezieniu problemu.

Raffael Luthiger
źródło
Raffael, dzięki. Tak, aplikacja PHP jest moja i nie trafia w żadne bazy danych SQL. Daję PHP Quick Profiler szansę i zgłoś się.
ondrej