¿Debería utilizar el soporte asíncrono de Django?

- Andrés Cruz

Al igual que yo, es posible que hayas considerado usar Django si quisieras un framework con todas las funciones para un desarrollo web rápido.

Desafortunadamente, Django no es famoso por su rendimiento, tal vez debido a su servicio síncrono (Sync) predeterminado. 

La sincronización funciona mal porque un subproceso del servidor solo puede atender una solicitud a la vez. Es importante destacar que las solicitudes de E/S bloquean el hilo. El rendimiento se puede aumentar agregando subprocesos del servidor, pero los subprocesos del servidor Python ocupan casi la misma cantidad de memoria que un proceso del servidor Python. Además, el uso de un servidor asíncrono evita que su equipo tenga que pensar en optimizar el parámetro de número de subprocesos. Si bien la memoria es uno de los recursos más baratos, no es óptimo para escalar costos innecesarios. Si la memoria del servidor no tiene un impacto sustancial en el precio, es posible que pueda obtener costos mucho más bajos si utiliza la tecnología sin servidor: 

https://nalkhish.medium.com/hosting-very-low-traffic-web-apps-for-cheap -en-aws-3-año-66f748cd04cf

El diseño asincrónico (Async) se agregó en Django 3.0 (https://docs.djangoproject.com/en/3.0/topics/async/) y no se menciona en la introducción. Es una ocurrencia de último momento mencionada como último tema sobre el uso de Django (https://docs.djangoproject.com/en/5.0/topics/).

Async puede superar a Sync porque un único subproceso del servidor Async puede atender varias solicitudes a la vez. Cuando una tarea espera una corrutina, devuelve el control a otros subprocesos. Este rendimiento voluntario (1) le da al diseño asíncrono el nombre de multitarea colaborativa y (2) lo hace más eficiente que el cambio de control basado en reloj en subprocesos múltiples.

Entonces eso generó las preguntas:

  • ¿Cuánto más rendimiento puede obtener Django usando una configuración asincrónica?
  • ¿Importa lo que esté haciendo la ruta/punto final (con mucha CPU o con mucha IO)?
  • ¿Qué pasa si hay una latencia baja (el servidor está cerca) o una latencia alta (el servidor está lejos)?
    experimento

Configuración del subproceso del trabajador del servidor

  • Para Sync, se utilizó Gunicorn para activar 1 trabajador de Sync (https://docs.gunicorn.org/en/stable/design.html).
  • Para Async Limited, Gunicorn se utilizó para activar 1 trabajador de Uvicorn (https://www.uvicorn.org/deployment/)
  • Para Async Unlimited, se usó Gunicorn para activar 1 trabajador de Uvicorn (https://www.uvicorn.org/deployment/), pero postgres se configuró para permitir 1000 conexiones simultáneas (más de las 100 predeterminadas).

Sincronización vs asíncrono

Sync tenía un sRPS máximo más bajo que Async unlimited. Probablemente esto se deba a que los servidores asíncronos pueden manejar múltiples solicitudes a la vez y, por lo tanto, varias solicitudes finalizaron al mismo tiempo. Esto es sorprendente porque supuestamente asyncio no cambia de contexto a menos que llegue a una declaración de espera, que no existe en la ruta de la CPU. Esto debe investigarse más a fondo.
Sync tenía una dinámica predecible y tuvo mayores éxitos generales que Async. Esto es suficiente para garantizar el uso de Sync para servicios vinculados a la CPU.
Async Limited vs Async Unlimited: Async Unlimited tuvo un sRPS máximo más alto y éxitos generales que Async Limited.

Para la ruta de lectura vinculada a IO, esto probablemente se puede atribuir a que la base de datos es un cuello de botella porque estaba fallando.
Para la ruta de creación vinculada a IO, esto debe investigarse más a fondo ya que la base de datos no fallaba por Async Limited (consulte la figura complementaria)

Sincronización frente a asíncrono

Tanto para las rutas io_read como para io_create, Sync tuvo un rendimiento mucho menor que Async (para una latencia adicional de 200 ms, la diferencia en el rendimiento general fue 40 veces mayor para io_read y 230 veces mayor para io_create).
Es probable que esto se deba a que el subproceso de trabajo del servidor estaba esperando a que finalizaran las solicitudes de la base de datos antes de poder manejar la siguiente solicitud. Esta teoría está respaldada por la relación inversa entre la latencia y el sRPS máximo y el éxito general de Sync.

Conclusión

Las limitaciones se exploran más en el archivo Readme del repositorio https://github.com/nalkhish/Asynchronize-Django (la poca información que se analiza aquí, la ausencia de lógica de reintento y la ausencia de latencia entrante), pero este estudio compara suficientemente los métodos asincrónicos y Servicio Django sincrónico.

Si usa Django y tiene cargas vinculadas a la CPU, use Sync. De lo contrario, si las cargas están vinculadas a E/S, utilice Async. Probablemente aumentará más de 10 veces el rendimiento de sus trabajadores.

No investigué el uso de múltiples subprocesos sincrónicos porque tenía que preocuparme por optimizar la cantidad de subprocesos de acuerdo con los costos de memoria adicionales y la latencia experimentada por los usuarios.

Artículo original:

https://nalkhish.medium.com/should-you-use-django-asynchronous-support-f86ef611d29f

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz En Udemy

Acepto recibir anuncios de interes sobre este Blog.