Comment réduire le temps d'exécution de votre application ?

David - 25/06/2015

À une période où l’information est accessible aux quatre coins de rue via la 3G et son accès accéléré par la fibre optique, nous acceptons de moins en moins l’attente due à une vitesse de chargement lente lors de la consultation d’applications ou de sites internet. Illustrons ce phénomène d’exécution de traitements lourds par le biais d’un projet mené chez Escale il y a quelques mois. Nous verrons ensuite la solution apportée par Escale pour réduire le temps de chargement.

rabbitMQ

Chez Escale, nous avons récemment eu l'occasion de travailler sur un projet original, pour le compte de RCA, éditeur de logiciels pour experts comptables. Nos partenaires et nous avions pour objectif de développer une plate-forme de génération de cartes de vœux vidéo (en motion design) personnalisables. Les experts comptables clients de RCA devaient avoir accès à une interface leur permettant de personnaliser leur carte, dans le but de l'envoyer à leurs propres clients par la suite.

L'interface en question a été réalisée sous la forme d'une petite application web, quasiment une « single page app ». Le créateur de la carte de voeux a la possibilité de personnaliser différents paramètres : nom du cabinet, message, environnement graphique, etc. Une fois ceux-ci saisis, l’interface va envoyer une requête HTTP à un serveur web. Sa fonction sera de créer une vidéo unique correspondant aux souhaits du client, et de la mettre à disposition via Youtube.

Le processus comporte ainsi 3 étapes :

Il a donc fallu imaginer une architecture logicielle qui soit capable, pour chaque création de vidéo, de mener à bien et de manière efficace ces trois étapes. On recherchait une solution qui offre les qualités suivantes :

Le but de cet article est de décrire les deux catégories de solutions que nous avons envisagées, et, bien sûr, de les argumenter.

UNE APPLICATION MONOLITHIQUE

La première solution, et la plus "naïve", est d’implémenter une application web (côté serveur) qui prenne en charge toutes les étapes du processus. À chaque fois qu'un utilisateur valide le formulaire de personnalisation, cette application recevrait la demande de création de vidéo sous forme d'une requête HTTP, et se chargerait de procéder aux trois étapes du processus vu précédemment, avant de renvoyer une réponse HTTP à l'utilisateur. Ce type d'application est souvent appelé "application monolithique", car l'ensemble des fonctionnalités du système sont gérées par un seul et même logiciel.

L'architecture de cette solution est relativement simple, mais elle comporte certains défauts. Tout d'abord, l'expérience utilisateur risque d'être relativement mauvaise : une fois que l'utilisateur a validé le formulaire de personnalisation, il va devoir attendre la fin du processus de création de sa carte avant que l'interface puisse lui donner un quelconque retour. Étant donné que l'étape de création de la vidéo est relativement longue (de l'ordre de plusieurs dizaines de secondes), le navigateur web de l'utilisateur risque de considérer que la requête s'est perdue (timeout) avant que le serveur puisse renvoyer une réponse. Il serait possible de résoudre ce problème, en utilisant le protocole WebSocket notamment, mais cela complexifierait (probablement trop) l'application.

Autre problème : si nous souhaitons déployer plus de serveurs pour pouvoir créer plus de cartes de vœux simultanément, chacun des serveur exécutera l'ensemble de notre application monolithique et nous aurons besoin d'un composant dont la fonction sera de distribuer les requêtes entrantes entre les différents serveurs, en amont de ceux-ci.

On pourrait se dire qu'il suffit d'utiliser un serveur plus puissant (scalabilité verticale), mais cette approche peut rapidement devenir très coûteuse ou tout simplement physiquement limitée. Cette solution ne convient donc pas, et n'offre pas les qualités que nous recherchons. Il est plus intéressant d'envisager de faire travailler plusieurs serveurs ensemble (scalabilité horizontale). Il devient théoriquement possible de mobiliser ou de démobiliser des serveurs en fonction de la charge, ce qui est financièrement intéressant.

service monolithique

LES MICRO-SERVICES AVEC RABBITMQ

La seconde solution, fondamentalement différente, met en œuvre le concept des micro-services. Un des avantages de cette solution c’est qu'elle facilite grandement la scalabilité horizontale. Le concept est plutôt simple : on va séparer notre système en plusieurs logiciels indépendants, qui communiqueront entre eux pour assurer les fonctionnalités que l'on souhaite. On appelle "micro-services" ces petits logiciels.

Dans notre cas, nous avons deux services. Le 1er est celui qui réceptionne la requête de création de carte, via HTTP. Le 2ème va, pour chaque demande de création de carte, réaliser le processus en trois étape vu précédemment. Comme la tâche du 1er service n'est pas très difficile, nous n'aurons qu'une seule instance de ce service. Par contre, le 2ème service aura plusieurs instances qui fonctionneront en parallèle sur plusieurs serveurs différents, permettant ainsi de générer plusieurs cartes simultanément.

Cependant, l’architecture en micro-services apporte quelques complications : les services doivent communiquer entre eux. Pour assurer la communication entre nos deux services, nous avons choisi de mettre en place RabbitMQ. Pour faire simple, RabbitMQ est un logiciel dont le but est de gérer des files d'attente de messages. Nos applications peuvent se connecter à RabbitMQ pour placer des messages dans la file d'attente. RabbitMQ pourra rapidement accuser réception des messages, et se chargera de les stocker correctement. D'autres applications pourront également se connecter à RabbitMQ, mais dans le but cette fois-ci de récupérer d'éventuels messages dans la file d'attente. RabbitMQ peut donc être vu comme une sorte de boîte aux lettres, qui stocke les lettres en mode FIFO (First In, First Out : premier arrivé, premier sorti).

Dans notre système, le 1er service va, lorsqu'il réceptionne une demande de création de carte, la vérifier, la stocker dans une base de données (pour en garder une trace), et la placer à la fin d'une file d'attente de RabbitMQ. Il peut ensuite envoyer une réponse HTTP à l'utilisateur, en lui disant que sa demande était valide et a bien été prise en compte. Chaque instance du 2ème service, va prendre une nouvelle demande dans la file d'attente de RabbitMQ, la traiter, et recommencer !

Comme ce sont les instances du 2ème service qui vont d'elles-mêmes chercher (et non les recevoir) des demandes à traiter, qu'il y ait une seule instance ou plusieurs dizaines importe peu ! On résout donc à la fois le problème de l'expérience utilisateur et celui de la scalabilité !

Un autre avantage qu'on peut attribuer aux micro-services est qu'ils aident à rendre les systèmes plus robustes face aux pannes et face au temps. En effet, si un service plante ou est séparé du système à cause d'un problème réseau, il ne met pas forcément en péril l'intégralité du système. Si les communications entre services sont asynchrones (comme c'est le cas avec RabbitMQ), le système retrouvera un fonctionnement normal et pourra rattraper son retard quand les problèmes seront résolus. Quant à la robustesse face au temps, on parle bien sûr d'une maintenabilité accrue du système : on peut facilement remplacer un service par une nouvelle implémentation, tant que celle-ci communique avec les autres services de manière identique à l'ancien service. On peut même raisonner sur le système en faisant une analogie : les services seraient des opérateurs qui travaillent sur une ligne de production, et les communications entre eux seraient des discussions, des ordres de fabrication papier, ou même des pièces/assemblages !

rabbitMQ microservices scalabilité horizontale

Construire ce projet en utilisant l'approche micro-services nous a permis de tenir la charge lors du lancement du service. Plus de 700 cartes de vœux ont été générées en 2 semaines, et tout ça en offrant une expérience fluide et stable pour les utilisateurs.

Nous saluons nos partenaires Doze Studio et François-Guillaume Ribreau avec qui nous avons partagé cette aventure, qui nous a fourni une nouvelle occasion de montrer que nous n'avons pas peur de mettre en œuvre des solutions techniques non triviales, lorsque cela sert l'expérience utilisateur et la stabilité/maintenabilité du produit.


Et si on parlait de vous ?

Vous avez un projet de site web ? Une problématique technique à nous soumettre ?
Dites-nous en plus : nous sommes impatients de découvrir votre projet !

escale © 2017 | Startup Palace - 18 rue Scribe - 44000 Nantes France | Proudly built on GestionAIRMentions Légales