Patron Bulkhead

  • 03/19/2020
  • 4 minutes de lecture
    • d
    • D
    • . a
    • v
    • d
    • +6

Le modèle Bulkhead est un type de conception d’application qui est tolérant aux défaillances. Dans une architecture bulkhead, les éléments d’une application sont isolés en pools de sorte que si l’un d’entre eux tombe en panne, les autres continuent à fonctionner. Ce modèle tire son nom des cloisons (bulkheads) de la coque d’un navire. Si la coque d’un navire est compromise, seule la section endommagée se remplit d’eau, ce qui empêche le navire de couler.

Contexte et problème

Une application basée sur le cloud peut inclure plusieurs services, chaque service ayant un ou plusieurs consommateurs. Une charge excessive ou une défaillance dans un service aura un impact sur tous les consommateurs du service.

De plus, un consommateur peut envoyer des demandes à plusieurs services simultanément, en utilisant des ressources pour chaque demande. Lorsque le consommateur envoie une demande à un service qui est mal configuré ou qui ne répond pas, les ressources utilisées par la demande du client peuvent ne pas être libérées en temps voulu. Comme les demandes au service continuent, ces ressources peuvent être épuisées. Par exemple, le pool de connexions du client peut être épuisé. À ce stade, les demandes du consommateur à d’autres services sont affectées. Finalement, le consommateur ne peut plus envoyer de demandes à d’autres services, pas seulement au service initial qui ne répond pas.

Le même problème d’épuisement des ressources affecte les services avec de multiples consommateurs. Un grand nombre de demandes provenant d’un seul client peut épuiser les ressources disponibles dans le service. Les autres consommateurs ne sont plus en mesure de consommer le service, provoquant un effet de défaillance en cascade.

Solution

Partitionner les instances de service en différents groupes, en fonction de la charge des consommateurs et des exigences de disponibilité. Cette conception aide à isoler les défaillances, et vous permet de maintenir la fonctionnalité du service pour certains consommateurs, même pendant une défaillance.

Un consommateur peut également partitionner les ressources, pour s’assurer que les ressources utilisées pour appeler un service n’affectent pas les ressources utilisées pour appeler un autre service. Par exemple, un consommateur qui appelle plusieurs services peut se voir attribuer un pool de connexion pour chaque service. Si un service commence à tomber en panne, cela n’affecte que le pool de connexion attribué pour ce service, permettant au consommateur de continuer à utiliser les autres services.

Les avantages de ce pattern incluent :

  • Isole les consommateurs et les services des pannes en cascade. Un problème affectant un consommateur ou un service peut être isolé dans sa propre cloison, empêchant la solution entière de tomber en panne.
  • Vous permet de préserver certaines fonctionnalités en cas de panne d’un service. Les autres services et fonctionnalités de l’application continueront de fonctionner.
  • Vous permet de déployer des services qui offrent une qualité de service différente pour les applications consommatrices. Un pool de consommateurs à haute priorité peut être configuré pour utiliser des services à haute priorité.

Le schéma suivant montre des cloisons structurées autour de pools de connexion qui appellent des services individuels. Si le service A échoue ou cause un autre problème, le pool de connexion est isolé, de sorte que seules les charges de travail utilisant le pool de threads affecté au service A sont affectées. Les charges de travail qui utilisent le service B et C ne sont pas affectées et peuvent continuer à travailler sans interruption.

Le schéma suivant montre plusieurs clients appelant un seul service. Chaque client se voit attribuer une instance de service distincte. Le client 1 a fait trop de demandes et a submergé son instance. Comme chaque instance de service est isolée des autres, les autres clients peuvent continuer à faire des appels.

Issues et considérations

  • Définir les partitions autour des exigences commerciales et techniques de l’application.
  • Lorsque vous partitionnez des services ou des consommateurs en cloisons, considérez le niveau d’isolation offert par la technologie ainsi que les frais généraux en termes de coût, de performance et de gérabilité.
  • Envisagez de combiner les cloisons avec des modèles de relance, de disjoncteur et d’étranglement pour fournir une gestion des pannes plus sophistiquée.
  • Lorsque vous partitionnez des consommateurs en cloisons, envisagez d’utiliser des processus, des pools de threads et des sémaphores. Des projets comme resilience4j et Polly offrent un cadre pour créer des cloisons de consommateurs.
  • Lorsque vous partitionnez des services en cloisons, envisagez de les déployer dans des machines virtuelles, des conteneurs ou des processus séparés. Les conteneurs offrent un bon équilibre d’isolation des ressources avec une surcharge assez faible.
  • Les services qui communiquent à l’aide de messages asynchrones peuvent être isolés par différents ensembles de files d’attente. Chaque file d’attente peut avoir un ensemble dédié d’instances traitant les messages sur la file d’attente, ou un groupe unique d’instances utilisant un algorithme pour déqueter et répartir le traitement.
  • Déterminer le niveau de granularité pour les cloisons. Par exemple, si vous souhaitez répartir les locataires entre les cloisons, vous pouvez placer chaque locataire dans une cloison distincte ou mettre plusieurs locataires dans une seule cloison.
  • Surveiller les performances et le SLA de chaque cloison.

Quand utiliser ce pattern

Utiliser ce pattern pour :

  • Isoler les ressources utilisées pour consommer un ensemble de services backend, surtout si l’application peut fournir un certain niveau de fonctionnalité même lorsqu’un des services ne répond pas.
  • Isoler les consommateurs critiques des consommateurs standards.
  • Protéger l’application des défaillances en cascade.

Ce pattern peut ne pas convenir lorsque :

  • Une utilisation moins efficace des ressources peut ne pas être acceptable dans le projet.
  • La complexité supplémentaire n’est pas nécessaire

Exemple

Le fichier de configuration Kubernetes suivant crée un conteneur isolé pour exécuter un seul service, avec ses propres ressources et limites de CPU et de mémoire.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.