Tornado WEB

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 4

Python: Tornado DESARROLLO

Una tormenta en la comunidad Python

TORNADO
FriendFeed tena un par de ases en la manga para alcanzar el xito: Python y Tornado Web.POR JOS MARA RUZ

cin, pero claro, eso implica arrancarlos, lo que consume tiempo y recursos. Gracias a las colas de eventos, Python y el ncleo del sistema trabajan mano a mano para afrontar la carga de trabajo. Los detalles tcnicos son bastante complicados, de ah la creacin del proyecto Twisted para ofrecer a toda la comunidad Python acceso a esta tecnologa. El da 10 de septiembre de 2009, Bret Taylor (ver Recurso [2]) mostr al mundo Tornado Web. Tras la adquisicin de FriendFeed por parte de FaceBook, y empleando el programa Facebooks open source initiative, consigui permiso para liberar Tornado Web como proyecto de software libre en la web que aparece en el Recurso [1]. Desde ese mismo da se desat una tormenta en la comunidad Python.

Tornado Web
Comencemos por instalarlo en nuestro sistema. Tornado Web es una librera diseada para Python 2.X, y an no ha sido portada a Python 3.X, por lo que necesitaremos en nuestro sistema como mnimo la versin 2.5 de Python. Podemos seguir las siguientes instrucciones:
$ wget -c http://www.tornadoweb.org/U sstatic/tornado-0.2.tar.gz $ tar xvzf tornado-0.2.tar.gz $ cd tornado-0.2 $ python setup.py build $ sudo python setup.py install

egar la importancia de la Web en cualquier lenguaje de programacin extendido a da de hoy es imposible. Existen incluso ejemplos de lenguajes como Ruby, que han alcanzado fama mundial gracias a unas libreras que permiten la creacin sencilla de pginas webs: Ruby On Rails. Y no hablemos ya de PHP, un lenguaje que no existira sin la web. Y Python? A pesar del gran influjo de proyectos como Django, que convierte el proceso de creacin de pginas webs en un juego de nios, Python siempre ha ido rezagado en esta carrera. Nunca ha demostrado la simbiosis necesaria que han mostrado, por ejemplo, lenguajes como Perl o PHP con el proyecto Apache. Tampoco estaba, ni est, tan necesitado de un empujn que animara a su uso como el que necesitaba Ruby.

sea a travs de la llamada del sistema epoll en Linux (ver Recurso [3]) o el sistema kqueue en los sistemas BSD, ver Figura 1. El resultado? Se pasa de atender unas 800 pginas por segundo en CherryPy (un servidor web Python puro basado en hebras), a ms de 2000 peticiones por segundo con Twisted o Tornado Web. Y todo por el simple hecho de comer lo que se necesita. Me explico. Lo que ocurre con llamadas como epoll es que podemos comunicarle al sistema cuntos paquetes queremos procesar en cada ciclo. Es decir, podemos indicar que vamos a procesar un nmero mximo de peticiones y que cada x segundos nos d las que tenga. Para ello creamos un bucle infinito en el que vamos procesando las peticiones en esos trminos. La forma habitual de hacer esto es vincular una hebra o proceso a cada peti-

Hay que tener en cuenta que, desde la publicacin de este artculo, es posible que la versin de Tornado Web haya variado, por lo que es recomendable ir a la pgina del proyecto y comprobar si es la ms reciente. Una vez tengamos instalado Tornado Web podemos pasar a crear nuestro Hola Mundo directamente, ver Listado 1

El Problema de FriendFeed
La empresa FriendFeed necesitaba una solucin ya! Precisaban crear una infraestructura web en Python de alto rendimiento. Evaluaron Twisted, pero les pareca mal documentado y demasiado complicado. Como empresa, deban crecer rpidamente y acumular tantos usuarios como fuera posible ofreciendo el mejor servicio posible con los mnimos recursos. Se liaron la manta a la cabeza y crearon su propio framework web: Tornado Web. Tanto Twisted como Tornado Web hacen uso de la infraestructura de notificaciones de eventos que ofrece el sistema operativo, ya
01 02 03 04 05 06 07 08

Listado 1: Hola Mundo!


#!/usr/bin/env python2.6 # -*- coding: utf-8 -*import tornado.httpserver import tornado.ioloop import tornado.web 12 aplicacion = tornado.web.Application([ 13 (r/, HolaHandler), 14 ]) 15 16 if __name__ == __main__: 17 servidor_http = tornado.httpserver.HTTPServer( aplicacion) 18 servidor_http.listen(8080) 19 tornado.ioloop.IOLoop. instance().start()

class HolaHandler(tornado.web.Reques tHandler): 09 def get(self): 10 self.write(Hola Mundo!) 11

WWW.LINUX- MAGAZINE.ES

Nmero 54

43

DESARROLLO Python: Tornado

Si analizamos este ejemplo podemos comprobar que slo necesitamos las libreras de Tornado Web para arrancar un servidor HTTP. Importamos el famoso bucle de eventos en la segunda lnea de cdigo, y lo podemos ver arrancar en la ltima. Realmente no tenemos que saber mucho sobre l para sacarle partido, lo cual es una buena noticia. Tornado Web se basa en el concepto de Application. Las Application se crean como un objeto ms, al que pasamos una serie de rutas y el handler que va a gestionarlas. En este caso la ruta /, que se corresponde con la web que aparece por defecto en nuestra web, ser gestionada por el handler HolaHandler. Por ltimo, un handler es una clase que hereda de RequestHandler e implementa algunos de sus mtodos. En el protocolo HTTP se definen las rdenes a las que una direccin URL debe responder. La ms importante es GET, que es la que se emplea para traer una web desde el servidor. Pues bien, esa es la que nosotros implementamos en nuestro handler, lo nico que hacemos es devolver la cadena Hola Mundo! ante cualquier peticin GET dirigida hacia /. Una vez lista nuestra aplicacin, slo nos queda conectarla al servidor HTTP, comunicarle a ste en qu puerto queremos que trabaje (cualquier puerto por encima del 1024

no requiere permisos especiales de root) y, como dijimos al principio, arrancar el bucle de eventos. Si introducimos en nuestro navegador la ruta http://localhost:8080, podremos ver nuestro saludo desde Tornado Web. Pero no estamos explorando Tornado Web por su belleza, sino por su rendimiento! Por lo que es hora de hacerlo sufrir. Emplearemos el comando:
$ ab -n 1000 -c 10 U http://localhost:8080/

Figura 1: Bucle de eventos vs Polling.

Este comando es parte del proyecto Apache, por lo que si no dispones de l, deberas buscarlo en tu sistema de paquetes junto a la palabra apache. Si lo ejecutamos, obtenemos una salida bastante larga de la que el punto ms interesante es el siguiente:
.... Requests per second: U 2814.31 [#/sec] (mean) ....

ser una de las pginas ms visitadas en Espaa y entrar en los ranking mundiales creo que es posible hacerse una idea de la potencia de Tornado Web. Pensemos que conseguimos esto sin la intermediacin de Apache, y que el servidor Python ms potente, CherryPy, slo logra 800 peticiones por segundo. Twisted tambin se acerca a esta cifra, pero quedndose en torno a las 2000 peticiones por segundo. Viendo estas cantidades es fcil entender el revuelo que ha causado Tornado Web. El orgullo de Twisted ha sido herido. Pasemos ahora a analizar ms profundamente este nuevo framework y veamos cmo podemos crear una web con l.

Para hacernos una idea de lo que esto significa, 2814 peticiones respondidas por segundo equivalen a responder 243.129.600 peticiones al da. Si consideramos que tener un milln de peticiones al da podra considerarse como

Plantillas, Componentes y Mil Detalles


He titulado de esta forma tan curiosa esta seccin porque creo que hay que resaltar una

Listado 2: Aplicacin Simple


01 02 03 04 05 06 07 08 09 10 11 12 13 14 #!/usr/bin/env python2.6 # -*- coding: utf-8 -*import tornado.httpserver import tornado.ioloop import tornado.web class Producto: def __init__(self,id, nombre, detalles): self.id = id self.nombre = nombre self.detalles = detalles productos = [ Producto(1, Lpiz, El mejor....), Producto(2, Boligrafo, El mejor....), Producto(3, Goma, El mejor....), Producto(4, Libreta, El mejor....), Producto(5, Chincheta, El mejor....), ] 25 return 1,50 eur 26 27 class ProductoHandler(tornado.web.RequestHandler): 28 def get(self, id_producto): 29 producto = (p for p in productos if p.id == int(id_producto)).next() 30 self.render(producto.html, producto = producto, precio = calcula_precio) 31 32 class ProductosHandler(tornado.web.RequestHandler): 33 def get(self): 34 self.render(productos.html, productos = productos) 35 36 aplicacion = tornado.web.Application([ 37 (r/, ProductosHandler), 38 (r/producto/([0-9]+), ProductoHandler) 39 ]) 40 41 if __name__ == __main__: 42 servidor_http = tornado.httpserver.HTTPServer(aplicacion) 43 servidor_http.listen(8080) 44 tornado.ioloop.IOLoop.instance().start()

15 16 17 18 19 20 21 def calcula_precio (producto): 22 if producto.id > 2: 23 return 1,75 eur 24 else:

44

Nmero 54

WWW.LINUX- MAGAZINE.ES

Python: Tornado DESARROLLO

Listado 3:Ffichero base.html


01 <html> 02 <head> 03 <title>{% block titulo %}Librera LM{% end %}</title> 04 </head> 05 <body> 06 <h1>Linux Magazine</h1> 07 <hr /> 08 09 10 11 12 {% block contenido %} Datos de ejemplo {% end %} <hr/> <p>2009 (c) Linux Magazine</p> 13 </body> 14 </html> 01 02 03 04 05 06

Listado 4: Fichero productos.html


{% extends base.html %} {% block contenido %} <ul> {% for producto in productos %} <li><a href={{ /producto/ + str(producto.id) }} ><strong>{{ producto.nombre }}</strong></a></li> {% end %} </ul> {% end %}

Listado 5: Fichero producto.html


01 {% extends base.html %} 02 03 {% block titulo %} 04 Librera LM: producto {{producto.nombre}} 05 {% end %} 06 07 {% block contenido %} 08 <h2>{{ producto.nombre }}</h2> 09 <p>{{ escape(producto.detalles) }}</p> 10 <p><strong>{{ precio(producto) }}</strong></p> 11 12 <p><a href=/> volver ... </a> </p> 13 14 {% end %} 07 08 09

que apareca en el navegador, por la siguiente:


self.render(saludo.html, U titulo=Saludo, U saludo=Hola mundo!)

gran diferencia entre el software libre que proviene de la empresa y aquel que proviene de la comunidad. Los detalles, esa parte de las aplicaciones que generalmente consume el 80% del esfuerzo, estn bastante bien cuidados en Tornado Web. Qu entiendo por detalles? Pues por ejemplo, que incluye soporte para internacionalizacin, o que dispone de sistemas que evitan el uso malicioso de la aplicacin. En otros frameworks, estas responsabilidades se descargan en libreras externas al proyecto, pero en Tornado Web se las considera esenciales para la creacin de una aplicacin web coherente. Sin embargo, Tornado Web, no ofrece ningn soporte integrado para la gestin de bases de datos. Mientras Django y otros frameworks (como Turbogears) nos ofrecen un ORM (Object Relation Mapper) como parte de su oferta, Tornado Web no quiere posicionarse sobre cmo se gestionarn los datos. Esto significa que queda en manos del desarrollador seleccionar y emplear el sistema que ms le interese. Personalmente creo que la opcin de emplear SQLAlachemy (ver Recurso [5]) es muy interesante. Nos centraremos en aquellas partes de Tornado Web que nos permitan crear una web a partir de la cual podamos seguir aprendiendo.

los anteriores, desde los enfocados en el desarrollador a los enfocados en el diseador, desde los que buscan la velocidad a los que buscan la coherencia. El enfoque de Tornado Web ha sido proporcionar un sistema de plantillas que busca la velocidad sin forzar que la pgina generada sea correcta. Este enfoque es parecido al de Django y el sistema de plantillas de Mako. Vemoslo.
<html> <head> <title> {{ titulo }}</title> </head> <body> <h1>{{ escape(saludo) }}</h1> </body> </html>

Para que los cambios tengan lugar debemos parar nuestro servidor, pulsando Control-C, y volver a arrancarlo. Y, como no, volvamos a probar su rendimiento con el comando ab como hicimos en el apartado anterior. El resultado es:
.... Requests per second: U 2193.82 [#/sec] (mean) ....

El Sistema de Plantillas
Las plantillas son esenciales para la creacin de una pgina web potente. Existen muchos sistemas de plantillas, como vimos en artcu-

Este cdigo corresponde a una plantilla Tornado Web. Es cdigo html con variables que aparecen enmarcadas entre los smbolos {{ y }}. Empleamos una funcin de Tornado Web, escape(), para asegurarnos de que el contenido de la variable saludo no interfiera con el html de la pgina, para lo cual convierte en entities html cualquier carcter sospechoso. Este cdigo debemos guardarlo en un fichero llamado saludo.html, por ejemplo. Ya dijimos antes que son los handler los responsables de responder a peticiones HTTP, por lo que ser nuestro handler HolaHandler quien utilizar nuestra plantilla. Para ello slo tenemos que reemplazar la llamada a self.write(), con la que generbamos el texto

S, ha cado el rendimiento, pasando de unas 2800 peticiones por segundo a casi 2200. Y esto se debe a que estamos empleando plantillas en lugar de responder directamente con una cadena. Esta es la gran paradoja de los servidores web, da igual lo potentes que sean, la velocidad en realidad la determinan libreras externas y acciones que no tienen mucho que ver con el acto de servir pginas por HTTP. Sigamos profundizando en el sistema de plantillas.

Figura 2: Pgina principal de nuestro catalogo.

WWW.LINUX- MAGAZINE.ES

Nmero 54

45

DESARROLLO Python: Tornado

Figura 3: Pgina con los datos de un producto.

Un Catlogo de Papelera
Todo sistema de plantillas nos debe permitir hacer varias cosas. Debe permitir componer pginas web, debe permitir emplear algn mecanismo para mostrar una lista de objetos, debe ser posible decidir si un bloque de cdigo se muestra Vamos a ver todas esas caractersticas con los Listados 2, 3, 4 y 5. En el Listado 2 aparece el cdigo de una pgina web muy sencilla: muestra un catlogo de productos y nos permite ver la informacin de los mismos. Para determinar qu producto muestra ProductoHandler usamos una expresin regular en el patrn que pasamos a Application. Cada una de las expresiones regulares que aparezcan entre parntesis en el patrn se corresponder con uno de los parmetros que recibir el mtodo get(). De esta forma es muy sencillo crear urls bonitas (del estilo de /producto/2321). Para componer las pginas empleamos una pgina base, Listado 3, que no es ms que una pgina html que incorpora una serie de instrucciones {% block <nombre> $}, cada una de las cuales debe acabar en {% end %}. Estos bloques incluyen un texto que se mostrar en caso de que no sean sustituidos por otro contenido. As, podemos incorporar a nuestra pgina tantos bloques como queramos, y las subpginas podrn decidir cules de ellos sustituyen. Eso es precisamente lo que vemos en los Listados 4 y 5. En el primero de ellos, usamos

la orden {% extends <pagina> %} para indicar que vamos a heredar el html de base.html, y a continuacin reemplazamos el bloque contenido con nuestro cdigo fuente. Lo mismo hacemos en el Listado 5, slo que adems de contenido sustituimos el bloque titulo. Por ltimo, Tornado Web tambin incorpora un sistema denominado UI Modules que nos permite crear componentes reutilizables. Imaginemos que tenemos una tienda online y queremos poder mostrar los datos de la cesta de la compra siempre que sea necesario. Es tedioso y peligroso tener que volver a invocar el mismo cdigo una y otra vez en nuestros handlers para comprobar que el usuario est registrado o recuperar los productos de su cesta. En lugar de ello, podemos crear un componente. Vemoslo con un ejemplo muy sencillo: vamos a crear un mdulo que mostrar la fecha en cada pgina que lo incorpore, ver Listado 6 para el cdigo y el Listado 7 para el html. Tanto el Listado 4 como el Listado 5 incorporan este mdulo, y podemos ver cmo lo vinculamos en el Listado 2 al configurar la aplicacin. Este sistema es muy interesante, puesto que nos permite vincular css y javascript a nuestro componente de forma que sea realmente independiente. El resultado de todo esto lo podemos ver en la Figura 2 y en la Figura 3.

Listado 7: Fichero fecha.html


01 <div class=fecha>{{ fecha }}</div>

base para la creacin de casi cualquier cosa. Hay quien dice que Twisted es genrico, mientras que Tornado Web es especfico. Pero no nos engaemos, Twisted es mucho ms avanzado que Tornado Web, y en la crtica que hace Glyph (ver Recurso [4]) a Tornado Web, revela gran cantidad de errores en su diseo que pueden generar errores bastante complicados de solucionar. Twisted es un proyecto maduro y muy bien probado, por lo que Glyph se enfad un poco cuando Tornado Web apareci como alternativa a Twisted. Otra cosa es que las libreras de Twisted para la creacin de sitios web sean algo desastrosas y estn mal documentadas, Glyph entona ah el mea culpa, pero dice que quiz no estaran tan mal si un proyecto como Tornado Web hubiese considerado seriamente emplear Twisted. De hecho, al poco de Tornado Web apareci un proyecto para reemplazar su bucle de eventos por el de Twisted, [6].

Conclusin
Las empresas siempre buscan una ventaja competitiva, y crear un framework propio, independiente de cualquier software libre, fue la opcin que adopt FriendFeed [7]. Pero ahora que han liberado su cdigo, sera necesario que lo integrasen completamente en la comunidad Python, y desde luego un proyecto de la calidad de Twisted necesitara ese empujoncito para alcanzar el estatus que I merece.

Y Qu Pasa con Twisted.Web?


Como ha quedado patente, Tornado Web nos ofrece todas las herramientas necesarias para la creacin de un sitio web complejo, y eso que ni siquiera hemos rascado la superficie, puesto que tambin nos ofrece soporte para Ajax y Comet (que nos permiten la creacin de aplicaciones web asncronas, donde los eventos no requieren una recarga de la pgina). En cambio, Twisted es ms bien un framework tcnico, que puede ser usado como

RECURSOS
[1] Tornado : http://www.tornadoweb.org [2] Post presentando a Tornado: http:// bret.appspot.com/entry/ tornado-web-server [3] Man Epoll: http://www.kernel.org/doc/ man-pages/online/pages/man4/epoll. 4.html [4] Opinin de Glyph: http://glyph. twistedmatrix.com/2009/09/ what-i-wish-tornado-were.html [5] SQLAlchemy: http://www.sqlalchemy. org [6] Tornado on Twisted: http://dustin. github.com/2009/09/12/tornado.html [7] FriendFeed, los padres de la criatura: http://friendfeed.com/

Listado 6: Fichero componentes.py


01 import tornado.web 02 import datetime 03 04 class Fecha(tornado.web.UIModule): 05 def embedded_css(self): 06 return div.fecha { font-style: italic; } 07 08 def render(self): 09 return self.render_string( fecha.html, 10 fecha = datetime.date.today() )

46

Nmero 54

WWW.LINUX- MAGAZINE.ES

También podría gustarte