Libro: High Performance Django

By rogerarjona Jan. 30, 2023, 7:49 p.m. Python Libro Django

"High Performance Django" es un libro escrito por Peter Baumgartner en colaboración con Yan Malet. El cual se enfoca en mejorar el rendimiento de las Aplicaciones Web Django. En este blog, pondré los apuntes y el resumen de cada capitulo del libro. Espero te sirvan y te motiven a leerlo.

La idea principal que pude obtener del libro es la siguiente:

"Simplicity is the best for a high performance site." | "La simplicidad es lo mejor para un sitio de alto rendimiento."

Entre más simple sea un proyecto que vaya a escalar, mas fácil será de mantener.

Capitulo 1 - The Big Picture


Pain Points / Puntos Problemáticos

Lo más importante a tener en cuenta, documentar, optimizar y tener en orden es:

  • Database - Base de Datos
  • Templates - Plantillas
  • Python (Es mejor cuando ni siquiera entra, se recomienda un Web Accelerator)

There are only two hard things in Computer Science: cache invalidation and naming things

Stack Recomendado para tu aplicación

Load Balancer

⬇️

Web Accelerator (Tambien puede usarse cache)

⬇️

Application (Django)

⬇️

Cache

⬇️

Database

Mientras mas alto se maneje la petición en el Stock, mas rapido será para el cliente. Mientras mas abajo se resuelva, mas tardado y complicado de manetener será.

Capitulo 2 - The Build


You need to separate the optimization you need from the time-wasting optimizations that won't make a difference.

Necesitas separar la optimización que necesitas de las optimizaciones que te hacen perder el tiempo y que no marcarán la diferencia.

Approach / Acercamiento

Al iniciar un proyecto en Django, debes tener en cuenta lo siguiente:

  • El proyecto debe ser fácil y rápido de instalar en diferentes entornos/dispositivos. Esto es bueno para las pruebas.
  • La configuración del proyecto debe ser fácil de manejar y enteder (separar apartados de pruebas, producción y desarrollo).
  • Ser cuidadoso con las apps de terceros! ¿Cubre exactamente lo que necesito? ¿Es fácil de utilizar e implementar?
  • Ayudarse de Django Debug Toolbar es bueno optimizar la base de datos, la vista y las plantillas.

Where to Optimize / Donde Optimizar

En la mayoría de aplicaciones web dinámicas, la base de datos se convierte en el cuello de botella. Consultar la información en disco (que es la parte mas lenta de una computadora | a menos que sea SSD)

Minimizar el numero de queries y el tiempo de consulta mejoraran la aplicacion. Ten en cuenta lo siguiente:

  • Reduce las queries utilizando select_related y prefetch_related
  • Escoge agregar mas queries que sean rápidas a utilizar una que es lenta.
  • Sera mas eficiente hacer uso de la query en cache que volver a consultar a la base de datos para hacer un filtrado.
  • Hacer uso de index en las tablas hara las consultas mas eficientes (siempre y cuando se consulte a la columna con el index)
  • Evita usar .all() esto hara lenta la consulta y el uso de la pagina web. La paginación puede ser util en casos donde muestras muchos resultados.
  • Evita el uso del .count() contar los registros de una tabla es muy lento, no siempre necesitas saber el total de registros para hacer un proceso.
  • Evita crear modelos con muchos métodos o con \@propertys. Normalmente se generan consultas o tardan mas tiempo debido a que el objeto debe crearse mientras consulta a la base de datos.
  • Utiliza defer y only en tus consultas. Excluye campos demasiado grandes o trae solo los necesarios,
  • Utiliza values y values_list. Trae los resultados como Diccionario o como Lista.
  • Haz uso del cache, puede ser configuración de la base de datos o puedes usar un middleware como Jhonny Cache o Cache Machine para Django.
  • Haz uso de las replicas, otra base de datos que solo sea de lectura.
  • Para querys muy complejas puedes utilzar .raw(query)
  • Utiliza otros tipos de Base de datos para almacenar informacion que afecta a tu base de datos. (Redis, ElasticSearch, Firebase etc.)
  • Utiliza Sharding solo si lo necesitas (tienes que ser el 0.1% de las empresas que lo necesitan)

Do Slow Work Later / Haz el trabajo lento más tarde

Never do today what you can put off till tomorrow | Nunca hagas hoy lo que puedes dejar para mañana

Celery es tu mejor amigo para las tareas asincronas o que puedan hacerse en segundo plano:

  • Llamadas a API de terceros y procesar información
  • Enviar Correos Masivamente
  • Proceso Computacional
  • Generar PDF o Archivos

Front-End Optimizations

  • YSlow and Googles PageSpeed para medir la respuesta del servidor.
  • Minimizar archivos CSS y Javascript: Puede probarse con: https://django-pipeline.readthedocs.io/en/latest/usage.html.
  • Comprimir Imágenes.
  • Servir archivos desde un CDN.
  • Subir archivos a la nube (tiene desventajas con la manipulacion en el servidor).

Testing / Pruebas

Llevar a cabo las pruebas en las partes más difíciles, más importante y las que más parezcan que pueden romperse a futuro.

  • Pruebas automatizadas y Continuous Integration (CI) con Jenkins (django-discover-jenkins):
    • Unit tests
    • Code Coverage
    • PEP8/Linting
    • Funcional test by Selenium
    • Performance Test via Jmeter

Capitulo 3 - The Deployment


Prerequisites / Requisitos previos

1. Operating systems | Sistemas Operativos

Ubuntu es el mas popular entre desarrolladores, pero no es el unico, puede utilizarse, Fedora, Debian y otors. Debido a que la comunidad mantiene la distribución con TLS, Ubuntu es el mas usado.

2. Configuration Managements |Gestión de la configuración

La configuracion de los servidores (archivos de configuracion) es importante para que no existan problemas. Puede utilizarse una aplicación para que todos los servidores funcionen igual. Es recomendable que:

  • Todos tengan la misma version del sistema operativo
  • Tengas las mismas versiones entre apps
  • Tengan las mismas configuraciones entre apps
  • Utilizar una herramienta de Despliegue como Ansible y Salt

Nota: Fabric no es una Herramienta de Gestion de Configuracion. Es bueno para ejecutar scripts remotamente pero solo eso.

Salt: https://docs.saltproject.io/en/latest/topics/index.html

3. Process Management | Gestión de procesos

Son los que permiten levantar y reinciar los servicios de la aplicación. (Por ejemplo, en vez de ejecutar runserver)

  • supervisorctl
  • service/daemon
  • circus

4. Shiping Your Code | Envío de su código

La simplicidad es la llave para hacer despliegues (deployments) repetidos y confiables.

Simplificarlos con un script es lo mas común para evitar errores humanos

  • Actualizar repositorio
  • Actualizar dependencias
  • Migrar la BD
  • Collect, Compress and push to CDN
  • Recargar Servicios UWSGI
  • Reinciar workers

5. Multiple Remote Enviroments | Varios entornos remotos

Es mejor que exista un servidor de pruebas donde se realicen nuevas integraciones. Donde los desarolladores puedan probar sin afectar a produccion. (Staggin/Develop Server)

  • Cada entorno debe estar aislado del otro
  • Ambos deben ser lo mas parecido posible (settings, software, OS etc)
  • Usar una base de datos con datos de produccion es una mala idea.
  • Que tan protegida esta la computadora de ataques?
  • Notificaciones y correos en local son mala idea si tienes una base de datos de produccion

Server Layout

  • Load balancer -> Puede usarse amazon elastic beanstalk (y parecidos) pero no es diferente de nginx + uwsgi
  • Application -> Es la capa donde corre el proyecto. Sera limitada por RAM y CPU y es lo primero que debemos escalar horizontalmente
  • Database -> No escatimes en Hardware cuando se trata de Base de datos
  • AutoScaling -> Puede ser bueno o malo dependiendo de tu stack

Tuning the Stack

1. Databases

  • Database tunning: Percona for Mysql Wizard
  • Percona Xtrabackup

2. Caches

Es buena idea implementar redis con "django-redis". Tener balanceadores de cache es bueno para evitar la caída del servicio.

Implementar servicio de cache reduce la durabilidad (durability) de la pagina/servicio debido a que cuando el servidor de cache deja de funcionar se provoca un error 500 en los usuarios. Para esto sirve los balanceadores pero no estas a salvo de que los 3 se caigan o tengan error.

Una buena opción es atrapar el error de cache y generar un log que notifique al administrador, así el cliente no vera un error 500 (Vease django-ft-cache ).

Es mejor que las sesiones las maneje Redis y No Base de datos. Esto para reducir los hits a la base de datos.

Los logs son los mejores amigos de los desarrolladores, utilizalos eficientemente pero ten cuidado con el espacio de almacenamiento.

Configuring your Servers

Los servidores en la nube han permitido la implementación de proyectos a gran escala de forma rápida y eficiente sin necesidad de tener demasiado conocimiento en el área.

Pero esto puede afectar con problemas que aparezcan con el tiempo, por lo que es mejor aprender sobre servidores y las aplicaciones/servicios que utilizamos.

1. Seguridad

El libro menciona las cosas que deberiamos hacer o al menos tener en cuenta si un servidor estara expuesto a Internet.

  • Lock Down SSH

    1.- Deshabilita el usuario root 2.- Permite que un usuario utilice el comando sudo 3.- Deshabilita el acceso con contraseñas 4.- Modificar el puerto de ssh

  • Patch Regularly

    Los servidores son seguros cuando usamos TLS pero se pueden descubrir formas de robar informacion de un servidor (Critical Zero Day). Hay que estar constamente revisando y aplicando parches de seguridad.

  • °Use Private Network

    No hay trafico en una red entre servidores y no se exponen los servicios al mundo.

  • Protect Internal Services

    Utiliza una VPN para acceder a Dashboards, servidores y el sistema de CI/CD (Jenkins, Travis, etc). Evita que se conviertan en brechas en la Red privada.

  • Firewall

    Solo permite el trafico a los puertos necesarios de tu proyecto. Puede complementarse con Iptables.

  • Secure Your Third-Party Endpoints

    Protege tus cuentas privadas (Github, AWS, Digital Ocean, Email):

    • Usa contraseñas fuertes
    • Utiliza una boveda de contraseñas
    • Habilita 2Factor Auth

2. Backup

Almacena en un lugar muy seguro una copia de seguridad de los archivos de configuración de los sistemas que manejan. Esto siempre pensando: ¿Si despierto y mis servidores desaparecieron, que estarías perdiendo/que te hace falta?

  • Para las base de datos es buena idea implementar replicas o full backups (Percona para mysql)
  • Hacer snapshots (pgdump/mysqldump)
  • Tener un segundo proveedor de almacenamientos para estaticos (Si usas amazon y sucede un error entonces cloudinary)
  • Un servidor en un datacenter diferente
  • Encriptar los backups evitara que se lleven a cabo problemas si se llegan a perder
  • Prueba tus backups de base de datos (que no se vuelvan backups de schrondinger)

Monitoring

Sin el monitoreo, las páginas en producción son cajas negras. No sabemos que es lo que pasa con lo que esta adentro. Debido a que producción es diferente a local, no podemos saber que sucedera, por lo que debemos utilizar herramientas de monitoreo que nos permitan saber que le pasa al CPU, RAM y los servicios que utilizamos.

1. Instrumentation

Necesitamos elementos que nos digan:

  • Que parte del sistema es la mas lena
  • Cual es tiempo de respuesta promedio por una peticion
  • Cuales son las vistas mas lentas
  • Cuales son las vistas mas consumidas
  • Cuales son las queries mas lentas (tardan mucho)

Se recomienda "NEW RELIC"

2. Server Resources

Lo que debe monitorearse de un servidor:

  • Promedio de Carga
  • CPU
  • RAM
  • Uso del Disco
  • Network I/O

3. Alerting

Lo mas logico es recibir una notificación antes de que suceda algo malo. Entonces cuando debemos ser alertados?

  • Errores / Estadisticas de servidor arriba de X%
  • Servidor Caido
  • Uso elevado de CPU, Disco, RAM
  • Servicio no responde

Django por defecto reporta errores por email, pero es un tema delicado ya que en caso de servidores caidos puedes recibir miles de correos de error y esto puede agregarte en la Black List de Dominios y pagar mucho debido al consumo.

Sentry es una buena opcion de Implementación

Capitulo 4 - The preparation


Before anything else, preparation is the key to success | Ante todo, la preparación es la clave del éxito

Testing | Utilizando JMeter

El llevar a cabo las pruebas necesarias para la aplicación nos ahorrara tiempo mostrando exactamente donde optimizar y cuando saber que es suficiente.

El uso de JMeter para simular el trafico de usuarios dentro de la aplicación parece una muy buena idea si tu vista tiene:

  • urls sin cache
  • urls con cache
  • consultas a db
  • peticiones AJAX

Después de cada cambio es bueno que se lleven a cabo pruebas de esto con Jenkins en un sevidor parecido a produccion (stagging)

Planificación de producción

No importa cuantas pruebas y planeación hayas realizado, nunca se podrá cubrir cada posible escenario.

Facilitar el trafico para hacer pruebas es mas recomendado que inundar de trafico el sistema. Es buena idea probar ambos casos para realizar cambios de manera eficiente.

Para facilitar el trafico (cantidad no exagerada durante tiempos prolongados):

  • Utiliza Load Balancers
  • Si tu pagina usa cache, puedes correr un script que habrá las urls mas visitadas para hacer el proceso de cache antes de llenarlo de trafico.

Para cualquier escenario que se elija, es importante tener un plan de emergencia. ¿Que harias si las cosas fueran catastroficas?

Tipo: No planeen llevar a cabo planificaciones o ejecuciones los fines de semana. El cliente no podra probar los cambios y el desarrollador no podra realizarlos.

Prelaunch Checklist → Puesta a produccion

  • Revisar la configuracion de Django
    • DEBUG y TEMPLATE_DEBUG en False
    • SECRET_KEY es un string random y largo
    • ALLOWED_HOSTS solo tenga el como tus usuarios accederan a tu proyecto.
    • CACHES tenga configurado REDIS
    • MEDIA_ROOT y MEDIA_URL esten apuntando a un servicio de Archivos (como S3)
    • Los administradores estan limitados y tienen contraseñas seguras.
  • Despliegue
    • Una revision rapida a la plataforma para verificar que funcione correctamente
    • Revisar que los logs funcionen
    • Revisar que el servicio de monitoreo este recibiendo información
    • Los errores son notificados
    • Los servicios de tercero funcionan correctamente dentro de la aplicacion (Paypal, PDF, etc)
    • El servicio de Correo esta funcionando
    • Los workers de celery estan trabajando correctamente
    • Los errores 500 y 400 estan especificados en todos los niveles (Load Balancer, Web Accelerator, Django)
    • El admin de django no es accesible o tiene /admin/
    • Los certificados SSL son validos y seguros
    • ./manage.py checksecure corre sin problemas
  • Infraestructura
    • Servidores y servicios estan seguros e inaccesibles (excepto para personal capacitado)
    • Procedimiento para el despliegue de nuevo codigo existe
    • Un plan para escalar horizantalmente si es necesario.

Capitulo 5 - The Launch


Las herramientas, las metricas y la instrumentación anterior nos ayudará a manejar el lanzamiento de la aplicación

Server Resources

Una buena idea para revisar en tiempo real los recursos del sistema es a traves de htop, con ella podremos analizar CPU y RAM

What to Watch | Que ver

  • Promedio de carga (Cores utilizados) → Si se tiene estimado un maximo entonces no debe sobrepasarse
  • Revisar los procesos. ¿Estan utilizando todo el CPU? Podemos tomar ventaja de los cores y utilizar workers para nivelar la carga
  • ¿El servidor esta usando swapping? → Conviene mas RAM o reducir el numero de procesos corriendo (servicios tal vez)

UWSGI

Utilizar uwsgitop para mostrar las estadisticas nos puede ayudar bastante.

pip install uwsgitop

Con esta terminal podremos ver:

  • Numero de peticiones servidas
  • Promedio del tiempo de respuesta
  • Bytes transferidos
  • Estatus

Databases

Monitoreo local con herramientas default.

Para POSTGRES:

  • PG_TOP
  • PG_STAT_STATEMENTS

Para MySQL

  • pt-query-digest
  • mytop

What to Watch | Que ver

  • Asegurate que el numero de conexiones este muy debajo del maximo configurado. De lo contrario, debido a crecimiento puede aumentarse este valor o utilizar un “connection pooler”
  • Revisar que no existan transacciones inactivas
  • Revisar queries lentas → Deben optimizarse
  • Las querys que son constantemente consultadas pueden cachearse

Capitulo 6 - The Road Ahead


Una vez que un sitio/aplicacion es lanzado debemos asegurarnos que se mantenga levantado y corriendo.

Durante este proceso existen 3 enemigos:

  1. Tus usuarios (via picos de trafico)
  2. Tu software (Servidores, Versiones de Sistema, Aplicaciones)
  3. Tú (Malas Decisiones)

Traffic Spikes | Picos de tráfico

  • Durante el funcionamiento “normal” de los servidores el sitio no deberia estar utilizando el 100% de sus recursos en cualquier nivel del stack.
  • Cualquier elemento del stack que este arriba del 70% debe ser optimizado
  • Debe tenerse suficientes recursos para combatir los pikos de trafico
  • Debemos ser avisados cuando se realicen campañas de marketing, durante este tiempo sabemos que aumentará el trafico
  • Creamos aplicaciones escalables, pero siempre apareceran issues → resuelvelos cuando aparezcan

Bit Rot

MANTEN ACTUALIZADO TU SOFTWARE, TUS SERVIDORES Y TODO LO QUE PUEDAS.

Poor Decisions | Malas decisiones

No cometas estos errores en producción

  • Flushing the cache → Esto llevará a tener un “cache stampede” es mejor realizar estos procesos cuando haya poco trafico
  • Las migraciones en las bases de datos pueden bloquear las tablas y esto generara problemas a tus clientes. Realiza pruebas en una replica, mide tiempos y planifica por cualquier inconveniente, Procura realizarlas sin trafico.
  • Los backups toman bastante tiempo, por lo que es mejor realizar snapshots a las replicas
  • Tener tareas en segundo plano que esten mal diseñadas (consultas pesadas, tareas tardadas etc)
  • GRADUAL DEGRADATION: Sin tener metricas del funcionamiento de tu sitio y no tener en cuenta el rendimiento de las caracteristicas tus servidores podemos entorpecer su funcionamiento (que el sitio se caiga). Por eso debemos monitorear cada cambio y revisar que no afecte al rendimiento de cada nivel del stack del sitio. Es mas facil encargarse inmediatamente que revisar meses de cambios hasta encontrar la raiz del problema