Een gids voor Spring Cloud Netflix - Hystrix

1. Overzicht

In deze tutorial behandelen we Spring Cloud Netflix Hystrix - de fouttolerantiebibliotheek. We gebruiken de bibliotheek en implementeren het Circuit Breaker-bedrijfspatroon, dat een strategie beschrijft tegen het trapsgewijs optreden van fouten op verschillende niveaus in een applicatie.

Het principe is analoog aan elektronica: Hystrix kijkt naar methoden voor mislukte oproepen naar gerelateerde services. Als er een dergelijke storing is, wordt het circuit geopend en wordt de oproep doorgeschakeld naar een fallback-methode.

De bibliotheek tolereert storingen tot een drempelwaarde. Buiten dat laat het het circuit open. Dat betekent dat alle volgende oproepen worden doorgeschakeld naar de fallback-methode om toekomstige storingen te voorkomen. Dit creëert een tijdbuffer voor de gerelateerde service om te herstellen van de falende staat.

2. REST Producer

Om een ​​scenario te maken dat het Circuit Breaker-patroon laat zien, hebben we eerst een servicebeurt nodig. We noemen het "REST Producer" omdat het gegevens levert voor de Hystrix-geactiveerde "REST Consumer", die we in de volgende stap zullen maken.

Laten we een nieuw Maven-project maken met de spring-boot-starter-web afhankelijkheid:

 org.springframework.boot spring-boot-starter-web 2.2.6.RELEASE 

Het project zelf is opzettelijk eenvoudig gehouden. Het bestaat uit een controllerinterface met één @RequestMapping geannoteerde GET-methode die eenvoudig een Draad, een @RestController het implementeren van deze interface en een @SpringBootApplication.

We beginnen met de interface:

openbare interface GreetingController {@GetMapping ("/ greeting / {username}") String-begroeting (@PathVariable ("gebruikersnaam") String-gebruikersnaam); }

En de implementatie:

@RestController public class GreetingControllerImpl implementeert GreetingController {@Override public String-begroeting (@PathVariable ("gebruikersnaam") String-gebruikersnaam) {return String.format ("Hallo% s! \ N", gebruikersnaam); }}

Vervolgens schrijven we de hoofdtoepassingsklasse op:

@SpringBootApplication openbare klasse RestProducerApplication {openbare statische leegte hoofd (String [] args) {SpringApplication.run (RestProducerApplication.class, args); }}

Om deze sectie te voltooien, hoef je alleen nog een applicatiepoort te configureren waarnaar we zullen luisteren. We zullen de standaardpoort 8080 niet gebruiken omdat de poort gereserveerd moet blijven voor de toepassing die in de volgende stap wordt beschreven.

Bovendien definiëren we een applicatienaam om onze producer te kunnen opzoeken in de clientapplicatie die we later zullen introduceren.

Laten we dan een poort specificeren van 9090 en een naam van rest-producer in onze application.properties het dossier:

server.port = 9090 spring.application.name = rest-producer

Nu kunnen we onze producer testen met cURL:

$> curl // localhost: 9090 / groet / Cid Hallo Cid!

3. REST-consument met Hystrix

Voor ons demonstratiescenario implementeren we een webtoepassing die de REST-service uit de vorige stap gebruikt met RestTemplate en Hystrix. Eenvoudigheidshalve noemen we het de "REST Consument".

Daarom creëren we een nieuw Maven-project met spring-cloud-starter-hystrix, spring-boot-starter-web en spring-boot-starter-thymeleaf als afhankelijkheden:

 org.springframework.cloud spring-cloud-starter-hystrix 1.4.7.RELEASE org.springframework.boot spring-boot-starter-web 2.2.6.RELEASE org.springframework.boot spring-boot-starter-thymeleaf 2.2.6. VRIJLATING 

Om de stroomonderbreker te laten werken, zal Hystix scannen @Component of @Onderhoud geannoteerde klassen voor @HystixCommand geannoteerde methoden, implementeer er een proxy voor en controleer de oproepen.

We gaan een @Onderhoud klasse eerst, die zal worden geïnjecteerd in een @Controller. Omdat we een webapplicatie bouwen met Thymeleaf, hebben we ook een HTML-sjabloon nodig om als weergave te dienen.

Dit wordt onze injecteerbare @Onderhoud implementeren van een @HystrixCommand met een bijbehorende uitwijkmethode. Deze fallback moet dezelfde handtekening gebruiken als het origineel:

@Service openbare klasse GreetingService {@HystrixCommand (fallbackMethod = "defaultGreeting") openbare String getGreeting (String gebruikersnaam) {retourneer nieuwe RestTemplate () .getForObject ("// localhost: 9090 / groet / {gebruikersnaam}", String.class, gebruikersnaam ); } private String defaultGreeting (String gebruikersnaam) {return "Hallo gebruiker!"; }}

RestConsumerApplication zal onze belangrijkste toepassingsklasse zijn. De @EnableCircuitBreaker annotatie scant het klassenpad voor elke compatibele Circuit Breaker-implementatie.

Om Hystrix expliciet te gebruiken, moeten we deze klasse annoteren met @EnableHystrix:

@SpringBootApplication @EnableCircuitBreaker openbare klasse RestConsumerApplication {openbare statische leegte hoofd (String [] args) {SpringApplication.run (RestConsumerApplication.class, args); }}

We stellen de controller in met behulp van onze GroetService:

@Controller openbare klasse GreetingController {@Autowired privé GreetingService greetingService; @GetMapping ("/ get-greeting / {gebruikersnaam}") public String getGreeting (Modelmodel, @PathVariable ("gebruikersnaam") String gebruikersnaam) {model.addAttribute ("groet", greetingService.getGreeting (gebruikersnaam)); retourneer "begroetingsweergave"; }}

En hier is de HTML-sjabloon:

   Groeten van Hystrix 

Om er zeker van te zijn dat de applicatie op een gedefinieerde poort luistert, plaatsen we het volgende in een application.properties het dossier:

server.port = 8080

Om een ​​Hystix-stroomonderbreker in actie te zien, starten we onze consument en wijzen onze browser hierop // localhost: 8080 / get-greeting / Cid. Onder normale omstandigheden wordt het volgende getoond:

Hallo Cid!

Om een ​​storing van onze producer te simuleren, stoppen we deze gewoon, en nadat we klaar zijn met het vernieuwen van de browser, zouden we een algemeen bericht moeten zien, geretourneerd van de fallback-methode in onze @Onderhoud:

Hallo gebruiker!

4. REST-consument met Hystrix en Feign

Nu gaan we het project van de vorige stap aanpassen om Spring Netflix Feign te gebruiken als declaratieve REST-client, in plaats van Spring RestTemplate.

Het voordeel is dat we later gemakkelijk onze Feign Client-interface kunnen refactoren om Spring Netflix Eureka te gebruiken voor het ontdekken van services.

Om het nieuwe project te starten, maken we een kopie van onze consument en voegen we onze producent en toe spring-cloud-starter-veinzen als afhankelijkheden:

 com.baeldung.spring.cloud spring-cloud-hystrix-rest-producer 1.0.0-SNAPSHOT org.springframework.cloud spring-cloud-starter-feign 1.1.5.RELEASE 

Nu kunnen we onze Groetcontroller om een ​​Feign Client uit te breiden. We zullen implementeren Hystrix fallback als een statische innerlijke klasse met annotaties @Component.

Als alternatief kunnen we een @Boon geannoteerde methode die een instantie van deze fallback-klasse retourneert.

De eigenschap name van het @Feyenoord is verplicht. Het wordt gebruikt om de applicatie op te zoeken via service discovery via een Eureka Client of via URL, als deze eigenschap is opgegeven:

@FeignClient (name = "rest-producer" url = "// localhost: 9090", fallback = GreetingClient.GreetingClientFallback.class) openbare interface GreetingClient breidt GreetingController uit {@Component openbare statische klasse GreetingClientFallback implementeert GreetingController {@Override public String-begroeting (@ PathVariable ("gebruikersnaam") String gebruikersnaam) {return "Hallo gebruiker!"; }}}

Raadpleeg dit artikel voor meer informatie over het gebruik van Spring Netflix Eureka voor het ontdekken van services.

In de RestConsumerFeignApplication, plaatsen we een extra annotatie om Feign-integratie mogelijk te maken, in feite @EnableFeignClients, naar de hoofdtoepassingsklasse:

@SpringBootApplication @EnableCircuitBreaker @EnableFeignClients openbare klasse RestConsumerFeignApplication {openbare statische leegte hoofd (String [] args) {SpringApplication.run (RestConsumerFeignApplication.class, args); }}

We gaan de controller aanpassen om een ​​auto-wired Feign Client te gebruiken, in plaats van de eerder geïnjecteerde @Onderhoud, om onze begroeting op te halen:

@Controller openbare klasse GreetingController {@Autowired privé GreetingClient greetingClient; @GetMapping ("/ get-greeting / {gebruikersnaam}") public String getGreeting (Modelmodel, @PathVariable ("gebruikersnaam") String gebruikersnaam) {model.addAttribute ("groet", greetingClient.greeting (gebruikersnaam)); retourneer "begroetingsweergave"; }}

Om dit voorbeeld van het vorige te onderscheiden, zullen we de luisterpoort van de toepassing in het application.properties:

server.port = 8082

Ten slotte zullen we deze Feign-enabled consument testen, zoals die uit de vorige sectie. Het verwachte resultaat zou hetzelfde moeten zijn.

5. Terugval in cache met Hystrix

Nu gaan we Hystrix toevoegen aan ons Spring Cloud-project. In dit cloudproject hebben we een beoordelingsservice die met de database praat en beoordelingen van boeken krijgt.

Laten we aannemen dat onze database een resource is waar veel vraag naar is en dat de responslatentie in de tijd kan variëren of in tijden niet beschikbaar is. We zullen dit scenario afhandelen waarbij de Hystrix-stroomonderbreker terugvalt naar een cache voor de gegevens.

5.1. Installatie en configuratie

Laten we de spring-cloud-starter-hystrix afhankelijkheid van onze beoordelingsmodule:

 org.springframework.cloud spring-cloud-starter-hystrix 

Wanneer beoordelingen worden ingevoegd / bijgewerkt / verwijderd in de database, repliceren we hetzelfde naar de Redis-cache met een Opslagplaats. Raadpleeg dit artikel voor meer informatie over Redis.

Laten we het RatingService om de database-zoekmethoden in een Hystrix-commando te verpakken met @HystrixCommand en configureer het met een terugval naar lezen vanuit Redis:

@HystrixCommand (commandKey = "ratingsByIdFromDB", fallbackMethod = "findCachedRatingById", ignoreExceptions = {RatingNotFoundException.class}) openbare beoordeling findRatingById (Long ratingId) {return Optioneel.ofNullable (ratingRepository (rating) ->). (Rating). nieuwe RatingNotFoundException ("Beoordeling niet gevonden. ID:" + ratingId)); } openbare beoordeling findCachedRatingById (lange ratingId) {retourneer cacheRepository.findCachedRatingById (ratingId); }

Merk op dat de fallback-methode dezelfde handtekening van een ingepakte methode moet hebben en zich in dezelfde klasse moet bevinden. Nu wanneer de findRatingById mislukt of wordt meer vertraagd dan een bepaalde drempel, Hystrix valt terug op findCachedRatingById.

Omdat de Hystrix-mogelijkheden transparant worden geïnjecteerd als AOP-advies, moeten we de volgorde waarin het advies wordt gestapeld aanpassen, voor het geval we ander advies hebben, zoals het transactieadvies van Spring. Hier hebben we het transactie-AOP-advies van Spring aangepast om een ​​lagere prioriteit te hebben dan Hystrix AOP-advies:

@EnableHystrix @EnableTransactionManagement (order = Ordered.LOWEST_PRECEDENCE, mode = AdviceMode.ASPECTJ) openbare klasse RatingServiceApplication {@Bean @Primary @Order (waarde = Ordered.HIGHEST_PRECEDENCE) openbare HystrixCommandAspectCommandAspectCommandAspectCommandAspectCommandAspectCommandAspect (return) } // andere bonen, configuraties}

Hier hebben we het transactie-AOP-advies van Spring aangepast om een ​​lagere prioriteit te hebben dan Hystrix AOP-advies.

5.2. Hystrix Fallback testen

Nu we het circuit hebben geconfigureerd, kunnen we het testen door de H2-database waarmee onze repository samenwerkt, te verwijderen. Maar laten we eerst de H2-instantie uitvoeren als een extern proces in plaats van deze als een ingesloten database uit te voeren.

Laten we de H2-bibliotheek (h2-1.4.193.jar) naar een bekende directory en start de H2-server:

> java -cp h2-1.4.193.jar org.h2.tools.Server -tcp TCP-server draait op tcp: //192.168.99.1: 9092 (alleen lokale verbindingen)

Laten we nu de gegevensbron-URL van onze module updaten in rating-service.properties om naar deze H2-server te verwijzen:

spring.datasource.url = jdbc: h2: tcp: // localhost / ~ / ratings

We kunnen onze services starten zoals beschreven in ons vorige artikel uit de Spring Cloud-serie, en beoordelingen van elk boek testen door de externe H2-instantie die we gebruiken te verwijderen.

We konden zien dat wanneer de H2-database niet bereikbaar is, Hystrix automatisch terugvalt op Redis om de beoordelingen voor elk boek te lezen. De broncode die deze use case demonstreert, is hier te vinden.

6. Scopes gebruiken

Normaal gesproken is een @HytrixCommand geannoteerde methode wordt uitgevoerd in een threadpoolcontext. Maar soms moet het in een lokale scope worden uitgevoerd, bijvoorbeeld een @SessionScope of een @RequestScope. Dit kan gedaan worden door argumenten te geven aan de opdrachtannotatie:

@HystrixCommand (fallbackMethod = "getSomeDefault", commandProperties = {@HystrixProperty (name = "execution.isolation.strategy", value = "SEMAPHORE")})

7. Het Hystrix-dashboard

Een leuke optionele functie van Hystrix is ​​de mogelijkheid om de status op een dashboard te volgen.

Om het in te schakelen, plaatsen we spring-cloud-starter-hystrix-dashboard en veer-boot-starter-actuator in de pom.xml van onze consument:

 org.springframework.cloud spring-cloud-starter-hystrix-dashboard 1.4.7.RELEASE org.springframework.boot spring-boot-starter-actuator 2.2.6.RELEASE 

De eerste moet worden ingeschakeld via het annoteren van een @Configuratie met @EnableHystrixDashboard en de laatste maakt automatisch de vereiste statistieken binnen onze webapplicatie mogelijk.

Nadat we de applicatie opnieuw hebben opgestart, wijzen we een browser op // localhost: 8080 / hystrix, voer de metrische URL van een Hystrix-stream in en begin met monitoren.

Ten slotte zouden we zoiets als dit moeten zien:

Het monitoren van een Hystrix-stream is prima, maar als we meerdere Hystrix-enabled applicaties moeten bekijken, wordt het lastig. Voor dit doel biedt Spring Cloud een tool genaamd Turbine, die streams kan samenvoegen om in één Hystrix-dashboard te presenteren.

Het configureren van Turbine valt buiten het bestek van dit artikel, maar de mogelijkheid moet hier worden vermeld. Het is dus ook mogelijk om deze streams via messaging te verzamelen met behulp van Turbine stream.

8. Conclusie

Zoals we tot nu toe hebben gezien, kunnen we nu het Circuit Breaker-patroon implementeren met Spring Netflix Hystrix samen met Spring RestTemplate of Spring Netflix Feign.

Dit betekent dat we services met inbegrepen fallback kunnen gebruiken met standaardgegevens en dat we het gebruik van deze gegevens kunnen volgen.

Zoals gewoonlijk kunnen we de bronnen vinden op GitHub.