Reducción del uso de memoria de Django. ¿Fruta madura?

136

Mi uso de memoria aumenta con el tiempo y reiniciar Django no es amable con los usuarios.

No estoy seguro de cómo perfilar el uso de la memoria, pero algunos consejos sobre cómo comenzar a medir serían útiles.

Tengo la sensación de que hay algunos pasos simples que podrían producir grandes ganancias. Asegurar que 'depurar' esté configurado como 'Falso' es un problema obvio.

¿Alguien puede sugerir otros? ¿Cuánta mejora tendría el almacenamiento en caché en sitios de poco tráfico?

En este caso, estoy ejecutando bajo Apache 2.x con mod_python. Escuché que mod_wsgi es un poco más delgado, pero sería difícil cambiar en esta etapa a menos que sepa que las ganancias serían significativas.

Editar: Gracias por los consejos hasta ahora. ¿Alguna sugerencia de cómo descubrir qué está usando la memoria? ¿Hay alguna guía para la creación de perfiles de memoria de Python?

Además, como se mencionó, hay algunas cosas que harán que sea difícil cambiar a mod_wsgi, por lo que me gustaría tener una idea de las ganancias que podría esperar antes de avanzar en esa dirección.

Editar: Carl publicó una respuesta un poco más detallada aquí que vale la pena leer: Implementación de Django: Cortar los gastos generales de Apache

Editar: El artículo de Graham Dumpleton es el mejor que he encontrado en las cosas relacionadas con MPM y mod_wsgi. Sin embargo, estoy bastante decepcionado de que nadie pueda proporcionar información sobre la depuración del uso de memoria en la aplicación.

Edición final: Bueno, he estado discutiendo esto con Webfaction para ver si pueden ayudar a recompilar Apache y esta es su palabra al respecto:

"Realmente no creo que obtendrá un gran beneficio al cambiar a una configuración MPM Worker + mod_wsgi. Calculo que podría ahorrar alrededor de 20 MB, pero probablemente no mucho más que eso".

¡Entonces! Esto me lleva de vuelta a mi pregunta original (de la que todavía no soy muy sabio). ¿Cómo se puede identificar dónde radica el problema? Es una máxima bien conocida que no optimizas sin probar para ver dónde necesitas optimizar, pero hay muy pocos tutoriales sobre la medición del uso de la memoria de Python y ninguno específico para Django.

Gracias por la ayuda de todos, pero creo que esta pregunta aún está abierta.

Otra edición final ;-)

Pregunté esto en la lista de usuarios de django y obtuve algunas respuestas muy útiles.

¡Honestamente la última actualización!

Esto acaba de ser lanzado. Podría ser la mejor solución hasta el momento: perfilar el tamaño del objeto Django y el uso de memoria con Pympler

Andy Baker
fuente

Respuestas:

50

Asegúrese de no mantener referencias globales a los datos. Eso evita que el recolector de basura de Python libere la memoria.

No utilice mod_python. Carga un intérprete dentro de apache. Si necesita usar apache, use mod_wsgien su lugar. No es complicado cambiar. Es muy fácil. mod_wsgies mucho más fácil de configurar para django que con muerte cerebral mod_python.

Si puede eliminar el apache de sus requisitos, eso sería aún mejor para su memoria. spawningParece ser la nueva forma rápida y escalable de ejecutar aplicaciones web de Python.

EDITAR : No veo cómo cambiar a mod_wsgi podría ser " complicado ". Debería ser una tarea muy fácil. Explique el problema que tiene con el interruptor.

nosklo
fuente
44
@ Josh: el uso de memoria y la hinchazón de Apache es estúpido si no estás usando las características de solo Apache. Es solo una capa innecesaria.
nosklo
3
Django todavía respalda mod_python porque mod_wsgi todavía es bastante nuevo, y quieren ser conservadores. Pero si sigues a la comunidad de Django, verás a las personas cambiar a mod_wsgi en masa. No pasará mucho tiempo antes de que sea la opción recomendada.
Carl Meyer
1
@Tiago: apache es bueno cuando ya tienes muchos hosts virtuales apache, usando SSL con apache, etc. En este caso, usa mod_wsgi. Si está comenzando de nuevo, use el desove. NUNCA use mod_python.
nosklo
1
Gracias nosklo. Estoy echando un vistazo al desove ... parece tener poca o ninguna documentación ... Trataré de seguir algunas instrucciones que encontré en las publicaciones de blog y ver dónde puedo obtenerlas.
Tiago el
1
Hmm, como alguien que recién comienza a usar Django, tendré en cuenta que debería usar mod_wsgi.
Powerlord
28

Si está ejecutando bajo mod_wsgi, y presumiblemente genera porque es compatible con WSGI, puede usar Dozer para ver el uso de su memoria.

En mod_wsgi solo agregue esto en la parte inferior de su script WSGI:

from dozer import Dozer
application = Dozer(application)

Luego apunte su navegador a http: // domain / _dozer / index para ver una lista de todas sus asignaciones de memoria.

También agregaré mi voz de soporte para mod_wsgi. Hace una gran diferencia en términos de rendimiento y uso de memoria sobre mod_python. El soporte de Graham Dumpleton para mod_wsgi es sobresaliente, tanto en términos de desarrollo activo como en ayudar a las personas en la lista de correo a optimizar sus instalaciones. David Cramer en curse.com ha publicado algunos gráficos (que desafortunadamente no puedo encontrar ahora) que muestran la reducción drástica en el uso de la CPU y la memoria después de que cambiaron a mod_wsgi en ese sitio de alto tráfico. Varios de los desarrolladores de django han cambiado. En serio, es obvio :)

Van Gale
fuente
En cuyo caso, pronto a publicar una pregunta sobre la forma en que se obtiene la autenticación basada en cookies para django usuarios que acceden a los archivos estáticos ...
Andy Baker,
15

Estas son las soluciones de perfil de memoria Python que conozco (no relacionadas con Django):

Descargo de responsabilidad: tengo un interés en este último.

La documentación del proyecto individual debería darle una idea de cómo usar estas herramientas para analizar el comportamiento de la memoria de las aplicaciones Python.

La siguiente es una buena "historia de guerra" que también ofrece algunos consejos útiles:

Pankrat
fuente
5

Además, verifique si no utiliza ninguno de los filtradores conocidos. Se sabe que MySQLdb pierde enormes cantidades de memoria con Django debido a errores en el manejo de Unicode. Aparte de eso, Django Debug Toolbar podría ayudarlo a rastrear a los cerdos.

zgoda
fuente
amix.dk/blog/viewEntry/19420 muestra que Dozer se está utilizando para mostrar que MySQLdb estaba perdiendo memoria. MySQLdb 1.2.3c1 y posterior corrige esto.
msanders
¿Cómo podría django-debug-toolbarayudar?
Wtower
4

Además de no mantener referencias globales a objetos de datos grandes, trate de evitar cargar grandes conjuntos de datos en la memoria siempre que sea posible.

Cambie a mod_wsgi en modo demonio y use el mpm de trabajador de Apache en lugar de prefork. Este último paso puede permitirle servir a muchos más usuarios concurrentes con mucha menos sobrecarga de memoria.

Carl Meyer
fuente
También vea la respuesta de Carl aquí: stackoverflow.com/questions/488864/…
Andy Baker
Además, en algunas publicaciones que he leído, parece que la ganancia real está en cambiar al MPM de los trabajadores en lugar del uso de mod_wsgi ...
Andy Baker
4

Webfaction en realidad tiene algunos consejos para mantener bajo el uso de memoria django.

Los puntos principales:

  • Asegúrese de que la depuración esté establecida en falso (ya lo sabe).
  • Use "ServerLimit" en su configuración de apache
  • Verifique que no se carguen objetos grandes en la memoria
  • Considere servir contenido estático en un proceso o servidor separado.
  • Use "MaxRequestsPerChild" en su configuración de apache
  • Descubre y comprende cuánta memoria estás usando
Jason Baker
fuente
2
Gracias, ya los había leído. ¡Son los números 3 y 6 que esperaba un poco más de detalle! ;-)
Andy Baker
3

Otra ventaja para mod_wsgi: establece un maximum-requestsparámetro en tu WSGIDaemonProcessdirectiva y mod_wsgi reiniciará el proceso del demonio de vez en cuando. No debería haber ningún efecto visible para el usuario, aparte de una carga lenta de la página la primera vez que se ejecuta un nuevo proceso, ya que cargará Django y el código de su aplicación en la memoria.

Pero incluso si lo tienen pérdida de memoria, que debe mantener el tamaño del proceso de conseguir demasiado grande, sin tener que servicio de interrupción a los usuarios.

AdamKG
fuente
1
Aquí se menciona algo similar: mail-archive.com/[email protected]/msg84698.html solo que usaron tiempo de inactividad en lugar de solicitudes máximas.
Tomas Andrle
3

Aquí está el script que uso para mod_wsgi (llamado wsgi.py, y puse en la raíz de mi proyecto 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()

Ajuste myproject.settings y la ruta según sea necesario. Redirijo toda la salida a / dev / null ya que mod_wsgi por defecto impide la impresión. Utilice el registro en su lugar.

Para 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>

Esperemos que esto al menos te ayude a configurar mod_wsgi para que puedas ver si hace la diferencia.

Staale
fuente
1

Cachés: asegúrese de que estén siendo vaciados. Es fácil que algo aterrice en un caché, pero nunca se GC 'debido a la referencia de caché.

Código Swig'd: asegúrese de que la gestión de la memoria se realice correctamente, es muy fácil omitirlos en Python, especialmente con bibliotecas de terceros

Monitoreo: si puede, obtenga datos sobre el uso de la memoria y los éxitos. Por lo general, verá una correlación entre un cierto tipo de solicitud y el uso de memoria.

Richard Levasseur
fuente
1

Nos encontramos con un error en Django con grandes mapas de sitio (10.000 artículos). Parece que Django está intentando cargarlos todos en la memoria al generar el mapa del sitio: http://code.djangoproject.com/ticket/11572 : mata efectivamente el proceso de apache cuando Google visita el sitio.

Emil Stenström
fuente