Pattern: Circuit Breaker
Context
È stata applicata l’architettura Microservice.I servizi a volte collaborano durante la gestione delle richieste.Quando un servizio richiama in modo sincrono un altro, c’è sempre la possibilità che l’altro servizio non sia disponibile o mostri una latenza così elevata che è essenzialmente inutilizzabile.Risorse preziose come i thread potrebbero essere consumate nel chiamante durante l’attesa che l’altro servizio risponda.Ciò potrebbe portare all’esaurimento delle risorse, il che renderebbe il servizio chiamante incapace di gestire altre richieste.L’errore di un servizio può potenzialmente cascata ad altri servizi in tutta l’applicazione.
Problema
Come evitare che un errore di rete o di servizio si colleghi a cascata ad altri servizi?
Soluzione
Un client di servizio deve richiamare un servizio remoto tramite un proxy che funzioni in modo simile a un interruttore elettrico.Quando il numero di guasti consecutivi supera una soglia, l’interruttore scatta e per la durata di un periodo di timeout tutti i tentativi di richiamare il servizio remoto falliranno immediatamente.Allo scadere del timeout, l’interruttore automatico consente il passaggio di un numero limitato di richieste di test.Se tali richieste riescono l’interruttore riprende il normale funzionamento.In caso contrario, se si verifica un errore, il periodo di timeout ricomincia.
Esempio
RegistrationServiceProxy
dall’applicazione Microservices Esempio è un esempio di un componente, che è scritto in Scala, che utilizza un interruttore per gestire i guasti quando si richiama un servizio remoto.
@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) } }}
Il @HystrixCommand
organizza per le chiamate a registerUser()
da eseguire utilizzando un interruttore.
La funzionalità dell’interruttore automatico è abilitata utilizzando l’annotazione @EnableCircuitBreaker
sulla classe UserRegistrationConfiguration
.
@EnableCircuitBreakerclass UserRegistrationConfiguration {
Risultante Contesto
Questo modello ha i seguenti vantaggi:
- Servizi gestire il fallimento dei servizi che essi invocano
Questo modello ha i seguenti problemi:
- è difficile scegliere i valori di timeout senza creare falsi positivi o introdurre un’eccessiva latenza.
- Il Microservice Telaio potrebbe implementare questo modello
- Un’API Gateway di usare questo modello di richiamare servizi
- Server-side scoperta router potrebbe utilizzare questo modello di richiamare servizi
Vedi anche
- Netflix Hystrix è un esempio di una libreria che implementa questo modello