Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Schéma du disjoncteur
Intention
Le schéma du disjoncteur peut empêcher un service appelant de retenter un appel vers un autre service (appelé) lorsque l'appel a déjà provoqué des délais ou des échecs répétés. Le modèle est également utilisé pour détecter le moment où le service appelé est à nouveau fonctionnel.
Motivation
Lorsque plusieurs microservices collaborent pour traiter les demandes, un ou plusieurs services peuvent devenir indisponibles ou présenter une latence élevée. Lorsque des applications complexes utilisent des microservices, une panne d'un microservice peut entraîner la défaillance de l'application. Les microservices communiquent par le biais d'appels de procédure à distance, et des erreurs transitoires peuvent survenir dans la connectivité réseau et provoquer des défaillances. (Les erreurs transitoires peuvent être gérées en utilisant le modèle de nouvelle tentative avec retrait.) Lors d'une exécution synchrone, la cascade de délais ou d'échecs peut nuire à l'expérience utilisateur.
Cependant, dans certains cas, la résolution des défaillances peut prendre plus de temps, par exemple lorsque le service appelé est en panne ou qu'un conflit de base de données entraîne des délais d'attente. Dans de tels cas, si le service d'appel tente les appels à plusieurs reprises, ces tentatives peuvent entraîner un conflit sur le réseau et une consommation du pool de threads de base de données. En outre, si plusieurs utilisateurs réessayent l'application à plusieurs reprises, cela ne fera qu'aggraver le problème et entraîner une dégradation des performances de l'ensemble de l'application.
Le schéma du disjoncteur a été popularisé par Michael Nygard dans son livre, Release It (Nygard 2018). Ce modèle de conception peut empêcher un service appelant de réessayer un appel de service qui a déjà provoqué des délais ou des échecs répétés. Il peut également détecter le moment où le service appelé est à nouveau fonctionnel.
Les objets disjoncteurs fonctionnent comme des disjoncteurs électriques qui interrompent automatiquement le courant en cas d'anomalie dans le circuit. Les disjoncteurs électriques coupent ou déclenchent la circulation du courant en cas de panne. De même, l'objet disjoncteur est situé entre l'appelant et le service appelé, et se déclenche si l'appelé n'est pas disponible.
Les erreurs de l'informatique distribuée
Lors d'une panne réseau, les applications peuvent attendre indéfiniment une réponse et consommer continuellement leurs ressources. Le fait de ne pas recommencer les opérations lorsque le réseau devient disponible peut également entraîner une dégradation des applications. Si API les appels à une base de données ou à un service externe sont interrompus en raison de problèmes de réseau, des appels répétés sans disjoncteur peuvent affecter les coûts et les performances.
Applicabilité
Utilisez ce modèle lorsque :
-
Le service d'appel passe un appel qui risque fort d'échouer.
-
Une latence élevée du service appelé (par exemple, lorsque les connexions à la base de données sont lentes) entraîne des délais d'attente pour le service appelé.
-
Le service d'appel effectue un appel synchrone, mais le service appelé n'est pas disponible ou présente une latence élevée.
Problèmes et considérations
-
Implémentation indépendante du service : pour éviter toute surcharge de code, nous vous recommandons d'implémenter l'objet disjoncteur d'une manière indépendante et pilotée par les microservices. API
-
Fermeture du circuit par l'appelé : lorsque l'appelé se remet d'un problème ou d'une panne de performance, il peut mettre à jour l'état du circuit sur.
CLOSED
Il s'agit d'une extension du schéma du disjoncteur qui peut être mise en œuvre si votre objectif de temps de rétablissement (RTO) l'exige. -
Appels multithread : la valeur du délai d'expiration est définie comme la période pendant laquelle le circuit reste déclenché avant que les appels ne soient à nouveau routés pour vérifier la disponibilité du service. Lorsque le service appelé est appelé dans plusieurs threads, le premier appel qui a échoué définit la valeur du délai d'expiration. Votre implémentation doit garantir que les appels suivants ne déplacent pas le délai d'expiration indéfiniment.
-
Forcer l'ouverture ou la fermeture du circuit : les administrateurs système doivent avoir la possibilité d'ouvrir ou de fermer un circuit. Cela peut être fait en mettant à jour la valeur du délai d'expiration dans la table de base de données.
-
Observabilité : L'application doit avoir une journalisation configurée pour identifier les appels qui échouent lorsque le disjoncteur est ouvert.
Mise en œuvre
Architecture de haut niveau
Dans l'exemple suivant, l'appelant est le service de commande et l'appelé est le service de paiement.
Lorsqu'il n'y a pas de panne, le service de commande achemine tous les appels vers le service de paiement par le disjoncteur, comme le montre le schéma suivant.
Si le délai d'expiration du service de paiement est dépassé, le disjoncteur peut détecter le délai d'expiration et suivre la panne.
Si les délais d'attente dépassent un seuil spécifié, l'application ouvre le circuit. Lorsque le circuit est ouvert, l'objet du disjoncteur n'achemine pas les appels vers le service de paiement. Il renvoie une panne immédiate lorsque le service de commande appelle le service de paiement.
L'objet disjoncteur essaie périodiquement de voir si les appels au service de paiement aboutissent.
Lorsque l'appel au service de paiement aboutit, le circuit est fermé et tous les autres appels sont à nouveau acheminés vers le service de paiement.
Mise en œuvre au moyen AWS de services
L'exemple de solution utilise des flux de travail express AWS Step Functions
La solution utilise également une table Amazon DynamoDB
Lorsqu'un service souhaite appeler un autre service, il lance le flux de travail avec le nom du service appelé. Le flux de travail obtient l'état du disjoncteur à partir de la table CircuitStatus
DynamoDB, qui stocke les services actuellement dégradés. S'il CircuitStatus
contient un dossier non expiré pour l'appelé, le circuit est ouvert. Le flux de travail Step Functions renvoie une défaillance immédiate et s'en sort avec un FAIL
état.
Si la CircuitStatus
table ne contient aucun enregistrement pour l'appelé ou contient un enregistrement expiré, le service est opérationnel. L'ExecuteLambda
étape de définition de la machine à états appelle la fonction Lambda qui est envoyée via une valeur de paramètre. Si l'appel aboutit, le flux de travail Step Functions se termine avec un SUCCESS
état.
En cas d'échec de l'appel de service ou d'expiration du délai imparti, l'application réessaie avec un retard exponentiel pendant un nombre défini de fois. Si l'appel de service échoue après les nouvelles tentatives, le flux de travail insère un enregistrement dans le CircuitStatus
tableau pour le service avec un anExpiryTimeStamp
, et le flux de travail sort avec un FAIL
état. Les appels ultérieurs au même service entraînent une panne immédiate tant que le disjoncteur est ouvert. L'Get Circuit Status
étape de définition de la machine à états vérifie la disponibilité du service en fonction de la ExpiryTimeStamp
valeur. Les éléments expirés sont supprimés de la CircuitStatus
table à l'aide de la fonctionnalité DynamoDB time to live TTL ().
Exemple de code
Le code suivant utilise la fonction GetCircuitStatus
Lambda pour vérifier l'état du disjoncteur.
var serviceDetails = _dbContext.QueryAsync<CircuitBreaker>(serviceName, QueryOperator.GreaterThan, new List<object> {currentTimeStamp}).GetRemainingAsync(); if (serviceDetails.Result.Count > 0) { functionData.CircuitStatus = serviceDetails.Result[0].CircuitStatus; } else { functionData.CircuitStatus = ""; }
Le code suivant montre les instructions Amazon States Language dans le flux de travail Step Functions.
"Is Circuit Closed": { "Type": "Choice", "Choices": [ { "Variable": "$.CircuitStatus", "StringEquals": "OPEN", "Next": "Circuit Open" }, { "Variable": "$.CircuitStatus", "StringEquals": "", "Next": "Execute Lambda" } ] }, "Circuit Open": { "Type": "Fail" }
GitHub référentiel
Pour une implémentation complète de l'exemple d'architecture pour ce modèle, consultez le GitHub référentiel à l'adresse https://github.com/aws-samples/circuit-breaker-netcore-blog