Le terme « comet » est employé à toutes les sauces aujourd’hui. C’est devenu un terme fourre-tout et ultra tendance lorsqu’on veut parler de web 2.0 ou 3.0. Lorsqu’on parle de comet, on parle également de reverse-ajax, cometd, long polling, slow polling, long-lived HTTP connections, server push…Une petite explication s’impose !

On va tâcher d’expliquer la différence entre server push et comet. Nous verrons que ce n’est pas tout à fait la même chose, bien qu’ils soient, aujourd’hui, très souvent associés l’un à l’autre.
Nous allons tout d’abord schématiser:
- le cycle de vie d’une requête HTTP standard
- le cycle de vie d’une requête HTTP type server push (avec une API bloquante)
- idem mais avec une API non bloquante
1. Le cycle de vie d’une requête HTTP standard
Ce schéma décrit le cycle de vie d’une requête http standard. La requête est envoyée, récupérée par le serveur (la traite dans un thread), répond immédiatement au client, ferme la connexion et libère le thread. On a donc 1 requête = 1 thread.
2. Le cycle de vie d’une requête type server push avec une API bloquante

Cycle de vie d'une requête type server push avec une API bloquante
On implémente le système de server push avec une API bloquante (le plus facile à mettre en place). Lorsque le serveur reçoit la requête, elle est prise en charge dans un thread. Au lieu de retourner la requête réponse, on ne retourne rien volontairement. C’est à dire qu’on gèle la connexion en attendant un événement coté serveur.
Par exemple, un client a une liste de messages non lus. S’il n’a aucun message, alors on attend:
messagesNonLus.wait();
Lorsque le serveur récupère un message d’un autre client pour le client en attente:
utilisateurEnAttente.messagesNonLus.add(new Message(« JDK Coding Club !»));
utilisateurEnAttente.messagesNonLus.notify ();
Le notify() a pour effet de réveiller le thread qui était verrouillé sur la liste. A ce moment, le thread récupère les messages non lus, et les envoie au client et se termine.
On est bien dans un schéma 1 requête = 1 thread.
3. Le cycle de vie d’une requête type server push avec une API non bloquante

Cycle de vie d'une requête type server push avec une API non bloquante
Avec l’API non bloquante, on s’approche du modèle d’architecture « Comet » (comet pattern).
En effet, lorsqu’un client envoie une requête, le serveur lance un thread pour la prendre en charge. Jusque là, on suit le même schéma que les deux précédents.
Mais, cette fois-ci on va dé-sérialiser la requête et la stocker (éventuellement l’associer à un client - utilisateur par exemple) pour pouvoir la récupérer ultérieurement. On peut libérer le thread. Ensuite, on ne fait rien (la requête est gelée) jusqu’à ce qu’un événement arrive et nécessite d’être transmis à un client ou plusieurs clients.
Dans notre cas de messagerie, lorsque le serveur reçoit un message pour un utilisateur en attente de ses messages non lus, il récupère tout d’abord la requête gelée « server push » du client en attente, il y insère le ou les messages non lus (on remplit le « payload » de la requête). On sérialise la requête, puis on envoie la requête au serveur. Et enfin, on ferme la connexion.
Définition Comet
Le terme Comet n’a pas de réel définition, pour preuve sur wikipedia personne n’arrive à se mettre d’accord. Il a été inventé par Alex Russell, un des créateurs du framework Cometd (dojo), dans son blog avec l’article Comet: Low Latency Data for the Browser.
Mais pour sûr, il désigne avant tout un modèle de patron web (j’insiste pour le web) permettant de transporter, via le protocole HTTP, des événements asynchrone du serveur vers le client en maintenant une latence très faible. Il s’implémente suivant deux points importants.
Premièrement, il faut absolument éviter le problème de blocage entre le client et le serveur (limitation à deux connexions). C’est pourquoi, au lieu d’utiliser plusieurs requêtes gelées pour un même client dans une application web, on n’instaure qu’un seul service qui ne fait que gérer les événements entre le serveur et les clients. C’est là qu’on utilise le principe du server push au travers des techniques de « long polling » (anciennement appelée « slow polling »).
Deuxièmement, le but est d’établir des connexions HTTP persistantes (« long-lived HTTP connections »). Même si d’un point de vue purement technique, ce n’est pas vraiment du « mode connecté », le comportement final obtenu est quand même semblable. Pour cela, il faut utiliser un serveur web/conteneur de Servlet qui autorise les connexions non bloquantes. Il y en a plusieurs, j’en cite trois des plus connus :
- Jetty avec Continuations
- Tomcat avec CometProcessor
- Grizly avec CometHandler
Pourquoi utiliser des API non bloquantes ?
On peut très bien faire du server push avec un simple serveur tomcat (API bloquante). Pour cela, il suffit de geler le thread de la servlet avec un « wait() » sur un objet, de répondre lorsque le serveur en a besoin en notify() ce dernier.
Le problème se situe au niveau de robustesse de l’application lors de la montée en charge.
2000 utilisateurs avec chacun leur requête server-push gelée par le serveur correspond également à 2000 threads. Le second problème, c’est qu’il y a un nombre de thread maximum (config server.xml) pour chaque Servlet. On pourrait, certes, le modifier, mais que ce passe-t-il si un petit malin envoie 2000 requêtes trafiquées d’un coup…Je crains qu’il finisse par faire tomber le serveur.
Alors qu’avec une API non bloquante, nous n’avons qu’une collection de 2000 requêtes. Là est toute la différence.
Reverse Ajax ?
Le terme a été lancé par les auteurs du Framework DWR (Direct Web Remoting). Concrètement, le Reverse-Ajax est l’ensemble des techniques plus ou moins proche de comet permettant de faire de la notification sur le web.
- Polling (scrutation)
- Comet / Slow polling / Long polling (ou encore l’utilisation des “long-lived HTTP connections”)
- PiggyBack
Ce dernier consiste à intégrer dans une requête de réponse une notification, de la sorte que la réponse et la notification sont envoyées en même temps.
Conclusion
Le server push permet d’envoyer des données à un client lorsque le serveur le décide (sans que le client ne le demande). C’est le principe de la notification pour le web.
Comet est un patron visant à bien implémenter le principe du server push. Et cela en partie du à l’arrivée des API non bloquantes.
En réalité, le server push est souvent associé au principe de comet, mais techniquement, ça n’a rien à voir.
Romain LAFOND


2 commentaires
Bien ces articles, j’apprends des trucs ! =)
instructif. merci