Motif : Disjoncteur
Contexte
Vous avez appliqué l’architecture de Microservice.Les services collaborent parfois lors du traitement des demandes.Lorsqu’un service en appelle un autre de manière synchrone, il est toujours possible que l’autre service ne soit pas disponible ou présente une latence si élevée qu’il est essentiellement inutilisable.Des ressources précieuses telles que des threads peuvent être consommées dans l’appelant en attendant que l’autre service réponde.Cela pourrait entraîner un épuisement des ressources, ce qui empêcherait le service appelant de traiter d’autres demandes.La défaillance d’un service peut potentiellement se répercuter sur d’autres services dans l’ensemble de l’application.
Problème
Comment empêcher une panne de réseau ou de service de se répercuter sur d’autres services?
Solution
Un client de service doit appeler un service distant via un proxy qui fonctionne de la même manière qu’un disjoncteur électrique.Lorsque le nombre de pannes consécutives franchit un seuil, le disjoncteur se déclenche et, pendant la durée d’un délai d’attente, toutes les tentatives d’appel du service distant échouent immédiatement.Après l’expiration du délai d’attente, le disjoncteur permet à un nombre limité de demandes de test de passer.Si ces demandes réussissent, le disjoncteur reprend son fonctionnement normal.Sinon, en cas d’échec, le délai d’expiration recommence.
Exemple
RegistrationServiceProxy
de l’application Exemple de Microservices est un exemple de composant, écrit en Scala, qui utilise un disjoncteur pour gérer les pannes lors de l’appel d’un service distant.
@Componentclass RegistrationServiceProxy @Autowired()(restTemplate: RestTemplate) extends RegistrationService { @Value("${user_registration_url}") var userRegistrationUrl: String = _ @HystrixCommand(commandProperties=Array(new HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="800"))) override def registerUser(emailAddress: String, password: String): Either = { try { val response = restTemplate.postForEntity(userRegistrationUrl, RegistrationBackendRequest(emailAddress, password), classOf) response.getStatusCode match { case HttpStatus.OK => Right(response.getBody.id) } } catch { case e: HttpClientErrorException if e.getStatusCode == HttpStatus.CONFLICT => Left(DuplicateRegistrationError) } }}
Le @HystrixCommand
s’arrange pour que les appels à registerUser()
soient exécutés à l’aide d’un disjoncteur.
La fonctionnalité du disjoncteur est activée à l’aide de l’annotation @EnableCircuitBreaker
sur la classe UserRegistrationConfiguration
.
@EnableCircuitBreakerclass UserRegistrationConfiguration {
Contexte résultant
Ce modèle présente les avantages suivants:
- Les services gèrent l’échec des services qu’ils invoquent
Ce modèle présente les problèmes suivants:
- Il est difficile de choisir des valeurs de délai d’attente sans créer de faux positifs ou introduire une latence excessive.
- Le châssis de microservice peut implémenter ce modèle
- Une passerelle API utilisera ce modèle pour appeler des services
- Un routeur de découverte côté serveur peut utiliser ce modèle pour appeler des services
Voir aussi
- Netflix Hystrix est un exemple de bibliothèque qui implémente ce modèle