Kurzanleitung zum Spring Cloud Leistungsschalter

1. Übersicht

In diesem Tutorial stellen wir das Spring Cloud Circuit Breaker-Projekt vor und erfahren, wie wir es nutzen können.

Zunächst werden wir sehen, was der Spring Cloud-Leistungsschalter zusätzlich zu den vorhandenen Leistungsschalterimplementierungen bietet. Als Nächstes erfahren Sie, wie Sie mithilfe des automatischen Spring Boot-Konfigurationsmechanismus einen oder mehrere Leistungsschalter in unsere Anwendung integrieren.

Beachten Sie, dass wir in Einführung in Hystrix, Spring Cloud Netflix Hystrix und Leitfaden zu Resilience4j weitere Informationen darüber haben, was ein Leistungsschalter ist und wie er funktioniert.

2. Spring Cloud Leistungsschalter

Bis vor kurzem bot uns Spring Cloud nur eine Möglichkeit, Leistungsschalter in unsere Anwendungen aufzunehmen. Dies geschah durch die Verwendung von Netflix Hystrix als Teil des Spring Cloud Netflix-Projekts.

Das Spring Cloud Netflix-Projekt ist eigentlich nur eine annotationsbasierte Wrapper-Bibliothek um Hystrix. Daher sind diese beiden Bibliotheken eng miteinander verbunden. Dies bedeutet, dass wir nicht zu einer anderen Leistungsschalterimplementierung wechseln können, ohne die Anwendung zu ändern.

Das Spring Cloud Circuit Breaker-Projekt löst dieses Problem. Es bietet eine Abstraktionsschicht über verschiedene Leistungsschalterimplementierungen hinweg. Es ist eine steckbare Architektur. So können wir anhand der bereitgestellten Abstraktion / Schnittstelle codieren und je nach Bedarf zu einer anderen Implementierung wechseln.

In unseren Beispielen konzentrieren wir uns nur auf die Implementierung von Resilience4J. Diese Techniken können jedoch für andere Plugins verwendet werden.

3. Automatische Konfiguration

Um bestimmte Leistungsschalterimplementierungen in unserer Anwendung verwenden zu können, müssen wir den entsprechenden Federstarter hinzufügen. In unserem Fall verwenden wir Spring-Cloud-Starter-Circuitbreaker-Resilience4j :

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

Der automatische Konfigurationsmechanismus konfiguriert die erforderlichen Leistungsschalter-Beans, wenn einer der Starter im Klassenpfad angezeigt wird.

Wenn wir die automatische Konfiguration von Resilience4J deaktivieren möchten , können wir die Eigenschaft spring.cloud.circuitbreaker.resilience4j.enabled auf false setzen .

4. Ein einfaches Beispiel für einen Leistungsschalter

Erstellen wir eine Webanwendung mit Spring Boot, um zu untersuchen, wie die Spring Cloud Circuit Breaker-Bibliothek funktioniert.

Wir werden einen einfachen Webdienst erstellen, der eine Liste von Alben zurückgibt. Angenommen, die Rohliste wird von einem Drittanbieter bereitgestellt. Der Einfachheit halber verwenden wir eine externe Dummy-API, die von Jsonplaceholder bereitgestellt wird, um die Liste abzurufen:

//jsonplaceholder.typicode.com/albums

4.1. Erstellen Sie einen Leistungsschalter

Lassen Sie uns unseren ersten Leistungsschalter erstellen. Wir beginnen mit der Injektion einer Instanz der CircuitBreakerFactory- Bean:

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

Mit der CircuitBreakerFactory # create- Methode können wir jetzt ganz einfach einen Leistungsschalter erstellen . Als Argument wird die Leistungsschalterkennung herangezogen:

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

4.2. Wickeln Sie eine Aufgabe in einen Leistungsschalter

Um eine durch den Leistungsschalter geschützte Aufgabe zu verpacken und auszuführen, müssen wir die Methode r un aufrufen, die einen Lieferanten als Argument verwendet.

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

Der Leistungsschalter führt unsere Methode für uns aus und bietet Fehlertoleranz.

Manchmal kann es zu lange dauern, bis unser externer Dienst reagiert, eine unerwartete Ausnahme auslöst oder der externe Dienst oder Host nicht vorhanden ist. In diesem Fall können wir als zweites Argument für die run- Methode einen Fallback bereitstellen :

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

Das Lambda für den Fallback empfängt das Throwable als Eingabe und beschreibt den Fehler. Dies bedeutet, dass wir dem Anrufer je nach Art der Ausnahme , die den Fallback ausgelöst hat , unterschiedliche Fallback-Ergebnisse zur Verfügung stellen können .

In diesem Fall wird die Ausnahme nicht berücksichtigt. Wir werden nur eine zwischengespeicherte Liste von Alben zurückgeben.

Wenn der externe Aufruf mit einer Ausnahme endet und kein Fallback bereitgestellt wird, wird von Spring eine NoFallbackAvailableException ausgelöst.

4.3. Erstellen Sie einen Controller

Lassen Sie uns nun unser Beispiel beenden und einen einfachen Controller erstellen, der die Dienstmethoden aufruft und die Ergebnisse über einen Browser anzeigt:

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

Rufen wir abschließend den REST-Service auf und sehen uns die Ergebnisse an:

[GET] //localhost:8080/albums

5. Globale benutzerdefinierte Konfiguration

Normalerweise reicht die Standardkonfiguration nicht aus. Aus diesem Grund müssen wir Leistungsschalter mit benutzerdefinierten Konfigurationen basierend auf unseren Anwendungsfällen erstellen.

Um die Standardkonfiguration zu überschreiben, müssen wir unsere eigenen Beans und Eigenschaften in einer @ Configuration- Klasse angeben .

Here, we're going to define a global configuration for all circuit breakers. For this reason, we need to define a Customizer bean. So let's use the Resilience4JCircuitBreakerFactory implementation.

First, we'll define circuit breaker and time limiter configuration classes as per the Resilience4j tutorial:

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

Next, let's embed the configuration in a Customizer bean by using the Resilience4JCircuitBreakerFactory.configureDefault method:

@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. Specific Custom Configuration

Of course, we can have multiple circuit breakers in our application. Therefore, in some cases, we need a specific configuration for every circuit breaker.

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.

Als Nächstes nutzten wir den automatischen Spring Boot-Konfigurationsmechanismus, um zu zeigen, wie Leistungsschalter definiert und integriert werden. Außerdem haben wir anhand eines einfachen REST-Service gezeigt, wie der Spring Cloud Circuit Breaker funktioniert.

Schließlich haben wir gelernt, alle Leistungsschalter sowohl einzeln als auch einzeln zu konfigurieren.

Wie immer ist der Quellcode für dieses Tutorial auf GitHub verfügbar.