Top 6 des systèmes de file d'attente pour les développeurs backend
Vous êtes à la recherche d'un mécanisme de file d'attente, ou peut-être désirez-vous une alternative supérieure ? Vous êtes au bon endroit, car cet article vous fournira toutes les informations nécessaires !
Les systèmes de files d'attente sont un atout souvent sous-estimé dans le développement backend.
Sans vouloir rédiger une ode aux systèmes de files d'attente, je dirais qu'un développeur backend junior franchit un cap et devient un développeur backend de niveau intermédiaire lorsqu'il maîtrise l'intégration de ces files. Elles améliorent l'expérience utilisateur (nous verrons comment), réduisent la complexité et augmentent la robustesse d'un système.
Certes, pour les applications web très basiques avec un trafic quasi nul, ou encore pour les sites vitrines, les files d'attente peuvent sembler superflues (voire impossibles à installer si vous utilisez un hébergement mutualisé), mais les applications plus complexes bénéficient grandement de ces systèmes. Les applications de grande envergure, quant à elles, ne peuvent tout simplement pas se passer de la mise en file d'attente.
Avant de commencer, un avertissement : si vous êtes déjà familier avec les systèmes de files d'attente et que vous souhaitez simplement comparer les différentes options, les prochaines sections introductives pourraient vous ennuyer. 🙂 N'hésitez donc pas à passer directement à la suite. Ces premières sections sont destinées à ceux qui ont une idée floue de ce qu'est un système de file d'attente ou qui en ont simplement entendu parler.
Qu'est-ce qu'un système de file d'attente ?
Commençons par définir ce qu'est une file d'attente.
En informatique, une file d'attente est une structure de données qui simule les files d'attente du quotidien que nous connaissons tous. Imaginez-vous dans un bureau de poste : vous prenez votre place à la fin de la file, et c'est la personne en tête qui est servie la première. C'est le principe du "premier arrivé, premier servi" (FIFO). En informatique, il est possible de programmer des systèmes qui stockent les tâches dans une file d'attente, et les traitent dans l'ordre, selon le même principe.
Il est important de noter que la file d'attente ne traite pas les tâches elle-même. Elle sert uniquement de zone de stockage temporaire où les tâches attendent d'être récupérées par un processus. Si tout cela vous semble encore abstrait, pas d'inquiétude. C'est un concept abstrait, mais les exemples concrets de la section suivante vous éclaireront. 🙂
Pourquoi a-t-on besoin de systèmes de file d'attente ?
Pour faire simple, la nécessité de systèmes de file d'attente découle principalement du besoin de traitement en arrière-plan, d'exécution en parallèle, et de la capacité de récupération en cas de panne. Illustrons cela avec quelques exemples :
Traitement en arrière-plan
Imaginez une campagne de marketing e-commerce avec des délais serrés. Votre application est conçue pour envoyer un e-mail de confirmation juste avant que le client ne finalise son achat et n'accède à la page de remerciement. Si le serveur de messagerie est hors service, la page web sera bloquée, ce qui perturbera l'expérience utilisateur.
Imaginez le nombre de demandes d'assistance que vous recevriez ! Dans un tel cas, il est préférable de déléguer la tâche d'envoi de l'e-mail à une file d'attente, et d'afficher immédiatement la page de confirmation au client.
Exécution parallèle
De nombreux développeurs, en particulier ceux qui conçoivent des applications simples avec peu de trafic, utilisent des tâches cron pour les traitements en arrière-plan. Cette approche fonctionne bien tant que le volume de données à traiter reste modeste. Cependant, si ce volume devient trop important, la tâche cron peut être débordée. Par exemple, supposons que vous ayez une tâche cron qui génère des rapports d'analyse et les envoie par e-mail aux utilisateurs, et que votre système puisse traiter 100 rapports par minute.
Dès que votre application prend de l'ampleur et reçoit plus de 100 requêtes par minute en moyenne, elle accumulera du retard et ne parviendra pas à traiter toutes les tâches.
Un système de file d'attente permet d'éviter ce problème en mettant en place plusieurs processus ("workers") qui peuvent chacun prendre en charge un lot de 100 rapports, et travailler en parallèle pour traiter l'ensemble des rapports plus rapidement.
Récupération après un échec
En tant que développeurs web, nous avons tendance à ignorer la possibilité d'une panne. Nous partons souvent du principe que nos serveurs et les API que nous utilisons seront toujours disponibles. La réalité est différente : les pannes de réseau sont fréquentes, et même les API les plus fiables peuvent être indisponibles à cause de problèmes d'infrastructure (avant de dire "ça n'arrive qu'aux autres!", souvenez-vous de la panne massive d'Amazon S3). Reprenons l'exemple des rapports. Si la génération d'un rapport nécessite une connexion à l'API de paiement, et que cette connexion est interrompue pendant 2 minutes, qu'advient-il des 200 rapports qui ont échoué ?
Les systèmes de file d'attente ont cependant un coût non négligeable. La courbe d'apprentissage est assez abrupte lorsque l'on découvre ce domaine, la complexité de l'application et de son déploiement augmente, et le contrôle des tâches en file d'attente n'est jamais précis à 100%. Ceci dit, dans certaines situations, créer une application sans files d'attente est tout simplement impensable.
Ceci étant dit, passons en revue quelques options courantes pour les systèmes de mise en file d'attente backend d'aujourd'hui.
Redis
Redis est connu comme un magasin clé-valeur, qui permet de stocker, de mettre à jour et de récupérer des données sous forme de chaînes, sans tenir compte de leur structure. Bien que cela ait pu être vrai par le passé, Redis propose désormais des structures de données performantes et utiles comme les listes, les ensembles triés et même un système Pub-Sub, ce qui le rend très intéressant pour la mise en œuvre de files d'attente.
Les avantages de Redis sont :
- Une base de données entièrement en mémoire, pour des lectures/écritures ultra-rapides.
- Très performant : il peut facilement supporter plus de 100 000 opérations de lecture/écriture par seconde.
- Un système de persistance très flexible. Vous pouvez privilégier des performances maximales au risque de perdre des données en cas de panne, ou bien choisir un mode plus conservateur qui sacrifiera les performances au profit de la cohérence.
- Gestion native des clusters
Notez que Redis n'intègre pas d'abstractions de messagerie/mise en file d'attente/récupération. Vous devrez donc utiliser un package ou créer vous-même un système léger. Par exemple, Redis est le backend de file d'attente par défaut du framework PHP Laravel, où un ordonnanceur a été mis en œuvre par les auteurs du framework.
Apprendre Redis est simple.
RabbitMQ
Il existe quelques différences subtiles entre Redis et RabbitMQ. Éclaircissons-les tout de suite.
Tout d'abord, RabbitMQ a un rôle plus spécialisé et défini : il est conçu pour la messagerie. En d'autres termes, son objectif premier est de servir d'intermédiaire entre deux systèmes, ce qui n'est pas le cas de Redis, qui se comporte plutôt comme une base de données. En conséquence, RabbitMQ offre des fonctionnalités supplémentaires qui manquent à Redis : routage des messages, tentatives, répartition de la charge, etc.
En y réfléchissant bien, les files d'attente de tâches peuvent également être considérées comme un système de messagerie, où l'ordonnanceur, les travailleurs et les "soumis" du travail peuvent être vus comme des acteurs participant à la transmission de messages.
RabbitMQ présente les avantages suivants :
- De meilleures abstractions pour la transmission de messages, ce qui réduit le travail nécessaire au niveau de l'application si la transmission de messages est votre objectif.
- Plus résistant aux coupures de courant et aux pannes (que Redis, du moins par défaut).
- Gestion des clusters et de la fédération pour les déploiements distribués.
- Des outils utiles pour gérer et surveiller vos déploiements.
- Prise en charge de quasiment tous les langages de programmation courants.
- Déploiement avec l'outil de votre choix (Docker, Chef, Puppet, etc.).
Quand utiliser RabbitMQ ? Je dirais que c'est un excellent choix lorsque vous avez besoin d'une communication asynchrone par messages, mais que vous n'êtes pas prêt à vous attaquer à la complexité des autres options de mise en file d'attente de cette liste (voir ci-dessous).
ActiveMQ
Si vous évoluez dans un environnement d'entreprise (ou que vous développez une application hautement distribuée et à grande échelle) et que vous souhaitez éviter de réinventer la roue (et de faire des erreurs au passage), ActiveMQ vaut le coup d'œil.
Voici les points forts d'ActiveMQ :
- Il est implémenté en Java, ce qui assure une intégration parfaite avec Java (il suit la norme JMS).
- Plusieurs protocoles pris en charge : AMQP, MQTT, STOMP, OpenWire, etc.
- Gestion native de la sécurité, du routage, de l'expiration des messages, de l'analyse, etc.
- Prise en charge des modèles de messagerie distribués les plus courants, ce qui permet d'éviter des pertes de temps et des erreurs coûteuses.
Cela ne veut pas dire qu'ActiveMQ est uniquement disponible pour Java. Il dispose de clients pour Python, C/C++, Node, .Net et d'autres environnements. De plus, ActiveMQ est basé sur des normes complètement ouvertes, et créer vos propres clients légers devrait être simple.
Cela étant dit, notez qu'ActiveMQ n'est qu'un courtier, et n'inclut pas de backend. Vous devrez toujours utiliser l'un des backends pris en charge pour stocker les messages. Je l'ai inclus ici, car il n'est pas lié à un langage de programmation particulier (contrairement à d'autres solutions populaires comme Celery, Sidekiq, etc.)
Amazon MQ
Amazon MQ mérite d'être mentionné rapidement. Si vous pensez qu'ActiveMQ est la solution idéale, mais que vous ne souhaitez pas gérer vous-même la construction et la maintenance de l'infrastructure, Amazon MQ propose un service géré pour cela. Il prend en charge tous les protocoles d'ActiveMQ – il n'y a aucune différence de fonctionnalité – puisqu'il utilise ActiveMQ lui-même.
L'avantage est qu'il s'agit d'un service géré, vous n'avez donc pas à vous soucier de quoi que ce soit d'autre que de son utilisation. Cela a encore plus de sens pour les déploiements sur AWS, car vous pouvez profiter d'autres services et offres directement depuis votre déploiement (des transferts de données plus rapides, par exemple).
Amazon SQS
On ne peut pas s'attendre à ce qu'Amazon reste silencieux sur un élément d'infrastructure aussi essentiel, n'est-ce pas ? 🙂
Voici donc Amazon SQS, un service de file d'attente simple, entièrement hébergé (littéralement) par le géant AWS. Encore une fois, les différences subtiles sont importantes. Notez que SQS ne propose pas de concept de transmission de messages. Comme Redis, il s'agit d'un simple backend pour accepter et distribuer des tâches dans des files d'attente.
Alors, quand utiliser Amazon SQS ? Voici quelques raisons :
- Vous êtes un fan d'AWS et vous ne voulez rien utiliser d'autre (honnêtement, il y a beaucoup de gens dans ce cas, et je ne pense pas qu'il y ait de mal à ça).
- Vous avez besoin d'une solution hébergée, avec l'assurance que le taux d'échec est nul et qu'aucune tâche n'est perdue.
- Vous ne voulez pas avoir à créer et surveiller vous-même un cluster. Ou pire, vous ne voulez pas développer des outils de surveillance, alors que vous pourriez utiliser ce temps pour coder.
- Vous avez déjà investi dans la plateforme AWS, et rester dans cet écosystème est logique d'un point de vue business.
- Vous recherchez un système de mise en file d'attente simple et ciblé, sans les complications liées à la transmission de messages ou aux protocoles.
Globalement, Amazon SQS est un choix solide pour tous ceux qui souhaitent intégrer des files d'attente de tâches dans leur système sans avoir à se soucier de l'installation et de la surveillance.
Beanstalkd
Beanstalkd existe depuis longtemps et constitue un backend simple, rapide et éprouvé pour la mise en file d'attente des tâches. Plusieurs caractéristiques distinguent Beanstalkd de Redis :
- Il s'agit d'un système de mise en file d'attente et rien d'autre. Vous y déposez des tâches, qui sont ensuite récupérées par des processus. Si votre application a ne serait-ce qu'un petit besoin en matière de messagerie, vous devriez éviter Beanstalkd.
- Il n'y a pas de structures de données avancées, comme les ensembles ou les files d'attente prioritaires.
- Beanstalkd est une file d'attente FIFO (premier entré, premier sorti). Il n'y a aucun moyen d'ordonner les tâches par priorité.
- Il n'y a pas d'options de clustering.
Malgré tout, Beanstalkd reste un système de file d'attente simple et rapide pour des projets simples qui tournent sur un seul serveur. Pour beaucoup, il est plus rapide et stable que Redis. Donc, si vous rencontrez des problèmes avec Redis que vous ne parvenez pas à résoudre, et que vos besoins sont basiques, Beanstalkd vaut la peine d'être essayé.
Conclusion
Si vous avez lu jusqu'ici (ou si vous avez survolé le texte), il y a de fortes chances que les systèmes de file d'attente vous intéressent ou vous soient nécessaires. Si c'est le cas, la liste présentée dans cet article vous sera utile, sauf si vous recherchez un système de file d'attente spécifique à un langage ou un framework.
J'aimerais vous dire que la mise en file d'attente est une solution simple et fiable à 100 %, mais ce n'est pas le cas. Elle peut être complexe, et puisque tout se passe en arrière-plan et très rapidement, des erreurs peuvent passer inaperçues et devenir très coûteuses. Cependant, les files d'attente sont indispensables au-delà d'un certain point, et vous constaterez qu'elles constituent une arme puissante (peut-être même la plus puissante) de votre arsenal. Bonne chance ! 🙂