
Les technologies des systèmes distribués regroupent les protocoles, logiciels, systèmes de stockage et outils d'exploitation qui permettent à des ordinateurs distincts de communiquer et de coordonner leur travail. Elles comprennent les appels de procédure à distance, les courtiers de messages, la découverte de services, les bases de données, les services de coordination et les outils d'observabilité.
Pour les choisir, il faut comprendre le problème que chacune résout. Une application peut avoir besoin d'une file de tâches sans avoir besoin d'un orchestrateur de conteneurs. Une base répliquée peut assurer sa coordination en interne, sans que l'application implémente un algorithme de consensus. Ce guide explique ces choix et les défaillances qui restent à prendre en charge.
Une application distribuée comprend des composants qui échangent des messages sur un réseau. Ils peuvent relever d'une seule organisation ou de plusieurs, et fonctionner sur un site ou sur plusieurs. La distribution décrit la répartition du travail et de l'état ; elle ne détermine pas qui contrôle le système. Notre guide des systèmes distribués et décentralisés explique cette distinction.
Les principales familles de technologies répondent à des besoins différents :
Aucune combinaison de produits n'est obligatoire. Retenez l'ensemble le plus simple qui satisfait les besoins de capacité, de reprise, de données et d'exploitation. Ajouter des machines peut augmenter la capacité ou offrir d'autres chemins d'exécution, à condition que l'application et ses dépendances puissent les utiliser.
Une technologie est un outil que l'on adopte, par exemple une bibliothèque RPC, une base de données ou un courtier de messages. Une technique décrit un comportement : la réplication copie l'état, le partitionnement le répartit, et l'idempotence permet à une exécution répétée de produire le même effet attendu qu'une seule exécution.
Un produit peut mettre en œuvre plusieurs techniques. Une base peut partitionner les enregistrements, répliquer chaque partition et utiliser un consensus pour convenir des mises à jour. Inversement, une stratégie de cache peut s'appuyer sur une bibliothèque intégrée au processus ou sur un service distinct. Le choix dépend de la façon dont l'application lit et modifie les informations.
Documentez la garantie recherchée. « Utiliser une file » ne précise pas si une tâche peut être perdue, livrée deux fois ou traitée dans le désordre. « Réessayer les requêtes échouées » ne dit pas si un dépassement de délai signifie que la première tentative a réellement échoué.
Les protocoles de transport déplacent les données entre des points de terminaison. TCP fournit un flux d'octets fiable et ordonné tant que la connexion reste utilisable. UDP envoie des datagrammes sans assurer lui-même ces garanties de livraison et d'ordre. QUIC construit un transport sécurisé au-dessus d'UDP, avec notamment des flux fiables ; HTTP/3 utilise QUIC.
Ces couches ne sont pas des solutions concurrentes interchangeables. HTTP définit un comportement applicatif, tandis que TCP et QUIC assurent le transport. UDP n'est pas non plus automatiquement le choix le plus rapide pour une application : la fiabilité, le contrôle de congestion et la reprise dont elle a besoin doivent toujours être assurés quelque part.
Commencez par les protocoles pris en charge, puis mesurez des charges utiles, comportements de connexion et conditions réseau représentatifs. Un échange réussi au niveau du transport ne prouve pas que l'application distante a validé une mise à jour en base de données.
Une API précise comment des composants demandent une opération ou échangent des informations. Une API HTTP peut exposer des ressources ou des opérations ; une bibliothèque RPC présente au code client des méthodes de service distantes. Dans les deux cas, la frontière réseau demeure.
gRPC, par exemple, définit des services et des méthodes et utilise couramment Protocol Buffers pour décrire les messages. Il prend en charge les échanges requête-réponse individuels ainsi que plusieurs formes de diffusion en continu. Les bibliothèques clientes gèrent une grande partie de la communication, tandis que l'application reste responsable du sens de l'opération.
Un appel distant peut se terminer sur le serveur alors que le client a cessé d'attendre. Une nouvelle tentative peut donc répéter un effet. Pour un paiement ou une commande, utilisez un identifiant de requête et un enregistrement durable du résultat, avec une gestion de la concurrence qui empêche deux tentatives d'appliquer l'effet deux fois. La présence d'une clé ne suffit pas à assurer ce comportement.
Fixez une échéance réaliste et transmettez le temps restant aux appels dépendants. La documentation gRPC sur les délais distingue également l'annulation d'un appel de l'arrêt du travail lancé par une application. Une annulation ne défait pas les changements déjà validés.
JSON, Protocol Buffers, Avro et MessagePack sont des exemples de formats utilisés entre composants. Évaluez la taille des messages, les langages pris en charge, les besoins de débogage, les règles de schéma et la compatibilité entre versions déployées. L'encodage binaire ne rend pas à lui seul une API plus rapide ou plus sûre.
Le guide de Protocol Buffers indique quels changements sont compatibles ou incompatibles avec son format binaire. Le sens applicatif exige une attention distincte : un champ peut rester lisible tout en changeant de signification métier. Testez les anciens clients avec les nouveaux services et les nouveaux clients avec les anciens services avant un déploiement.
Une file peut conserver une tâche jusqu'à ce qu'un consommateur soit prêt. La publication-abonnement permet à plusieurs consommateurs intéressés de recevoir des messages. Un journal d'événements conservé permet aussi de relire des événements antérieurs dans les limites de la politique de rétention. Ces modèles conviennent aux tâches de fond, à l'intégration et aux traitements dont toutes les étapes n'ont pas besoin de se terminer avant la réponse au client.
Apache Kafka organise les événements en topics et en partitions. L'ordre est défini à l'intérieur d'une partition : la clé de partitionnement détermine donc quels événements associés partagent cette garantie d'ordre. La rétention et la position des consommateurs permettent la relecture, mais l'application doit rester correcte lorsque d'anciens événements sont traités à nouveau.
Distinguez l'acceptation par le courtier de l'achèvement par le consommateur. La documentation des acquittements de RabbitMQ explique pourquoi les confirmations aux producteurs et les acquittements des consommateurs couvrent des étapes différentes. Aucun de ces mécanismes ne promet à lui seul qu'une opération métier en aval s'est produite une seule fois.
Avant d'adopter une messagerie, définissez le traitement des doublons, les besoins d'ordre, les nouvelles tentatives, la rétention et le sort des messages qui échouent de façon répétée. Limitez l'accumulation des tâches et surveillez le retard des consommateurs. Une file absorbe un écart temporaire entre les débits ; elle ne permet pas à un consommateur durablement sous-dimensionné de suivre la charge.
La découverte de services associe un nom logique à des adresses lorsque les instances démarrent, s'arrêtent ou changent d'emplacement. Un petit déploiement stable peut utiliser des adresses configurées ou le DNS. Un déploiement plus dynamique peut recourir à un registre ou aux fonctions de découverte de sa plateforme.
Les Services et EndpointSlices de Kubernetes en donnent un exemple : un Service représente un ensemble de points de terminaison, enregistrés dans des EndpointSlices. La plateforme peut les mettre à jour lorsque les charges de travail évoluent. Trouver une adresse ne prouve toutefois pas qu'une requête donnée aboutira.
La répartition de charge sélectionne une destination parmi celles qui conviennent. Elle peut tenir compte d'une rotation, du nombre de connexions, de la proximité ou de clés propres à l'application. Un même nombre de requêtes peut produire des charges différentes si leur coût varie. Les contrôles de santé, l'arrêt progressif des connexions et les nouvelles tentatives influencent aussi le résultat.
Adaptez le routage à l'état de l'application. Envoyer une requête à une autre instance n'est utile que si celle-ci peut accéder à la session ou aux données nécessaires. Le répartiteur ne déplace pas cet état à votre place.
Une application peut utiliser une base relationnelle, un stockage clé-valeur, une base distribuée, un stockage objet ou un système de fichiers partagé. Choisissez selon les accès et garanties nécessaires : transactions, types de requêtes, taille des objets, mises à jour concurrentes, ancienneté acceptable des lectures et exigences de reprise.
Une application distribuée n'exige pas une base de données distribuée. Plusieurs services peuvent utiliser une base sur une seule machine, qui devient alors une dépendance commune de capacité et de disponibilité. Une base gérée possède aussi sa propre architecture interne, avec parfois une réplication que les clients n'exploitent pas directement.
Distinguez durabilité, disponibilité, cohérence et sauvegarde. Un service peut conserver les données correctement tout en refusant temporairement les requêtes. Des répliques peuvent rester accessibles tout en accusant un retard sur les écritures. La réplication peut également copier une suppression accidentelle. Les sauvegardes nécessitent leur propre rétention et des contrôles de restauration.
La technologie ne décide pas quelle équipe possède une fiche client et ne réconcilie pas deux définitions différentes d'une commande. Ces questions relèvent du système d'information distribué, avec ses schémas, ses intégrations et ses règles de responsabilité sur les données.
La réplication maintient des copies des données ou de l'état. Le protocole de mise à jour détermine quand une écriture est confirmée et ce que les lecteurs peuvent observer. Les modèles synchrones et asynchrones font des compromis différents entre attente, disponibilité et perte de données possible après une panne. La documentation de réplication de PostgreSQL illustre ces choix.
Le partitionnement, souvent appelé sharding dans le contexte des bases de données, répartit les données ou le travail entre composants. La clé peut correspondre à un locataire, un client, une valeur de hachage ou un intervalle. Il permet de dépasser les capacités d'une machine, tout en pouvant créer des points chauds, des transactions entre partitions ou des rééquilibrages coûteux.
Dans un service de commandes, un partitionnement par client peut regrouper ses commandes, mais aussi laisser un gros client monopoliser une partition. Testez la répartition attendue de l'activité, pas seulement des données générées uniformément. Ajouter des partitions ne corrige pas automatiquement une clé mal choisie.
Le consensus permet aux nœuds participants de s'accorder sur une décision ou une suite ordonnée de changements d'état, dans un modèle de défaillance défini. Il peut servir à l'élection d'un responsable, à la gestion des membres ou à la réplication d'une configuration. Les applications utilisent généralement ces capacités par l'intermédiaire d'une base ou d'un service de coordination.
etcd utilise Raft et exige l'accord d'une majorité des membres votants pour les mises à jour. Un cluster de cinq votants nécessite trois voix. Si une coupure réseau sépare les membres en groupes de trois et de deux, seul le groupe disposant d'une majorité joignable peut continuer à valider des mises à jour, sous réserve des autres conditions de fonctionnement.
Le consensus ne peut pas rendre tous les groupes isolés capables d'accepter des écritures tout en conservant la même garantie d'accord. Il ne définit pas non plus les règles de l'application, ne garantit pas un délai et n'empêche pas un client autorisé d'envoyer une mise à jour erronée. La plupart des équipes ont intérêt à utiliser une implémentation éprouvée et à comprendre ses procédures de reprise.
Un cache conserve des informations moins coûteuses à récupérer qu'à recalculer ou à recharger. Il peut être intégré à un processus, fourni par un service comme Redis ou Memcached, ou prendre la forme d'un cache HTTP proche des utilisateurs. Chaque solution possède ses propres limites de partage et de défaillance.
Définissez l'expiration ou l'invalidation des entrées et les opérations qui doivent contourner le cache. Une description de produit ancienne peut être acceptable pendant un court délai ; une décision d'autorisation ancienne peut ne pas l'être. La durée de vie limite le temps de conservation sans rafraîchissement, mais ne garantit pas que l'entrée corresponde à la source durant cet intervalle.
Prévoyez la perte du cache et les absences simultanées d'une même entrée. Si de nombreuses requêtes recalculent la même valeur, le service sous-jacent peut être surchargé. Regrouper ce travail, limiter les rafraîchissements concurrents et tester le fonctionnement sans cache sont souvent plus utiles que d'optimiser uniquement le taux de succès du cache.
Les conteneurs regroupent les applications avec leurs dépendances en espace utilisateur. Des orchestrateurs comme Kubernetes placent les charges de travail, maintiennent un nombre souhaité d'instances et prennent en charge des opérations de déploiement et de réseau. Ces fonctions peuvent aider lorsque de nombreuses charges évoluent indépendamment.
Elles ne définissent pas la cohérence ni la reprise de l'application. Redémarrer un processus ne permet pas de savoir si sa dernière écriture en base a abouti. Exécuter plusieurs répliques ne rend pas les sessions stockées en mémoire accessibles à toutes. La configuration et le stockage persistant nécessitent toujours des choix explicites.
Un système distribué peut fonctionner sur des machines physiques ou virtuelles, sans conteneurs. Pour un petit déploiement, une gestion plus simple des processus et une automatisation du déploiement peuvent suffire. Adoptez l'orchestration lorsque ses fonctions de placement et de gestion du cycle de vie justifient l'exploitation d'un plan de contrôle ou la dépendance envers un service géré.
Les journaux enregistrent des événements, les métriques décrivent des mesures dans le temps et les traces relient les segments de travail entre composants instrumentés. Ensemble, ils peuvent aider à expliquer les requêtes lentes, les erreurs, la pression sur les ressources et l'attente entre services.
OpenTelemetry fournit l'instrumentation et les mécanismes de génération, de collecte et d'export des données de télémétrie. Il faut encore une destination pour les stocker et les analyser. Le contexte de trace doit se propager aux frontières que l'on souhaite suivre, y compris dans les messages asynchrones lorsque cela convient.
Une trace peut montrer qu'un appel au service d'inventaire occupe l'essentiel du temps d'une requête. Elle ne prouve pas que toutes les répliques contiennent la même quantité en stock. L'échantillonnage, l'instrumentation manquante et les ruptures de propagation limitent également ce qui est visible. Utilisez des contrôles applicatifs explicites pour vérifier les invariants des données et la reprise.
Choisissez des alertes liées aux résultats pour les utilisateurs et aux défaillances sur lesquelles une équipe peut agir. Définissez qui intervient et quelles preuves lui sont nécessaires. Excluez les identifiants secrets et les données personnelles inutiles de la télémétrie, puis contrôlez l'accès aux enregistrements conservés.
Prenons un service de commandes fictif. Voici un déroulement possible, qui ne constitue pas une architecture obligatoire :
La quatrième étape illustre le modèle transactional outbox, ou boîte d'envoi transactionnelle. Il évite de valider une commande sans conserver l'événement correspondant à publier. Un relais peut tout de même publier deux fois s'il échoue avant d'enregistrer sa progression. Les consommateurs doivent donc gérer les doublons. La reprise exige de vérifier tout le parcours, y compris les effets produits dans des systèmes externes.
Commencez par la raison qui justifie la distribution et le comportement dont les utilisateurs ont besoin en cas de panne. Prenez ensuite les décisions dans un ordre qui permet de tester les choix techniques :
Pendant les tests, vérifiez les résultats métier autant que la santé des processus. Après une réponse perdue et une nouvelle tentative, il doit rester une seule commande attendue. Après le redémarrage d'un consommateur, le traitement doit reprendre sans ignorer silencieusement des éléments. Après la restauration d'une sauvegarde, l'application doit pouvoir utiliser les données récupérées.
Le cloud computing décrit la fourniture et la consommation de capacités informatiques sous forme de services. Les technologies des systèmes distribués décrivent la communication et la coordination de composants distincts. Une plateforme cloud peut exploiter un courtier ou une base à votre place, tandis que votre application reste responsable du sens des messages, de sa configuration d'accès et de l'usage des garanties du service.
Une application distribuée peut fonctionner sur des serveurs détenus par l'organisation, des machines virtuelles louées ou une combinaison d'emplacements. On peut aussi consommer un service cloud sans concevoir son système distribué interne. Le mode d'obtention de l'infrastructure et la conception de l'application restent deux décisions liées, mais distinctes.
Si une application et une base de données répondent aux besoins de capacité, de reprise et de localisation, elles peuvent constituer le meilleur point de départ. Un processus de traitement en arrière-plan, une base de secours ou une deuxième instance applicative peuvent répondre à une contrainte précise sans introduire de nombreux services déployés séparément.
Ces ajouts peuvent eux-mêmes créer un comportement distribué : la simplicité ne dispense donc pas de tester les défaillances. Elle limite le volume de coordination que l'équipe doit comprendre. Avant d'adopter une nouvelle technologie, nommez la contrainte qu'elle traite, démontrez son intérêt avec la charge réelle et désignez l'équipe qui en assurera la maintenance.
Choisissez une charge de travail d’IA, de calcul ou de stockage à tester sur Hivenet, ou échangez avec notre équipe sur sa mise en production.