Celery: mini tutorial
Escrit per Aaloy a 28 de November , 2010 a les 6:55 p.m.
Configuració del servidor rabbitmq
El servidor Rabbitmq és qui rebrà les ordre d'execució de les tasques i les enviarà als workers que han de fer la feina i rebrà el resultats de les operacions de manera que el procés que ha donat l'ordre d'execució de la tasca el pugui fer servir.
És important destacar que a l'hora de donar l'ordre d'execució podem decidir si el resultat s'ha de guardar o bé s'ha de descartar. Si el resultat no és necessari (pensem per exemple en l'enviament d'un e-mail) llavors convé marcar la tasca per a que el resultat es descarti.
sudo aptitude install rabbitmq-server
Els paquets nous següents s'instal·laran:
erlang-os-mon{a} erlang-snmp{a} rabbitmq-server
0 paquets a actualitzar, 3 a instal·lar, 0 a suprimir i 5 a no actualitzar.
Es necessita obtenir 1398kB d'arxius. Després del desempaquetat s'utilitzaran 3187kB.
Esteu segur de voler continuar? [Y/n/?] y
Obté:1 http://es.archive.ubuntu.com/ubuntu/ maverick/main erlang-snmp i386 1:13.b.3-dfsg-2ubuntu3 [581kB]
Obté:2 http://es.archive.ubuntu.com/ubuntu/ maverick/main erlang-os-mon i386 1:13.b.3-dfsg-2ubuntu3 [77,4kB]
Obté:3 http://es.archive.ubuntu.com/ubuntu/ maverick/main rabbitmq-server all 1.8.0-1ubuntu2 [739kB]
S'han obtingut 1398kB en 2s (480kB/s)
S'estan preconfigurant els paquets...
S'està seleccionant el paquet erlang-snmp prèviament no seleccionat.
(S'està llegint la base de dades … hi ha 118931 fitxers i directoris instal·lats actualment.)
S'està desempaquetant erlang-snmp (de …/erlang-snmp_1%3a13.b.3-dfsg-2ubuntu3_i386.deb) …
S'està seleccionant el paquet erlang-os-mon prèviament no seleccionat.
S'està desempaquetant erlang-os-mon (de …/erlang-os-mon_1%3a13.b.3-dfsg-2ubuntu3_i386.deb) …
S'està seleccionant el paquet rabbitmq-server prèviament no seleccionat.
S'està desempaquetant rabbitmq-server (de …/rabbitmq-server_1.8.0-1ubuntu2_all.deb) …
S'estan processant els activadors per a man-db …
S'estan processant els activadors per a ureadahead …
S'està configurant erlang-snmp (1:13.b.3-dfsg-2ubuntu3) …
S'està configurant erlang-os-mon (1:13.b.3-dfsg-2ubuntu3) …
S'està configurant rabbitmq-server (1.8.0-1ubuntu2) …
Adding group `rabbitmq' (GID 123) ...
Fet.
Adding system user `rabbitmq' (UID 115) ...
Adding new user `rabbitmq' (UID 115) with group `rabbitmq' ...
Not creating home directory `/var/lib/rabbitmq'.
Starting rabbitmq-server: SUCCESS
rabbitmq-server.Amb això hem aconsegui instal·lar i posar en marxa el RabbitMq en un sistema Ubuntu 10.10.
Ara ens queda configurar, afegirem un usuari i un vhost per a que accepti els treballs,
a més hem de donar permisos a aquest usuari per a que que pugui enviar treballs
al vhost creat.
Afegim l'usuari:
$ sudo su $ rabbitmqctl add_user django password Creating user "django" ... ...done.
Cream l'vhost
$ rabbitmqctl add_vhost test Creating vhost "test" ... ...done.
Assignam els permisos a l'usuari per a quest vhost
$rabbitmqctl set_permissions -p test django ".*" ".*" ".*" Setting permissions for user "django" in vhost "test" ... ...done.
Ja tenim la part més complexa llesta. El servidor RabbitMQ pot estar en la mateixa màquina o en una totalment distinta de la que llançarà la tasca o de la màquina de l'executarà.
Preparant l'entorn
La gràcia del Celery és que ens permet llançar les tasques i executarles mantinguent la cohesió de la nostra aplicació. És a dir, si estam treballant amb Django Celery ens permet manetenir el codi de cridada i d'execució de la tasca des de la mateixa aplicació o des del mateix projecte.
Per començar convé que instal·lem Celery. Ho farem des de un entorn virtual,
per això convé tenir instal·lats els paquets virtualenv i virtualenvwrapper.
sudo pip install virtualenv virtualenvwrapper
i configurar el virtualenvwrapper.
Crear l'entorn, de nom per exemple celery i instal·larem el paquet celery
mkvirtualenv celery workon celery pip install celery
Que sigui un projecte Django o Python pur té molt poques diferències. En el cas de Django hem d'instal·lar el paquet django-celery i configurar el projecte. Així a les nostres aplicacions afegirem "djcelery"
INSTALLED_APPS += ("djcelery", )I també és important afegir les següents línies al settings.py
import djcelery djcelery.setup_loader()
La resta es comú tant a un projecte Python que a un projecte Django, sols que
les configuracions en el primer cas aniran a un arxiu anomenat celeryconfig.py
i en el cas de django la configuració pot anar dins el settings.py
Per la nostra primera tasca crearem un project Python simple i l'arxiu
de configuració celeryconfig.py contindrà
#-*- coding: UTF-8 -*-
BROKER_HOST = "192.168.1.10"
BROKER_PORT = 5672
BROKER_USER = "django"
BROKER_PASSWORD = "password"
BROKER_VHOST = "test"
CELERY_RESULT_BACKEND = "amqp"
CELERY_IMPORTS = ("tasks", )
CELERY_SEND_EVENTS=TrueEl prefixe BROKER fa referència al servidor RabbitMq que acabam d'instal·lar. Celery pot fer servir difernts tipus de Brookers pero RabbitMq és el més recomanat.
Fitxau-vos que el configuram amb els paràmetres amb els quals hem creat el vhost, i amb l'usuari i password creats a RabbitMq.
CELERY_RESULT_BACKEND serveix per a indicar a Celery on s'han de deixar els resultats. Podem tenir distints backends, des de Memcached, a una base de dades o una base de dades NoSQL.
CELERY_IMPORTS indica a l'aplicació que tasks.py conté les tasques que
s'han d'executar. Bé, de fet el que fa és indicar al daemon de celery
quines són les tasques a exeuctar quan es posi en marxa, però també pot
fer-se servir per altres tipus d'inicialitzacions.
CELERY_SEND_EVENTS li diu a Celery que volem monitoritzar els events que es produeixin. Si no posam aquesta ordre i després volem saber què esta passant ho tendrem molt més complicat.
Creant la nostra primera tasca
Per cerar la nostra primea tasca crearem una arxiu anomenat tasks.py
#-*- coding: UTF-8 -*-
from celery.decorators import task
@task(name='tasks.add')
def add(x,y, **kwargs):
logger=add.get_logger(**kwargs)
logger.info('Entrant a la tasca ...')
return x+yFitxem-nos que és codi Python del més normalet, sols que hem afegit un
decorador tasks per marcar la funció com a tasca i posar-li el nom. Aquest
nom és opcional, però convé posar-li ja que així evitam que celery li posi
un nom per defecte que podria fer menys portable la nostra aplicació.
També podem veure como podem enviar informació a logger des de la tasca.
Executant el worker
Ara ja podem anar al nostre projecte, si tot ha anat bé tindrem dos arxius:
tasks.py i celeryconfig.py
Executam: celeryd -l info
[2010-11-28 18:44:20,949: WARNING/MainProcess] celery@D820 v2.1.3 is starting.
[2010-11-28 18:44:20,950: WARNING/MainProcess]
Configuration ->
. broker -> amqp://django@192.168.1.10:5672/test
. queues ->
. celery -> exchange:celery (direct) binding:celery
. concurrency -> 2
. loader -> celery.loaders.default.Loader
. logfile -> [stderr]@INFO
. events -> ON
. beat -> OFF
. tasks ->
. tasks.add
[2010-11-28 18:44:20,960: INFO/PoolWorker-1] child process calling self.run()
[2010-11-28 18:44:20,962: INFO/PoolWorker-2] child process calling self.run()
[2010-11-28 18:44:20,963: WARNING/MainProcess] celery@D820 has started.amb això hem creat el nostre primer worker preparat per a executar la tasca que
li diguem (i que estarà dins tasks.py). Per aquest article hem deixat el
worker dins al consola, però es pot deixar com a dimoni. Consulteu el vostre
administrador de sistemes de capçalera per a una configuració acurada. El paràmetre
que li passa indica que volem que generi log en mode info. Fixem-nos que també
ens informa de les tasques disponibles i del nivell de concurrència que tenim, 2
en el meu cas, que és el nombre de processadors del portàtil.
I executam la tasca
Des d'una altra consola executarem l'interpret de Python
>>>from tasks import add >>>result = add.delay(2,3)
Si ara observam la consola del worker veurem alguna cosa semblant a això:
[2010-11-28 18:46:57,783: INFO/MainProcess] Got task from broker: tasks.add[c379421f-fa6a-4917-b45a-4833a9e30ef3] [2010-11-28 18:46:57,830: INFO/PoolWorker-2] [tasks.add(c379421f-fa6a-4917-b45a-4833a9e30ef3)] Entrant a la tasca ... [2010-11-28 18:46:57,879: INFO/MainProcess] Task tasks.add[c379421f-fa6a-4917-b45a-4833a9e30ef3] succeeded in 0.0486330986023s: 5
El brooker (RambbitMQ) ha enviat l'ordre d'execució de la tasca add que el worker té registrada i aquest es disposa a executar-la.
Des de la consola hem dit a la coa que volíem que la tasca s'executàs en modoe asíncron, d'aquí l'ús de delay.
Si ara volem obtenir el resultat farem
>>> print result.get()
5Com es pot veure l'exemple és molt senzill, potser massa per adonar-nos de la potència de Celery. Pensem que en lloc d'una suma podem fer la generació d'un pdf, l'enviament d'un e-mail, la càrrega en batch d'un xml, etc. etc. L'important és que el procés principal ja no té que realitzar la tasca i pot ser una altra màquina l'encarregada de fer-ho. Pensem en una màquina plena de targes gràfiques dedicades al processament numèric, en un sistema encarregat del data-mining dels logs, les possibilitats són infinites.
També és important notar l'escalabilitat que aconseguim amb Celery. No estam parlant ja d'escalabilitat amb nombre de processadors, sinó que parlam d'escalabilitat amb nombre de màquines. Mentre les nostres tasques puguin ser paralelitzades podrem fer servir Celery per a distribuir la càrrega de feina entre les màquines disponibles.
I això és sols el principi: celery pot substituir al Cron, permet la monitorització,
la creació de tasques molt més complexes que les que ens permet una funció i un
llarg etcètera d'opcions. La documentació és força completa, però llevat de
casos molt especial, el grau de dificultat que trobarem és el que hi ha a aquest post.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Introducció a Celery
Escrit per Aaloy a 13 de November , 2010 a les 12:18 p.m.
Introducció a Celery
Celery es una aplicació que ens permet crear tasques de feina asíncrones gestionades per un gestor de cues que està basada en l'enviament de missatges de manera distribuïda. Es focalitza en operacions en temps real però també suporta la calendarització de tasques.
Les unitats d'execució, anomenades tasques, s'executen de manera concurrent en un o més nodes de treball. Aquestes tasques poden executar-se de manera asíncrona bé de manera síncrona (esperant fins que la tasca està llesta).
El sistema de missatgeria recomanat per celery és RabbitMQ encara que és bastant agnòstic en el tema i pot fer servir com a substitut Redis, MongoDB o una base de dades sql.
Encara que el programa va sorgir lligat a Django, actualment és una llibreria que es pot utilitzar de manera independent. S'han creat dos projectes a partir de l'original, Celery manté l'estructura bàsica de la llibreria i django-celery manté la integració amb Django.
Bé, fins aquí la parrafada d'introducció traduïda amb més o menys fortuna de la documentació de Celery, el que estam dien és que celery ens permet executar tasques de manera distribuïda, on el director d'orquestra (si seguim les recomanacions) és una aplicació anomenada RabbitMQ, escrita en Erlang, per cert, que se n'encarrega de rebre les ordres de les tasques que s'han d'executar i les distribueix entre els distints nodes que estan registrats per a executar dita tasca. Aquest director és el que se n'encarrega de saber com està cada tasca i d'obtenir-ne el resultat quan aquesta finalitza, de manera que el programa que ha encomanat la tasca.
Així dons hem de distingir tres actors en tot això, l'aplicació que comana la tasca, l'aplicació que executa la tasca (el worker) i l'aplicació que se n'encarrega de la comunicació entre qui comana la tasca i qui l'execute. La gràcia de tot això és que podem tenir més d'un worker a distintes màquines o a la mateixa màquina, de tal manera que el gestor se n'encarrega de repartir les tasques en funció de qui està lliure per executar-les.
Pensem un noment amb el que això significa: podem passar de tenir una aplicació que ho fa tot, a un conjunt d'aplicacions que poden estar en distintes màquines que col·laboren entre sí. Resumint: ens permet l'escalabilitat horitzontal.
Per què fer servir Celery?
Abans de Celery la meva experiència havia estat amb Beanstalkd, un sistema semblant, molt simple i ràpid. Ara us contaré una batalleta, estant de cap de projecte per Tui España un dels projectes que duia era el de la creació d'un servei web per a la venda on-line de transfers i excursions. La informació estava (i supòs que encara hi és) a una base de dades Oracle i amb una estructura pensada per a introduir-hi informació, de manera que fer una consulta un poc complexa com "vull totes les excursions que hi ha tal dia que es poden fer des de tal punt" era extremadament lent. La solució que trobàrem va ser desnormalitzar la informació passant-la cap a una base de dades Postgresql, un parell mallorquí de milions de registres que s'actualitzaven diàriament.
La primera versió del programa de càrrega estava fet amb Java, va ser complexe de crear, gairebé 3 mesos de feina, mal de mantenir i executant-ho tot amb fils estava gairebé 2 hores en tenir-ho tot carregat.
La segona versió la férem amb Python, una setmana i mitja, un 10% del codi, més funcionalitat i utilitzarem Beanstalk per a distribuir les tasques, ja que la càrrega en sí es podia particionar molt bé. Això ens permeté aprofitar la potència de servidors que estaven ociosos i aprofitar també els temps morts entre la consulta a Oracle, el parseig de la resposta i la introducció a Postgres. A una de les proves posarem en marxa processos a 4 servidors diferents, amb un total d'uns 20 workers i un temps de càrrega d'uns 3 minuts. Amb 2 servidors el temps era d'uns 5 minuts, una millora molt significativa respecte a l'aplicació Java.
Així doncs una de les utilitat que tenim és la de poder distribuir tasques molt pesades entre moltes màquines. Celery el que té molt millor que Beanstalk és una documentació molt acurada, sistemes de monitorització i gestió i en el cas de fer servir Django, la possibilitat de mantenir les tasques dins el mateix projecte.
El segon ús important de Celery és la web. En aplicacions web el que volem és donar la millor experiència d'usuari possible, i aquesta experiència es degrada si l'usuari ha d'esperar molt. El que ens interessa és donar la resposta a l'usuari de que la seva comanda s'està està executant i deixar el servidor web lliure per poder atendre altres peticions. Imaginem-nos per exemple una aplicació de comerç electrònic on l'usuari demana una factura i aquesta li arriba en pdf. En sistemes de molta càrrega la generació del pdf pot degradar la resposta global de la web, el que és interessant és poder enviar la petició de factura a un sistema extern a la web i que sigui aquest l'encarregat de la generació i l'enviament. Aquest sistema no té perquè estar ni tant sols a la mateixa màquina on hi ha l'aplicació web o poden aprofitar-se hores de poca càrrega per a fer-ne la generació i l'enviament.
Anar cap a la complexitat d'arquitectura que representa afegir un sistema de cues asíncron a la nostra aplicació implica voler anar cap a un aprofitament dels recursos i sobretot entendre com funciona la nostra aplicació, què s'ha de fer de manera immediata i què es pot fer de manera asíncrona, saber quines són les tasques més feixugues que ens afecten i com podem paralelitzar-les i distribuir-les. L'altra solució és posar més màquina amb n-mil cores i passar de tot, però a més de ser una opció econòmicament més cara i tècnicament discutible, és una opció a curt termini, ja que si la nostra aplicació té molt èxit pot arribar un moment on ja ni hi hagi màquines més grans o el cost de les mateixes es mengi tot els nostres beneficis. Podem acabar fent feina pel fabricant de hardware i per pagar-ne les llicències associades.
Convençuts? Esper que sí. Un sistema així no és per totes les aplicacions, la complexitat d'instal·lació i manteniment és més gran que tenir tot el sistema en una màquina i sense distribuir, però si teniu necessitats de fer càlculs intensius de manera puntual o tasques per les quals no voleu fer esperar l'usuari Celery és una molt bona solució. A més pensau amb sistemes com el núvol d'Amazon, puntualment podem aixecar-ne tantes instàncies com calgui i executar-ne workers, o imaginem un Datacenter propi on la majoria de servidors estan ociosos, podem posar workers a les màquiens amb mensy càrrega per a que ajudin en els processos pesats. Se'ns obre un ventall de possibilitat pràcticament il·limitat.
En el proper post, instal·lació de Celery, la creació d'una tasca i un exemple d'integració amb Django, així com problemes que ens podem trobar i com a evitar-los.
Traducciones/Translations by apertium
6 comentaris, 0 trackbacks (URL) , Tags: Python Django
