Yoan Blanc’s weblog

Another lost swiss guy

Messages powered web applications

Yoan BlancSun, 10 May 2009, , ,

The web is made of messages, e-mail is the first class citizen of them. Instant messaging protocols (like the beloved XMPP) and now Twitter and every twitter-like applications are collecting and sending back tons of messages. Let’s see how this concept can be applied and becoming very useful at a smaller scale too.

Before going further, Matt Biddulph (CTO of Dopplr) made a very interesting presentation explaining how Dopplr is using messages that transit between the different parts of the application. Take a look at it! Dopplr: It's made of messages - Matt Biddulph

How messages can help your web application to become better? Like every good manager do, by delegating. Instead of doing everything yourself, let other people doing that for you. The drawback is that you’ll have to wait on that person to do his job, the good ones are that you can quickly answering your customer (sending back a HTML page in our case).

I wrote a simple application called up! that is an image uploader. The cool thing about this image uploader is that, like Flickr for example, once the pictures are uploaded the application tells you that the thumbnails are currently processed and that you’ll very soon get them without telling anything before its done (which is rude, but common)

Let’s dive with the image upload.

Upload schema

When John uploads his picture, the file is saved into a temporary directory and a message of this kind is sent to a queue called resize.

("/tmp/foobar.jpg", "jpeg")

And respond directly with a HTML page containing a placeholder for the thumbnail.

<p id="preview">
 <span>foobar.jpg</span> sent.
</p>
<p id="loading"><em>
 Please wait for the preview
 to be generated.
</em></p>

Now, the client will try to obtain the expected thumbnails.

Message passing schema

On the client-side a JavaScript code will ping that expecte picture every 2 seconds as long as the server doesn’t find it and therefor answers with an error 404.

During that time, a consumer (a different process, independant from the web server) will get that message, resize the picture in 3 different sizes and put them at the right place. The arrow that goes back to the queue is a message acknowledgement saying that everything went find and that the message can be removed from the queue. The goal is to not lose any messages, if possible.

Thumbnails are generated schema

Once the thumbnails are available, the page displays the picture and the polling is stopped.

Different messaging mecanisms exist, some of them are very simple, like STOMP, but most of them are transcient only. It means no persistancy, if nobody listens; the messages are lost. Because shit happens, I prefer having some kind of persistency and acknowledgement that a message was well processed. Persistance means slowliness too. For that, this demo uses RabbitMQ and the AMQP protocol. The first one is powered by Erlang and both of them are open source. Installing RabbitMQ is as simple as (once downloaded and extracted): make run. Learn more about RabbitMQ reading: Rabbits and warrens.

As libraries, it uses both txamqp (tx stands for twisted matrix) and amqp-lib. I find amqp-lib handy for the client side, to just send a message and prefer twisted matrix for a server that has to live (if possible) for ever and without causing too many trouble. Using only amqp-lib is of course possible.

Resizing image is one use case, maybe not the best one. In another application, I’m also using a queue for sending e-mail notifications, or it could be IM notification (AMQP instead of XML-RPC in my twootr article for example), ... Separating them from the web server logic as the great advantage that you can tune both of them separately, instanciate more processes to handle image resizing the one you have have too much work without affecting anyone else. Small pieces of software collaborating together.

I’ve read once, that once you’ve gone in that path, you cannot go back. You’ve been warned. I think that big monolithics web apps aren’t agile enough those days where data are growing bigger and data are going faster to many people, mediums and third-parties.

Download it from bitbucket and feel free to hack it or to send me any questions.

Envoyer des messages est le cœur d’Internet. Ça a commencé par les courriels (e-mails), puis les messageries instantanées (dont le fameux XMPP) et à l’heure actuelle, Twitter et autres confrères brassent une quantitée impressionnante de petits messages devant être distribués à un grand nombre de destinataires de manière (quasi-)instantanée. Cet article illustre comment l’usage d’une architecture à base de messages peut être bénéfique à une application web.

Avant tout, je vous invite à prendre connaissance de la présentation donnée par Matt Biddulph (CTO de Dopplr) concernant l’architecture qui a été adoptée dans le cadre de ce projet. C’est tout simplement très instructif. Dopplr: It's made of messages - Matt Biddulph

Comme vous pouvez le voir dans la partie anglophone, qui est joliment illustrée d’ailleurs, le but a été de réaliser un système d’envoi d’images qui va déléguer le traitement des images à un tier. Le serveur web peut ainsi répondre directement informant que le fichier a été envoyé et que les miniatures seront très promptement disponible sans avoir à le faire lui-même.

Un message a été envoyé dans une queue de messages, et va être distribué à une petite application dont le but est juste de redimensionner l’image en (dans ce cas) 3 miniatures. En parallèle, un petit bout de JavaScript va tenter d’accèder aux fichiers devant être produits, à intervale régulier (ici 2 secs), jusqu’à ce que ça réussisse et qu’il soit possible d’afficher le contenu à l’utilisateur.

De prime abord, l’avantage de ce mic-mac n’est pas forcément clair, maintenant imaginez que ceci soit fait par le serveur web directement, qui a pour, presque unique fonction, de servir un maximum de monde le plus rapidement possible. Redimensionner une image implique d’ouvrir un fichier parfois volumineux pour en créer un autre un peu moins volumineux. Ça rime avec mémoire. Et si un serveur web qui sert 50 requêtes simultanément ouvre 50 fichiers JPEG de quelque Mo chacun, ça peut être coriace pour lui, et surtout pénible pour les autres utilisateurs qui aimeraient bien envoyer leurs images mais ne peuvent pas accèder au serveur car il est raz-la-gorge.

Déléguer signifie avoir les mains libres pour faire autre chose, signifie également que si ça ne suit pas de leur côté, il est envisageable d’allouer plus de ressources à cette tâche-là. Et bien sûr, découpler un problème en de multiples tâches réduit un gros problème en plusieurs plus petits problèmes. Dans ce cas-ci c’est tout simplement le bon vieux problème du producteur / consommateur.

Le code se compose d’un peu de Python, tout simplement WSGI, utilisant WebOb, AMQP-lib (pour le producteur) et txAMQP (pour le consommateur). AMQP est un protocole libre et qui possède notamment un client écrit en Erlang nommé RabbitMQ, libre lui aussi. L’avantage de ce dernier est qu’il est capable de gérer des listes persistantes avec confirmation de lecture. Ce qui manque souvent dans d’autres protocoles plus simples, comme STOMP. Trouvez-le et faites-en ce que vous voulez sur mon compte Bitbucket

L’usage d’AMQP n’est pas forcément facile à prendre en main, tout simplement car les possibilités offertes sont très vastes mais étonnamment efficaces. Il est, par exemple, très simple qu’un message soit dispatchés vers plusieurs consommateurs différents sans avoir à envoyer son message plusieurs fois. Donc de découpler les producteurs des consommateurs, mais c’est une autre histoire qui est très bien documentée dans cet article là : Rabbits and warrens.

About

meYoan Blanc is a web developer that lives in Switzerland (Jaquet-Droz 6, 2300 La Chaux-de-Fonds) and works as a freelance.

Get my vCard or contact me by phone (skype:yoan.blanc) or email ().

Misc

RSS, list.blogug.ch

This site reflects only my opinion and is not affiliated with anyone else.

copyright 2006-2009 — doSimple.ch