Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Trabajando de forma asincronica en Django/Python

Trabajando de forma asincronica en Django/Python

Martin Alderete

November 15, 2014
Tweet

More Decks by Martin Alderete

Other Decks in Programming

Transcript

  1. Trabajando de forma
    asíncrona
    en Django/Python
    Martin Alderete
    @alderetemartin
    [email protected]

    View Slide

  2. ● Introducción y repaso
    ● Presentación de la problemática
    ● Introducción a los brokers de mensajes
    ● Algunos brokers de mensajes
    ● Soluciones propuestas a la problemática
    ○ Arquitectura
    ○ Analysis
    ○ Resumen
    ● Extra: Lock distribuido
    ● Extra: Taskqueue (Appengine)
    ● Pensamientos y conclusiones
    Agenda

    View Slide

  3. Protocolo de capa de aplicación utilizado por las web.
    Protocolo Request-Response (pregunta-respuesta).
    Protocolo SIN estados.
    Posee varios verbos (GET, POST, PUT, DELETE, ...)
    Define varios User-Agent
    Apps cliente (browser, crawlers, etc)
    Proxies
    webservers
    MÁS RÁPIDO SE RECIBE UN RESPONSE MEJOR ES!
    Repaso HTTP (HyperText Transfer Protocol)

    View Slide

  4. HTTP Request
    HTTP Response
    HTTP Request - Response Overview
    User agents
    Web Server

    View Slide

  5. Repaso Django request-response
    Controller = urls.py + views.py
    Model = models.py
    View = template.html

    View Slide

  6. Presentación de la problemática

    View Slide

  7. Presentación de la problemática
    Recordar que más rápido retornemos es mejor!

    View Slide

  8. Presentación de la problemática
    “Conclusiones”
    Acoplado al ciclo Request- Response
    No puede moverse a otra máquina
    Propenso a ser un “cuello de botella”
    Necesita manejo de errores extras (poco DRY)
    send_registration_email(user) es bloqueante
    No escala!
    El trabajo “pesado” DEBE sacarse del ciclo
    Request-Response.
    Pesado: “Todo aquello que puede demorar, agregar
    overhead o no es necesario inmediatamente”

    View Slide

  9. Intro Brokers de mensajes (DS)
    Sistema Distribuido
    Aplicacion
    (producer)
    Broker
    mensajes
    Abstraccion
    Worker
    (consumer)
    mensajes

    View Slide

  10. Intro Brokers de mensajes (DS)
    Redis, RabbitMQ, MongoDB y varios mas...

    View Slide

  11. Intro Brokers de mensajes (DS)
    Ventajas
    Contienen “Queues” tipo FIFO (FIFO-like)
    Generalmente se parecen a una HASH (key-value)
    Permiten desacoplar el sistema
    Permiten distribuir el sistema
    Permiten la intercomunicación entre tecnologías
    Permiten escalar de forma “mas” natural
    Desventajas
    Pensemos que Sistema == Sistema distribuido
    Agregan complejidad al stack
    Necesidad de mantenimiento

    View Slide

  12. Soluciones propuestas: Hardcore...
    Hardcore way = Python + Broker + Worker hogareño

    View Slide

  13. Hardcore way! Producer
    pip install redis
    redis_conn = redis.Redis(host='localhost', port=6379)

    View Slide

  14. Hardcore way! Consumer

    View Slide

  15. Hardcore way!
    Resumen...
    Simple y Complejo
    Independiente del framework del Producer
    Desacopla el sistema
    Mueve el trabajo pesado a otro lado
    Control absoluto por parte de los desarrolladores
    Todo debe ser hecho “from scratch”
    Pegado a un solo broker (Redis)
    Escalabilidad limitada
    Se re-escribe mucho código
    Monitoreo ?
    Administracion ?

    View Slide

  16. Soluciones propuestas: Django-rq
    Django-rq = Django + Redis + rq
    pip install django-rq

    View Slide

  17. Django-RQ: settings.py

    View Slide

  18. Django-RQ: @jobs

    View Slide

  19. Django-RQ: Ejecutando workers
    # Procesa solo ‘default’
    python manage.py rqworker
    # Procesa ‘default’ y ‘high’
    python manage.py rqworker default high
    # Procesa solo ‘low’
    python manage.py rqworker low
    Django-rq nos provee un management
    command!

    View Slide

  20. Django-RQ: Ejecutando...
    # Corre en el thread actual (bloqueante)
    send_registration_email(user_id)
    # Corre en algun worker procesando ‘emails’
    send_registration_email.delay(user_id)
    # Corre en algun worker procesando 'high'
    q = django_rq.get_queue('high')
    q.enqueue(send_registration_email, user_id)

    View Slide

  21. Django-RQ
    Resumen...
    Es simple de instalar y usar
    Define las “Queues” en las settings
    Concepto de “Job” y “Worker”
    Abstracción de la conexión contra Redis
    Abstracción de la comunicación con Redis
    Comando de Django para ejecutar workers
    Debemos crear jobs y ejecutar un worker
    Solo para Redis
    No almacena Resultados (debemos hacerlo nosotros)
    Para proyectos no muy demandantes ni que
    necesiten escalar mucho anda bien :)!

    View Slide

  22. Soluciones propuestas: Celery
    Celery is an asynchronous task queue/job queue
    based on distributed message passing. It is focused
    on real-time operation, but supports scheduling as
    well.
    The execution units, called tasks, are executed
    concurrently on a single or more worker servers.

    View Slide

  23. Celery
    pip install celery
    Celery = Python + Broker + Baterias incluidas!
    www.amqp.org

    View Slide

  24. Celery Application
    Es el punto de entrada de todo lo relacionado a Celery.
    Se crea una sola application (aka “app”).
    http://docs.celeryproject.org/en/latest/django/first-steps-with-django.html

    View Slide

  25. Tasks
    Son la base de una aplicacion Celery.
    Son de una clase.
    Tienen 2 responsabilidades:
    Definir que pasa cuando una task es llamada.
    Definir que hacer cuando el worker recibe la task.
    Todas las tasks tiene un nombre único.
    Son basicamente callables de python con magia.
    Por convension van en tasks.py
    Se crean usando un decorador:
    Reusable django apps/libraries
    @shared_task (from celery import shared_task)
    App concreta
    @task (from celery.task import task)

    View Slide

  26. Tasks
    Poseen muchos atributos que permiten definir cómo se
    comporta la tarea, por ejemplo:
    Task.name
    Task.bind
    Task.queue
    Task.max_retries
    Task.default_retry_delay
    Task.rate_limit
    Task.time_limit
    Task.soft_time_limit
    Task.ignore_result
    varios mas…
    http://celery.readthedocs.org/en/latest/reference/celery.app.task.html

    View Slide

  27. Tasks (tasks.py)

    View Slide

  28. Tasks mas real (tasks.py)

    View Slide

  29. Routing
    Routing es el mecanismo por el cual podemos decidir
    cuál será la Queue que debería recibir el mensaje de una
    nueva tarea hacia un worker.
    RECOMENDADO en vez de ‘queue’ en la TASK!!!

    View Slide

  30. Tasks: Llamando
    Basicamente existen dos formas:
    Usando un shortcut y opciones definidas en el momento
    de crear la tarea (@shared_task, @task).
    Task.delay(arg1, kwarg1=value1)
    Usando la forma “larga”, permite customizar la llamada a
    la tarea modificando opciones de la tarea.
    Task.apply_async(args=l, kwargs=d, **options)
    http://docs.celeryproject.org/en/latest/reference/celery.app.task.html#celery.app.task.Task.apply_async

    View Slide

  31. Workers: Consumidores de tareas
    #loglevel=INFO
    celery -A projName worker --loglevel=info
    #mas workers
    celery -A projName worker --concurrency=10
    #evenlet
    celery -A proj worker -P eventlet -c 1000
    #autoscale (prefork, gevent)
    celery -A projName worker --autoscale=10,3
    celery worker --help
    http://docs.celeryproject.org/en/latest/userguide/workers.html

    View Slide

  32. AsyncResult
    Celery nos provee de ser posible un AsyncResult (un
    future) con el resultado de ejecutar una tarea.
    Para que esto sea posible Celery utiliza un backend en
    donde almacena los resultados de las tareas.
    Este backend se configura en
    CELERY_RESULT_BACKEND
    Algunos backend validos son:
    cache (memcached), mongodb, redis, amqp, etc
    Cada backend tiene su configuracion.
    http://celery.readthedocs.org/en/latest/configuration.html#celery-result-backend

    View Slide

  33. AsyncResult: API
    Algunos métodos…
    http://celery.readthedocs.org/en/latest/reference/celery.result.html

    View Slide

  34. AsyncResult: API (desde un task_id)
    http://celery.readthedocs.org/en/latest/reference/celery.result.html

    View Slide

  35. CeleryBeat
    Es un planificador de tareas periódicas (chau cron?).
    celery -A projName beat

    View Slide

  36. Celery Canvas
    Celery nos provee mecanismos para poder agrupar,
    encadenar tareas, agregar callbacks, como así también
    procesar chunks de argumentos.
    Para esto se utiliza lo que Celery llama PRIMITIVAS.
    partial: Crea funciones parciales.
    group: Ejecución en paralelo.
    chain: Encadena tareas( f(g(a)) ).
    chord: Un grupo más un callback (Barrier).
    map: Similar a map() de Python.
    starmap: Similar a map() pero usa *args
    chunks: Separa una lista larga de elementos en partes.
    http://docs.celeryproject.org/en/latest/userguide/canvas.html

    View Slide

  37. Canvas: Ejemplos (Hay demo!)

    View Slide

  38. Monitoreo: Celery Flower

    View Slide

  39. Monitoreo: Celery Flower
    Monitoreo en tiempo real:
    Progreso e historial de tareas.
    Información sobre las tareas.
    Graficos y estadisticas.
    Control remoto:
    Estado y estadísticas de los workers.
    Apagado y reinicio de workers.
    Controlar autoscaling y pool size.
    Ver tareas que estan en ejecución.
    Administracion de queues.
    ETC…
    pip install flower
    celery -A projName flower --port=5555

    View Slide

  40. Pensamientos y conclusiones
    Los Brokers de mensajes:
    Llegaron para quedarse.
    Permiten sistemas con arquitecturas flexibles.
    Permiten la intercomunicación entre tecnologías.
    AMQP es un muy buen protocolo (www.amqp.org).
    Los sistemas distribuidos:
    Son complejos pero escalables.
    Agregan complejidad en el stack.
    Permiten distribucion del trabajo.
    Requieren mantenimiento/monitoreo constante
    Dificiles de debugear (mas si son multi-worker).
    Cada vez más servicios y pero más pequeños.

    View Slide

  41. Pensamientos y conclusiones
    Celery:
    Es EL framework para sistemas distribuidos.
    Es EL framework que todo Pythonista en sistemas
    distribuidos tiene que probar.
    Es un proyecto con mucho soporte/desarrollo.
    Tiene muy buena documentación.
    Es simple de configurar y poner en marcha.
    Es UN MUNDO para aprender y entender
    en profundidad.
    Se puede extender “facilmente”
    (signals, management commands, remotes).
    Tiene MUCHAS settings y features que aun no
    conozco/entiendo…
    Debe ser monitoreado como cualquier servicio.
    Algo seguro podemos charlar entre todos :)!

    View Slide

  42. Extra: TaskQueue
    Servicio dentro de AppEngine para procesamiento en
    background (builtin).
    Muy eficiente.
    API SUPER simple e intuitiva.
    Escalable.
    Seguro.
    https://cloud.google.com/appengine/docs/python/taskqueue/

    View Slide

  43. Extra: Locking distribuido

    View Slide

  44. Muchas Gracias!
    ¿Preguntas?
    Martin Alderete
    @alderetemartin
    [email protected]

    View Slide

  45. Muchas Gracias!
    ¿Preguntas?
    while not manos.dormidas:
    aplausos()
    Martin Alderete
    @alderetemartin
    [email protected]

    View Slide

  46. http://www.celeryproject.org/
    http://redis.io/
    http://www.rabbitmq.com/
    http://www.amqp.org/
    https://cloud.google.
    com/appengine/docs/python/taskqueue/
    http://zookeeper.apache.org/
    https://github.com/brolewis/celery_mutex
    Links....

    View Slide