Zmniejszanie wykorzystania pamięci Django. Nisko wiszący owoc?

136

Z biegiem czasu moje zużycie pamięci rośnie, a ponowne uruchamianie Django nie jest miłe dla użytkowników.

Nie jestem pewien, jak zająć się profilowaniem użycia pamięci, ale przydatne byłyby kilka wskazówek, jak rozpocząć pomiar.

Mam wrażenie, że jest kilka prostych kroków, które mogą przynieść duże korzyści. Zapewnienie ustawienia „debugowania” na „Fałsz” jest oczywistym problemem.

Czy ktoś może zasugerować innym? Jak dużo ulepszyłoby buforowanie w witrynach o małym ruchu?

W tym przypadku pracuję pod Apache 2.x z mod_python. Słyszałem, że mod_wsgi jest nieco szczuplejszy, ale trudno byłoby go zmienić na tym etapie, chyba że wiem, że korzyści byłyby znaczące.

Edycja: Dzięki za dotychczasowe wskazówki. Jakieś sugestie, jak odkryć, co zużywa pamięć? Czy są jakieś przewodniki po profilowaniu pamięci w języku Python?

Jak wspomniano, jest kilka rzeczy, które utrudnią przejście na mod_wsgi, więc chciałbym mieć pojęcie o korzyściach, których mogę się spodziewać, zanim zacznę orać w tym kierunku.

Edycja: Carl zamieścił tutaj nieco bardziej szczegółową odpowiedź, którą warto przeczytać: Django Deployment: Cutting Apache's Overhead

Edycja: artykuł Grahama Dumpletona jest najlepszym, jaki znalazłem w sprawach związanych z MPM i mod_wsgi. Jestem raczej rozczarowany, że nikt nie mógł podać żadnych informacji na temat debugowania użycia pamięci w samej aplikacji.

Ostateczna edycja : Cóż, omawiałem to z Webfaction, aby sprawdzić, czy mogą pomóc w ponownej kompilacji Apache, a to jest ich słowo w tej sprawie:

„Naprawdę nie sądzę, abyś odniósł wiele korzyści, przełączając się na konfigurację MPM Worker + mod_wsgi. Szacuję, że możesz zaoszczędzić około 20 MB, ale prawdopodobnie niewiele więcej niż to”.

Więc! To prowadzi mnie z powrotem do mojego pierwotnego pytania (o którym nadal nie jestem mądrzejszy). Jak należy zidentyfikować, gdzie leżą problemy? Jest to dobrze znana maksyma, że ​​nie optymalizuje się bez testowania, aby zobaczyć, gdzie trzeba ją zoptymalizować, ale jest bardzo niewiele tutoriali na temat pomiaru wykorzystania pamięci w Pythonie i nie ma ich w ogóle specyficznych dla Django.

Dziękuję wszystkim za pomoc, ale myślę, że to pytanie jest nadal otwarte!

Kolejna ostatnia edycja ;-)

Zapytałem o to na liście użytkowników django i otrzymałem kilka bardzo pomocnych odpowiedzi

Szczerze mówiąc, ostatnia aktualizacja w historii!

To właśnie zostało wydane. To może być najlepsze jak dotąd rozwiązanie: Profilowanie rozmiaru obiektu Django i użycia pamięci za pomocą Pymplera

Andy Baker
źródło

Odpowiedzi:

50

Upewnij się, że nie przechowujesz globalnych odniesień do danych. To zapobiega zwolnieniu pamięci przez moduł odśmiecania pamięci Pythona.

Nie używaj mod_python. Ładuje interpretera wewnątrz Apache. Jeśli potrzebujesz użyć apache, użyj mod_wsgizamiast tego. Zmiana nie jest trudna. To bardzo łatwe. mod_wsgijest o wiele łatwiejszy do skonfigurowania dla django niż mózg martwymod_python .

Jeśli możesz usunąć apache ze swoich wymagań, byłoby to jeszcze lepsze dla twojej pamięci. spawningwydaje się być nowym, szybkim, skalowalnym sposobem uruchamiania aplikacji internetowych w języku Python.

EDYCJA : Nie widzę, jak przejście na mod_wsgi może być „ trudne ”. To powinno być bardzo łatwe zadanie. Opisz problem, który masz z przełącznikiem.

nosklo
źródło
4
@Josh: wzdęcia i zużycie pamięci Apache są głupie, jeśli nie używasz funkcji tylko Apache. To tylko niepotrzebna warstwa.
nosklo
3
Django nadal popiera mod_python, ponieważ mod_wsgi jest wciąż dość nowy i chcą być konserwatywni. Ale jeśli będziesz obserwować społeczność Django, zobaczysz, jak ludzie masowo przechodzą na mod_wsgi. To nie potrwa długo, zanim będzie to zalecana opcja.
Carl Meyer
1
@Tiago: Apache jest dobry, gdy masz już wiele wirtualnych hostów Apache, używając SSL z Apache, itp. W tym przypadku użyj mod_wsgi. Jeśli zaczynasz od nowa, użyj spawnowania. NIGDY nie używaj mod_python.
nosklo
1
Dzięki, nosklo. Przyglądam się spawnowaniu… wydaje się, że nie ma żadnej dokumentacji… Spróbuję postępować zgodnie z instrukcjami, które znalazłem w postach na blogu i zobaczę, gdzie mogę znaleźć.
Tiago
1
Hmm, ponieważ ktoś dopiero zaczyna używać Django, będę pamiętać, że powinienem użyć mod_wsgi.
Powerlord
28

Jeśli używasz pod mod_wsgi i przypuszczalnie tarła, ponieważ jest zgodny WSGI można używać Dozer spojrzeć na zużycie pamięci.

Pod mod_wsgi po prostu dodaj to na dole swojego skryptu WSGI:

from dozer import Dozer
application = Dozer(application)

Następnie skieruj swoją przeglądarkę na http: // domain / _dozer / index, aby zobaczyć listę wszystkich przydziałów pamięci.

Dodam też tylko głos poparcia dla mod_wsgi. To robi ogromną różnicę pod względem wydajności i zużycia pamięci w porównaniu z mod_python. Wsparcie Grahama Dumpletona dla mod_wsgi jest wyjątkowe, zarówno pod względem aktywnego rozwoju, jak i pomocy osobom z listy mailingowej w optymalizacji ich instalacji. David Cramer z curse.com opublikował kilka wykresów (których niestety nie mogę znaleźć) pokazujących drastyczne zmniejszenie zużycia procesora i pamięci po przejściu na mod_wsgi w tej witrynie o dużym ruchu. Kilku deweloperów django się zmieniło. Poważnie, to oczywiste :)

Van Gale
źródło
W takim razie wkrótce opublikuję pytanie, w jaki sposób można uzyskać uwierzytelnianie oparte na plikach cookie dla użytkowników django uzyskujących dostęp do plików statycznych ...
Andy Baker
15

Oto znane mi rozwiązania profilera pamięci w Pythonie (nie związane z Django):

Zastrzeżenie: mam udział w tym drugim.

Dokumentacja projektu powinna dać wyobrażenie o tym, jak używać tych narzędzi do analizy zachowania pamięci aplikacji Python.

Poniżej znajduje się fajna „historia wojenna”, która zawiera również przydatne wskazówki:

Pankrat
źródło
5

Dodatkowo sprawdź, czy nie używasz żadnego ze znanych wycieków. Wiadomo, że MySQLdb wycieka ogromne ilości pamięci wraz z Django z powodu błędu w obsłudze Unicode. Poza tym Django Debug Toolbar może pomóc w śledzeniu świń.

zgoda
źródło
amix.dk/blog/viewEntry/19420 pokazuje, że spycharka jest używana do pokazania, że ​​MySQLdb przecieka pamięć. MySQLdb 1.2.3c1 i nowsze wersje rozwiązują ten problem.
msanders
Jak może django-debug-toolbarpomóc?
Wtower
4

Oprócz unikania globalnych odwołań do dużych obiektów danych, staraj się w ogóle unikać ładowania dużych zestawów danych do pamięci, gdy tylko jest to możliwe.

Przełącz się na mod_wsgi w trybie demona i użyj mpm pracownika Apache zamiast prefork. Ten ostatni krok umożliwia obsługę większej liczby jednoczesnych użytkowników przy znacznie mniejszym obciążeniu pamięci.

Carl Meyer
źródło
Zobacz także odpowiedź Carla tutaj: stackoverflow.com/questions/488864/…
Andy Baker
Ponadto - w kilku postach, które przeczytałem, wydaje się, że prawdziwym zyskiem jest przejście na pracującego MPM, a nie użycie mod_wsgi ...
Andy Baker
4

Witryna internetowa faktycznie ma kilka wskazówek dotyczących ograniczania zużycia pamięci przez django.

Główne punkty:

  • Upewnij się, że debugowanie jest ustawione na false (już to wiesz).
  • Użyj "ServerLimit" w konfiguracji Apache
  • Sprawdź, czy do pamięci nie są ładowane żadne duże obiekty
  • Rozważ udostępnianie zawartości statycznej w oddzielnym procesie lub serwerze.
  • Użyj „MaxRequestsPerChild” w konfiguracji Apache
  • Dowiedz się i zrozum, ile pamięci używasz
Jason Baker
źródło
2
Dzięki, już je przeczytałem. To numery 3 i 6, liczyłem na trochę więcej szczegółów! ;-)
Andy Baker
3

Kolejny plus dla mod_wsgi: ustaw maximum-requestsparametr w swojej WSGIDaemonProcessdyrektywie, a mod_wsgi będzie co jakiś czas restartować proces demona. Dla użytkownika nie powinno być żadnych widocznych efektów, poza powolnym ładowaniem strony przy pierwszym uruchomieniu nowego procesu, ponieważ ładuje on Django i kod aplikacji do pamięci.

Ale nawet jeśli zrobić ma wycieków pamięci, które powinny utrzymać wielkość procesową się zbyt duże, bez konieczności przerwania usługi dla użytkowników.

AdamKG
źródło
1
Coś podobnego jest tutaj wspomniane: mail-archive.com/[email protected]/msg84698.html, tylko że używali czasu nieaktywności zamiast maksymalnych żądań.
Tomas Andrle
3

Oto skrypt, którego używam dla mod_wsgi (o nazwie wsgi.py i umieszczam w katalogu głównym mojego projektu django):

import os
import sys
import django.core.handlers.wsgi

from os import path

sys.stdout = open('/dev/null', 'a+')
sys.stderr = open('/dev/null', 'a+')

sys.path.append(path.join(path.dirname(__file__), '..'))

os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings'
application = django.core.handlers.wsgi.WSGIHandler()

Dostosuj ustawienia myproject.settings i ścieżkę według potrzeb. Przekierowuję wszystkie dane wyjściowe do / dev / null, ponieważ mod_wsgi domyślnie zapobiega drukowaniu. Zamiast tego użyj logowania.

Dla Apache:

<VirtualHost *>
   ServerName myhost.com

   ErrorLog /var/log/apache2/error-myhost.log
   CustomLog /var/log/apache2/access-myhost.log common

   DocumentRoot "/var/www"

   WSGIScriptAlias / /path/to/my/wsgi.py

</VirtualHost>

Mam nadzieję, że powinno to przynajmniej pomóc w skonfigurowaniu mod_wsgi, abyś mógł zobaczyć, czy to robi różnicę.

Staale
źródło
1

Skrytki: upewnij się, że są opróżniane. Łatwo jest coś wylądować w pamięci podręcznej, ale nigdy nie zostanie przypisane do GC z powodu odwołania do pamięci podręcznej.

Kod Swig'd: Upewnij się, że zarządzanie pamięcią jest wykonywane poprawnie, bardzo łatwo jest przeoczyć je w Pythonie, szczególnie w przypadku bibliotek innych firm

Monitorowanie: jeśli możesz, uzyskaj dane o wykorzystaniu pamięci i trafieniach. Zwykle zobaczysz korelację między określonym typem żądania a zużyciem pamięci.

Richard Levasseur
źródło
1

Natknęliśmy się na błąd w Django z dużymi mapami witryn (10.000 pozycji). Wygląda na to, że Django próbuje załadować je wszystkie do pamięci podczas generowania mapy witryny: http://code.djangoproject.com/ticket/11572 - skutecznie zabija proces apache, gdy Google odwiedza witrynę.

Emil Stenström
źródło