Guida rapida a Spring Cloud Circuit Breaker

1. Panoramica

In questo tutorial, introdurremo il progetto Spring Cloud Circuit Breaker e impareremo come utilizzarlo.

Innanzitutto, vedremo cosa offre Spring Cloud Circuit Breaker oltre alle implementazioni esistenti degli interruttori automatici. Successivamente, impareremo come utilizzare il meccanismo di configurazione automatica di Spring Boot per integrare uno o più interruttori di circuito nella nostra applicazione.

Tieni presente che abbiamo ulteriori informazioni su cosa sia un interruttore di circuito e su come funzionano in Introduzione a Hystrix, Spring Cloud Netflix Hystrix e Guida a Resilience4j.

2. Spring Cloud Circuit Breaker

Fino a poco tempo, Spring Cloud ci forniva solo un modo per aggiungere interruttori di circuito nelle nostre applicazioni. Ciò è avvenuto attraverso l'uso di Netflix Hystrix come parte del progetto Spring Cloud Netflix.

Il progetto Spring Cloud Netflix è in realtà solo una libreria wrapper basata su annotazioni attorno a Hystrix. Pertanto, queste due librerie sono strettamente collegate. Ciò significa che non è possibile passare a un'altra implementazione dell'interruttore di circuito senza modificare l'applicazione.

Il progetto Spring Cloud Circuit Breaker risolve questo problema. Fornisce uno strato di astrazione tra diverse implementazioni di interruttori automatici. È un'architettura collegabile. Quindi, possiamo codificare in base all'astrazione / interfaccia fornita e passare a un'altra implementazione in base alle nostre esigenze.

Per i nostri esempi, ci concentreremo solo sull'implementazione di Resilience4J. Tuttavia, queste tecniche possono essere utilizzate per altri plugin.

3. Configurazione automatica

Per poter utilizzare una specifica implementazione dell'interruttore nella nostra applicazione, è necessario aggiungere l'avviamento a molla appropriato. Nel nostro caso, usiamo spring-cloud-starter-circuitbreaker-resilience4j :

 org.springframework.cloud spring-cloud-starter-circuitbreaker-resilience4j 1.0.2.RELEASE 

Il meccanismo di configurazione automatica configura i bean dell'interruttore di circuito necessari se vede uno degli avviatori nel classpath.

Se volessimo disabilitare la configurazione automatica di Resilience4J, potremmo impostare la proprietà spring.cloud.circuitbreaker.resilience4j.enabled su false .

4. Un semplice esempio di interruttore automatico

Creiamo un'applicazione web utilizzando Spring Boot per permetterci di esplorare come funziona la libreria Spring Cloud Circuit Breaker.

Costruiremo un semplice servizio web che restituisce un elenco di album. Supponiamo che l'elenco grezzo sia fornito da un servizio di terze parti. Per semplicità, utilizzeremo un'API fittizia esterna fornita da Jsonplaceholder per recuperare l'elenco:

//jsonplaceholder.typicode.com/albums

4.1. Crea un interruttore automatico

Creiamo il nostro primo interruttore automatico. Inizieremo iniettando un'istanza del bean CircuitBreakerFactory :

@Service public class AlbumService { @Autowired private CircuitBreakerFactory circuitBreakerFactory; //... }

Ora, possiamo facilmente creare un interruttore automatico usando il metodo di creazione # CircuitBreakerFactory . Prende l'identificativo dell'interruttore come argomento:

CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker");

4.2. Avvolgi un'attività in un interruttore automatico

Per eseguire il wrapping ed eseguire un'attività protetta dall'interruttore, dobbiamo chiamare il metodo r un che prende come argomento un fornitore .

public String getAlbumList() { CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker"); String url = "//jsonplaceholder.typicode.com/albums"; return circuitBreaker.run(() -> restTemplate.getForObject(url, String.class)); }

L'interruttore automatico esegue il nostro metodo per noi e fornisce la tolleranza ai guasti.

A volte, il nostro servizio esterno potrebbe impiegare troppo tempo per rispondere, generare un'eccezione imprevista oppure il servizio esterno o l'host non esiste. In tal caso, possiamo fornire un fallback come secondo argomento al metodo run :

public String getAlbumList() { CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker"); String url = "//localhost:1234/not-real"; return circuitBreaker.run(() -> restTemplate.getForObject(url, String.class), throwable -> getDefaultAlbumList()); }

Il lambda per il fallback riceve Throwable come input, che descrive l'errore. Ciò significa che possiamo fornire diversi risultati di fallback al chiamante, in base al tipo di eccezione che ha attivato il fallback.

In questo caso, non prenderemo in considerazione l'eccezione. Restituiremo solo un elenco di album memorizzati nella cache.

Se la chiamata esterna termina con un'eccezione e non viene fornito alcun fallback, Spring genera un'eccezione NoFallbackAvailableException .

4.3. Crea un controller

Ora, finiamo il nostro esempio e creiamo un semplice controller che chiama i metodi del servizio e presenta i risultati tramite un browser:

@RestController public class Controller { @Autowired private Service service; @GetMapping("/albums") public String albums() { return service.getAlbumList(); } }

Infine, chiamiamo il servizio REST e vediamo i risultati:

[GET] //localhost:8080/albums

5. Configurazione personalizzata globale

Di solito, la configurazione predefinita non è sufficiente. Per questo motivo, dobbiamo creare interruttori automatici con configurazioni personalizzate in base ai nostri casi d'uso.

Per sovrascrivere la configurazione predefinita, dobbiamo specificare i nostri bean e proprietà in una classe @Configuration .

Qui, definiremo una configurazione globale per tutti gli interruttori automatici. Per questo motivo, dobbiamo definire un bean Customizer . Quindi usiamo l' implementazione di Resilience4JCircuitBreakerFactory .

Innanzitutto, definiremo le classi di configurazione di interruttori automatici e limitatori di tempo come da tutorial Resilience4j:

CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .failureRateThreshold(50) .waitDurationInOpenState(Duration.ofMillis(1000)) .slidingWindowSize(2) .build(); TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom() .timeoutDuration(Duration.ofSeconds(4)) .build();

Successivamente, incorporiamo la configurazione in un bean Customizer utilizzando il metodo Resilience4JCircuitBreakerFactory.configureDefault :

@Configuration public class Resilience4JConfiguration { @Bean public Customizer globalCustomConfiguration() { // the circuitBreakerConfig and timeLimiterConfig objects return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id) .timeLimiterConfig(timeLimiterConfig) .circuitBreakerConfig(circuitBreakerConfig) .build()); } }

6. Configurazione personalizzata specifica

Naturalmente, possiamo avere più interruttori automatici nella nostra applicazione. Pertanto, in alcuni casi, è necessaria una configurazione specifica per ogni interruttore.

Similarly, we can define one or more Customizer beans. Then, we can provide a different configuration for each one by using the Resilience4JCircuitBreakerFactory.configure method:

@Bean public Customizer specificCustomConfiguration1() { // the circuitBreakerConfig and timeLimiterConfig objects return factory -> factory.configure(builder -> builder.circuitBreakerConfig(circuitBreakerConfig) .timeLimiterConfig(timeLimiterConfig).build(), "circuitBreaker"); }

Here we provide a second parameter, the id of the circuit breaker we're configuring.

We can also set up multiple circuit breakers with the same configuration by providing a list of circuit breaker ids to the same method:

@Bean public Customizer specificCustomConfiguration2() { // the circuitBreakerConfig and timeLimiterConfig objects return factory -> factory.configure(builder -> builder.circuitBreakerConfig(circuitBreakerConfig) .timeLimiterConfig(timeLimiterConfig).build(), "circuitBreaker1", "circuitBreaker2", "circuitBreaker3"); }

7. Alternative Implementations

We've seen how to use the Resilience4j implementation to create one or more circuit breakers with Spring Cloud Circuit Breaker.

However, there are other implementations supported by Spring Cloud Circuit Breaker that we can leverage in our application:

  • Hystrix
  • Sentinel
  • Spring Retry

It's worth mentioning that we can mix and match different circuit breaker implementations in our application. We're not just limited to one library.

The above libraries have more capabilities than we've explored here. However, Spring Cloud Circuit Breaker is an abstraction over only the circuit breaker part. For example, Resilience4j also provides other modules like RateLimiter, Bulkhead, Retry in addition to the CircuitBreaker and TimeLimiter modules used in this article.

8. Conclusion

In this article, we discovered the Spring Cloud Circuit Breaker project.

First, we learned what the Spring Cloud Circuit Breaker is, and how it allows us to add circuit breakers to our application.

Successivamente, abbiamo sfruttato il meccanismo di configurazione automatica di Spring Boot per mostrare come definire e integrare gli interruttori di circuito. Inoltre, abbiamo dimostrato come funziona Spring Cloud Circuit Breaker attraverso un semplice servizio REST.

Infine, abbiamo imparato a configurare tutti gli interruttori automatici insieme, oltre che individualmente.

Come sempre, il codice sorgente di questo tutorial è disponibile su GitHub.