Hacer que distintos servicios se comuniquen entre ellos es todo un problema que Facebook ha tratado de solucionar con Thrift. POR JOS MARA RUZ
a informacin quiere ser libre es uno de los lemas hacker, pero habra que preguntarse cmo se mover una vez que lo sea. En un mundo como el actual, donde la informacin y su procesado pueden encontrarse distribuidos en decenas (o miles!) de servidores, es preciso contar con algn mecanismo que permita comunicar sistemas informticos de todo tipo sin tener que recurrir a tecnologas de bajo nivel. Este problema ha sido resuelto por muchos mediante el empleo del protocolo HTTP, pero cuando lo que buscamos es rendimiento, HTTP puede no ser una opcin. No es de extraar que dos de las empresas de referencia de Internet, Facebook y Google, se hayan enfrentado a este mismo problema y hayan creado, de forma totalmente independiente, dos tecnologas que buscan solucionarlo: Thrift [1] y Protocol Buffers [2]. Tanto Facebook como Google necesitaban una forma de poder comunicar sistemas informticos desarrollados en diferentes lenguajes de programacin para que pudiesen intercambiar datos entre ellos. Por ms que queramos a nuestro querido Python, cuando el rendimiento es una prioridad no es nuestra mejor opcin. Y puede ocurrir tambin lo contrario: por mucho que nos guste Java, en numerosas ocasiones la velocidad de desarrollo con Python no tiene rival! En este nmero echaremos un vistazo a la tecnologa Thrift de Facebook y vere-
mos cmo Python puede usarla para comunicarse con un sistema Java que est ganando gran popularidad: ElasticSearch.
Serializando
Al acto de transformar un formato interno de datos en algo que podamos transmitir o almacenar de forma externa se le suele denominar serializar. Existe una cantidad inimaginable de formatos que podemos usar para serializar datos, y Python viene de serie con varias opciones: XML JSON Pickle Sqlite Todos ellos cuentan con ventajas e inconvenientes. XML es uno de los formatos ms extendidos del mundo. Al ser un formato de texto es fcilmente manipulable, y es posible editarlo a mano. Su nivel de complejidad es seleccionable, podemos hacer que sea tan complejo y almacene tanta informacin como deseemos. JSON fue la respuesta de la Web a la complejidad de XML. Al igual que l, es un formato de texto, pero su estructura est cerrada. Es sorprendentemente simple y sencillo de manejar, lo que no ayuda demasiado en situaciones complejas. Pickle es en realidad un mecanismo propio de Python para la superlacin de objetos. Ningn otro lenguaje parece disponer de soporte para l, y cuenta con al menos
WWW.LINUX- MAGAZINE.ES
Nmero 73
47
Hola mundo
Thrift funciona como un compilador (Figura 2) que acepta una descripcin de los datos y servicios, la interfaz, que vamos a utilizar y a partir de la cual generar una librera en el lenguaje de destino que codificar y decodificar ese formato en el lenguaje de programacin que le indiquemos. Es ms sencillo verlo con un ejemplo. Digamos que queremos disponer de un servicio llamado hola que acepta una cadena de texto y devuelve otra cadena de texto. Lo primero que necesitaremos es crear un fichero de descripcin en el formato de Thrift como el que aparece en el Listado 1. Una vez tengamos el fichero listo, podemos generar el cdigo Python con el siguiente comando:
shell$ thrift -gen pyU hola.thrift
ponder a la interfaz declarada en el fichero hola.thrift, mientras que en Listado 3 se encuentra el cdigo que usar este servicio. Para verlos en funcionamiento tendremos que arrancar primero el servidor en un terminal:
shell$ python servidor.py Arrancando el servidor...
shell$ thrift Usage: thrift [options] file Options: -version Print the ?. ....
Necesitamos un componente ms para poder hacer uso de Thrift: la librera python thrift. Instalarla es mucho ms sencillo:
shell$ pip install thrift
El comando generar un directorio llamado gen-py que contendr el mdulo que vamos a usar. Debemos copiar el mdulo hola al directorio en el que vayamos a ejecutar tanto el script del Listado 2 como el del Listado 3. El cdigo del Listado 2 genera un servidor de red que res-
Ha funcionado! Thrift nos permite arrancar un servidor de red con el servicio que hemos definido. La librera se encarga de prcticamente todo, lo que nos permite concentrarnos en crear el cdigo fuente de nuestro servicio. Pero es Thrift rpido? Hagamos una prueba. Con el servidor an arrancado, vamos a mandar
48
Nmero 73
WWW.LINUX- MAGAZINE.ES
No est nada mal, siendo Python, y sin usar ninguna optimizacin. Podemos parar el servidor pulsando la combinacin de teclas Control+C.
debe trabajar sobre algn protocolo de comunicaciones, ofreciendo varias posibilidades dependiendo del lenguaje de programacin que usemos. En Python es posible usar un socket, el protocolo http o Twisted. Por simplicidad vamos a usar un socket, que es el protocolo de ms bajo nivel, mediante la clase TSocket. Sobre el protocolo de comunicaciones debemos montar un servidor, TServer, que atienda los mensajes que lleguen y se los pase al procesador. Como puedes ver, los nombres son bastante descriptivos. Thrift nos obliga an a hacer algunas elecciones. Debemos indicar al servidor qu clase de protocolo vamos a usar en nuestro caso TBinaryProtocol y cmo queremos que se comporte el servidor, usando un bfer con TBufferedTransport. Thrift es configurable y nos ofrece diferentes opciones para casi todo. Podramos haber seleccionado un protocolo basado en JSON mediante TJSONProtocol, por ejemplo. Ya slo nos falta arrancar el servidor, instanciando por ejemplo TSimpleServer y llamando al mtodo server() que se bloquear mientras no lleguen mensajes.
ElasticSearch
Como ejemplo del uso de Thrift vamos a crear un pequeo programa Python que emplee esta tecnologa para interactuar con el motor de bsqueda de moda: ElasticSearch [3]. ElasticSearch est revolucionando el mundo de los motores de bsqueda. Ofreciendo el rendimiento de Solr/ Lucene, pero aadiendo la capacidad de trabajar de forma distribuida, reparte el ndice de bsqueda entre varias mquinas de forma automtica. Est programado en Java y ofrece varios protocolos de trabajo, siendo posible comunicarse con el servidor ElasticSearch mediante Rest sobre http o Thrift (Figura 3). Para instalar ElasticSearch slo tenemos que descargarlo desde la direccin del Recurso 3 :
shell$ wget -c U https://github.com/downloads/U elasticsearch/elasticsearch/U elasticsearch-0.16.2.tar.gz shell$ tar zxpf U elasticsearch-0.16.2.tar.gz shell$ cd elasticsearch-0.16.2 shell$ cd bin shell$ ./plugin -install U transport-thrift shell$ ./elasticsearch -f
Listo! Ya tenemos funcionando un motor de bsqueda con ndice distribuido y que se comunica usando Thrift. Es normal que ElasticSearch se est ganando el corazn de muchos desarrolladores. Debemos generar el mdulo de la interfaz de Thrift para Python. Para ello debemos descargar el fichero elasticsearch.thrift de la direccin que aparece en el Recurso 4. Y compilarlo:
shell$ thirft --gen U py elasticsearch.thrift
Cuando tengamos el directorio gen-py, extraemos de su interior el mdulo elasticsearch y lo ubicamos en el mismo directo-
WWW.LINUX- MAGAZINE.ES
Nmero 73
49
rio en el que pongamos el script del Listado 5. Cuando lo ejecutemos, ste ser el resultado:
shell$ time python busqueda.py [{u_score: 0.38431653, U u_type: uarticulo, U u_id: u1, u_source: {utitulo: U uThrift, Python y U ElasticSearch}, u_index: ulinuxmagazine}] real 0m0.353s user 0m0.040s sys 0m0.016s
Hemos creado un ndice, aadido un modelo de documento, insertado un documento y realizado 100 bsquedas en 300 milisegundos. ElasticSearch trabaja usando una API Rest que acepta comandos codificados en URIs (rutas) mediante los mtodos tpicos de HTTP. Tanto los datos enviados como los recibidos se codifican en JSON, que podemos codificar y decodificar empleando la librera json de Python. El esquema de trabajo es parecido al que hemos visto con anterioridad. Creamos una conexin usando TSocket, especificamos el tipo de transporte y el protocolo (en este caso una variante del binario) y generamos un cliente. La clase RestRequest ha sido generada por Thrift y tiene cuatro parmetros: Mtodo (POST, GET, PUT) URI (<indice>/<modelo>/<id>)
Cabeceras (Headers) Cuerpo del mensaje (Body) Algunos mtodos exigen el uso del body (por ejemplo los que requieren el mtodo POST), mientras que otros slo requieren el URI (GET) Y por qu usamos nmeros para el tipo de mtodo usado? Si echamos un vistazo al fichero elasticsearch.thrift veremos que ah se declaran los nmeros que usaremos para los mtodos. En nuestro ejemplo podemos ver diferentes mtodos en uso. Crear un ndice exige un POST, aadir un modelo, un PUT y hacer una consulta, un GET. Cada llamada de ejecucin de un request devuelve un objeto RestResponse con un campo body, en el que encontraremos el resultado codificado en JSON.
Conclusin
Thrift puede parecer algo complejo ahora que todos nos hemos acostumbrado a emplear HTTP como protocolo para las peticiones remotas. Pero existen muchas situaciones en las que necesitaremos utilizar un protocolo que consuma menos ancho de banda y ofrezca ms rendimiento. Tanto Facebook como Google han tenido que desarrollar su propia tecnologa para solventar este problema, y ambos han tenido la gentileza de liberarla como software libre. Y por si fuese poco, ambos sistemas generan cdigo Python, todo un regalo para nuestra comunidad. I
Figura 3: Funcionamiento de ElasticSearch.
RECURSOS
[1] Tecnologas Thrift de http://thrift.apache.org/ Facebook: [2] Tecnologa Protocol Buffers de Google: http://code.google.com/p/ protobuf/ [3] Motor de bsqueda ElasticSearch: http://www.elasticsearch.org/ [4] Fichero thrift para ElasticSearch: https://github.com/elasticsearch/ elasticsearch/blob/master/plugins/ transport/thrift/elasticsearch.thrift
50
Nmero 73
WWW.LINUX- MAGAZINE.ES