L'événementiel c'est écologique

le 30 décembre 2016, par Bruno Thomas

Pour faire suite à une mini série sur l’écoconception, je voulais partager un remaniement récent de transformation d’un polling web en push serveur (avec une websocket), et les conséquences en terme d’utilisation de bande passante.

Dans le projet sur lequel je travaille actuellement, nous intégrons le mail dans un site web. Nous montrons par exemple à l’utilisateur s’il a reçu de nouveaux emails. Le plus simple, au départ a été de faire du polling (requêtes régulières vers le serveur) avec un setInterval :

setInterval(function () {
  $.get('new_mails', function(data) {
    update_ui(data);
  })
}, mail_poll_period_second);

Côté serveur, dès qu’un utilisateur se connecte, un client IMAP est créé et va aussi faire du polling sur la boite de réception. Ca fonctionne, mais il y a au moins deux problèmes :

  • si un utilisateur est connecté toute la journée, et qu’il ne reçoit aucun message, l’application est sollicitée, le réseau également, pour rien
  • l’expérience utilisateur est dégradée par le temps de polling : comme nous avons positionné ce temps à 30 secondes, au pire il devra attendre une minute pour être notifié d’un nouveau message. Dans l’absolu c’est pas beaucoup, mais nous nous sommes habitués à une certaine immédiateté. Ce délais peut par exemple nuire à l’image qu’on se fait d’une application

Passer en événementiel

Pour en apprendre un peu plus sur le sujet, nous avons fait un spike afin de valider l’intérêt d’une solution événementielle.

  • côté serveur, nous utilisons l’instruction IDLE de l’IMAP4 et nous programmons le batch de récupération de mail en python asynchrone pour que le serveur se mette au repos lorsque rien ne se passe sur la connexion IMAP. Pour la partie web, nous utilisons un worker gaiohttp de green unicorn en passant par aiohttp. En effet cela permet d’utiliser une application pyramid en mode asynchrone. Comme le reste du projet utilise pyramid pour le web, nous contrôlons l’authentification par le même token, c’est pratique, et on ne change pas de techno. Enfin, ce sont des projets opensource reconnus qui se basent sur la couche asynchrone native de python (asyncio) contrairement à twisted ou tornado ;
  • pour le front web, nous configurons nginx comme un proxy websocket qui jouera un role de load balancing et de reverse proxy
  • côté client, nous mettons en place une websocket
var websocket = new WebSocket('wss://monHost:monPort/email/userId');
websocket.onmessage = function (evt) {
    update_ui(evt.data);
}

Pour le WEB

Nous voulons alors mesurer l’écart d’utilisation du réseau. Comme la websocket est un mode connecté, le navigateur ne nous indique pas tout, notamment les trames TCP/IP de keep alive. Nous faisons un dump TCP avec wireshark.

Avec le polling :

Wireshark polling

On voit notre requête GET vers l’url new_mails qui utilise 683 + 215 octets et puis l’aquitement TCP avec 66 octets.

Avec websocket :

Wireshark websocket

On voit à présent les TCP Keep-Alive toutes les 45 secondes, ce qui fait 2 fois 66 octets (avec le ACK).

En résumé :

Polling Websocket
requête/réponse HTTP + ACK TCP TCP Keep-Alive
964 octets 132 octets
toutes les 30s toutes les 45s

Nous divisions par 7,3 le nombre d’informations échangées à chaque requête, et nous faisons trois requêtes HTTP pour deux Keep-Alive/ACK. Donc nous échangeons 10 fois moins de données en ayant une meilleure réactivité à la réception d’un mail.

Pour l’IMAP

De la même manière, les échanges IMAP sont diminués. Avec le polling, on fait un FETCH toutes les 30 secondes :

* 160 FETCH (UID 258 FLAGS (\Seen NonJunk POUET))\r\n
463 OK Fetch completed.\r\n
142 bytes on the wire (1136 bits)

Soit 142 octets avec un ACK de 66 octets : 208 octets. En mode événementiel, on utilise l’instruction IDLE, le serveur envoie un ‘OK Still here’ (83 octets) toutes les 2 minutes (pour Dovecot), avec un ACK TCP, soit 149 octets au total.

Polling fetch IDLE
requête/réponse FETCH Still Here serveur
208 octets 149 octets
toutes les 30s toutes les 2mn

Ce qui fait presque 5 fois moins de données là encore en améliorant la réactivité du service.

En résumé

Synthèse

Nous avons transformé notre mail_fetcher multithreadé avec un client IMAP actif par thread en mail_fetcher monothreadé événementiel, ce qui le rend moins gourmand en mémoire et CPU.

Nous obtenons :

  • une meilleure expérience utilisateur avec un temps de réponse diminué pour la réception d’un email
  • une librairie IMAP asynchrone
  • une division par 9 de la sollicitation du réseau (client <-> serveur HTTP + serveur HTTP <-> serveur IMAP)
  • une diminution de l’utilisation des serveurs
  • un apprentissage sur la programmation asynchrone en python

Dans cet environnement contraint nous avons rendu notre tâche simple en tâche difficile : notifier l’utilisateur de l’arrivée d’un nouveau message par scrutation en push serveur.

Pour bien faire, il reste à travailler la fiabilité et le déploiement :

  • un fallback en longtime polling pour les clients qui ne supportent pas les websockets
  • la détection côté client d’un lien cassé et le rétablissement automatique d’une nouvelle websocket
  • le dimentionnement du nombre de clients websocket que peut servir une machine. Ce fil stackoverflow peut aider.

Nous calculerons également l’économie en eau et en émission de CO2 en fonction du nombre d’utilisateurs, en se basant sur le modèle d’Ecoindex. Mais cela fera l’objet d’un autre article :)

Bonne année à vous !!

La facilitation graphique dans la revue et le planning du sprint

le 13 décembre 2016, par David Boissier

L’équipe dans laquelle je suis a adopté le cadre SCRUM pour son mode de fonctionnement. Les rituels classiques tels que la réunion du matin et l’indéboulonnable trio revue/rétrospective/planning est appliqué scrupuleusement.

Une migration vers ES6 et un pas de plus en écoconception

le 6 décembre 2016, par Bruno Thomas

Actuellement je travaille sur un site web en mode SaaS pour travailleurs indépendants et professions libérales. Comme le javascript n’était pas ma tasse de thé, j’avais négligé cet aspect, en accumulant le minimum de code (backbone/semantic-ui) dans de petits fichiers qui commençaient à grossir. Conscient de cette dette technique qui s’y accumulait, il y a une dixaine de jours je suis allé aux Javascript Les 10 Doigts Dedans (ou JSLDD pour les intimes) afin de rencontrer des férus du JS qui pourraient me faire aimer un peu mieux le JS et prendre soin de cet aspect incontournable du site.

Utiliser docker-compose avec le réseau docker

le 1 octobre 2016, par Bruno Thomas

Depuis la version 1.6 de docker-compose et la version 1.10 de docker, une gestion nouvelle du réseau dans les conteneurs docker a été implémentée. Quand vous avez des dépendances entre plusieurs conteneurs, plus besoin de faire des liens (links) entre eux. Pour les environnements de dévelopement c’est très pratique, notamment pour le problème des liens bidirectionnels.

Installer une chaîne SSL avec dovecot

le 22 juillet 2016, par Bruno Thomas

Nous avons entamé avec quelques amis développeurs notre cure de dégooglelisation il y a quelques années. Pour le mail, nous avons choisi, aussi pour notre apprentissage, de monter notre serveur postfix/dovecot. Pour ceux que ça intéresse, mais qui ne veulent pas mettre les mains dans le cambouis, il y a des infos chez Framasoft.

Une équipe agile, c'est comme l'équipe du Dr House

le 18 avril 2016, par Jean-Philippe Caruana

L’autre soir, je regardais un épisode de Dr House (oui, ça arrive) et j’ai été frappé par la similitude entre le fonctionnement de son équipe et celui d’une équipe agile.

Le A3 comme outil de communication avec le management

le 12 avril 2016, par Bruno Thomas

Il y a peu encore, je travaillais pour un groupe de télécom qui commercialise une messagerie instantanée d’entreprise permettant aux internautes de communiquer avec le service client depuis un site web. Il comprend une distribution des chats dans des files d’attentes, des outils d’aide pour les conseillers et des outils de supervision/administration.

Astuce - lancer un conteneur docker comme un service système

le 8 octobre 2015, par Jean-Philippe Caruana

Je ne vais pas ici vous faire une introduction à docker, ce n’est pas l’objet de ce post.

MongoDb le cluster qui bagote, la suite

le 23 septembre 2015, par Bruno Thomas

Suite de notre épisode précédent sur les bagots mongo, nous reprenons où nous nous étions arrêtés : nous avons un test d’acceptance instable et nous avons acquis la certitude que le cluster mongo en est la cause. Soit il est mal configuré soit buggué.