En guide til Spring Cloud Netflix - Hystrix

1. Oversigt

I denne vejledning dækker vi Spring Cloud Netflix Hystrix - fejltolerancebiblioteket. Vi bruger biblioteket og implementerer Circuit Breaker-virksomhedsmønsteret, der beskriver en strategi mod fiasko, der kaskaderer på forskellige niveauer i en applikation.

Princippet er analogt med elektronik: Hystrix overvåger metoder til mislykkede opkald til relaterede tjenester. Hvis der er sådan en fejl, åbner den kredsløbet og videresender opkaldet til en tilbageførselsmetode.

Biblioteket tåler fejl op til en tærskel. Ud over det lader det kredsløbet være åbent. Hvilket betyder, at det videresender alle efterfølgende opkald til reservemetoden for at forhindre fremtidige fejl. Dette skaber en tidsbuffer for den relaterede tjeneste til at gendanne fra sin svigtende tilstand.

2. REST Producent

For at skabe et scenario, der demonstrerer Circuit Breaker-mønsteret, skal vi først bruge en service. Vi kalder det "REST Producer", da det leverer data til den Hystrix-aktiverede "REST Consumer", som vi opretter i næste trin.

Lad os oprette et nyt Maven-projekt ved hjælp af spring-boot-starter-web afhængighed:

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

Selve projektet er bevidst holdt enkelt. Den består af en controller-interface med en @RequestMapping kommenteret GET-metode returnerer simpelthen a Snor, -en @RestController implementering af denne grænseflade og en @SpringBootApplication.

Vi begynder med grænsefladen:

offentlig grænseflade GreetingController {@GetMapping ("/ greeting / {username}") String greeting (@PathVariable ("username") String username); }

Og implementeringen:

@RestController offentlig klasse GreetingControllerImpl implementerer GreetingController {@Override public String greeting (@PathVariable ("username") String username) {return String.format ("Hello% s! \ N", username); }}

Dernæst skriver vi hovedapplikationsklassen ned:

@SpringBootApplication offentlig klasse RestProducerApplication {public static void main (String [] args) {SpringApplication.run (RestProducerApplication.class, args); }}

For at fuldføre dette afsnit er det eneste, der er tilbage at gøre, at konfigurere en applikationsport, som vi lytter til. Vi bruger ikke standardport 8080, fordi porten skal forblive forbeholdt den applikation, der er beskrevet i næste trin.

Desuden definerer vi et applikationsnavn for at kunne slå op til vores producent fra klientapplikationen, som vi introducerer senere.

Lad os derefter specificere en havn af 9090 og et navn på hvile-producent i vores application.properties fil:

server.port = 9090 spring.application.name = hvileproducent

Nu er vi i stand til at teste vores producent ved hjælp af cURL:

$> krølle // localhost: 9090 / hilsen / Cid Hello Cid!

3. REST Forbruger med Hystrix

I vores demonstrationsscenarie implementerer vi en webapplikation, der bruger REST-tjenesten fra det foregående trin ved hjælp af RestTemplate og Hystrix. Af enkelheds skyld vil vi kalde det "REST-forbrugeren".

Derfor opretter vi et nyt Maven-projekt med spring-cloud-starter-hystrix, spring-boot-starter-web og spring-boot-starter-thymeleaf som afhængigheder:

 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. FRIGØRE 

For at afbryderen fungerer, scanner Hystix @Komponent eller @Service kommenterede klasser til @HystixCommand annoterede metoder, implementerer en proxy for den og overvåger dens opkald.

Vi opretter en @Service klasse først, som vil blive injiceret i en @Kontrol. Da vi bygger en webapplikation ved hjælp af Thymeleaf, har vi også brug for en HTML-skabelon til at fungere som en visning.

Dette vil være vores injicerbare @Service implementering af en @HystrixCommand med en tilknyttet tilbageførselsmetode. Denne tilbageførsel skal bruge den samme signatur som originalen:

@Service public class GreetingService {@HystrixCommand (fallbackMethod = "defaultGreeting") public String getGreeting (String username) {return new RestTemplate () .getForObject ("// localhost: 9090 / greeting / {username}", String.class, username ); } privat streng standardGreeting (streng brugernavn) {return "Hej bruger!"; }}

RestConsumerApplication vil være vores vigtigste applikationsklasse. Det @EnableCircuitBreaker annotation scanner klassestien for enhver kompatibel Circuit Breaker-implementering.

For at bruge Hystrix eksplicit skal vi kommentere denne klasse med @EnableHystrix:

@SpringBootApplication @EnableCircuitBreaker offentlig klasse RestConsumerApplication {public static void main (String [] args) {SpringApplication.run (RestConsumerApplication.class, args); }}

Vi opretter controlleren ved hjælp af vores HilsenService:

@Controller offentlig klasse GreetingController {@Autowired private GreetingService greetingService; @GetMapping ("/ get-greeting / {username}") public String getGreeting (Model model, @PathVariable ("username") String username) {model.addAttribute ("greeting", greetingService.getGreeting (username)); returner "hilsen-visning"; }}

Og her er HTML-skabelonen:

   Hilsner fra Hystrix 

For at sikre, at applikationen lytter til en defineret port, sætter vi følgende i en application.properties fil:

server.port = 8080

For at se en Hystix-afbryder i aktion starter vi vores forbruger og peger vores browser på // localhost: 8080 / get-greeting / Cid. Under normale omstændigheder vises følgende:

Hej Cid!

For at simulere en producents fiasko stopper vi det simpelthen, og når vi er færdige med at opdatere browseren, skal vi se en generisk besked, returneret fra reservemetoden i vores @Service:

Hej bruger!

4. REST Forbruger med Hystrix og Feign

Nu skal vi ændre projektet fra det foregående trin for at bruge Spring Netflix Feign som erklærende REST-klient i stedet for Spring RestTemplate.

Fordelen er, at vi senere er i stand til let at omlægge vores Feign Client-interface til at bruge Spring Netflix Eureka til serviceopdagelse.

For at starte det nye projekt laver vi en kopi af vores forbruger og tilføjer vores producent og spring-cloud-starter-feign som afhængigheder:

 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 kan vi bruge vores GreetingController at udvide en Feign-klient. Vi implementerer Hystrix tilbageførsel som en statisk indre klasse kommenteret med @Komponent.

Alternativt kunne vi definere en @Bønne annoteret metode, der returnerer en forekomst af denne reserveklasse.

Navnet egenskab af @FeignClient er obligatorisk. Det bruges til at slå op i applikationen enten ved opdagelse af tjenester via en Eureka-klient eller via URL, hvis denne egenskab er givet:

@FeignClient (name = "rest-producer" url = "// localhost: 9090", fallback = GreetingClient.GreetingClientFallback.class) offentlig grænseflade GreetingClient udvider GreetingController {@Component offentlig statisk klasse GreetingClientFallback implementerer GreetingController {@Override public String PathVariable ("brugernavn") String brugernavn) {returner "Hej bruger!"; }}}

For mere om brug af Spring Netflix Eureka til opdagelse af tjenester, se denne artikel.

I RestConsumerFeignApplication, sætter vi en yderligere kommentar for at muliggøre Feign-integration, faktisk @EnableFeignClients, til hovedapplikationsklassen:

@SpringBootApplication @EnableCircuitBreaker @EnableFeignClients public class RestConsumerFeignApplication {public static void main (String [] args) {SpringApplication.run (RestConsumerFeignApplication.class, args); }}

Vi vil ændre controlleren til at bruge en automatisk kablet Feign-klient snarere end den tidligere injicerede @Service, for at hente vores hilsen:

@Controller offentlig klasse GreetingController {@Autowired private GreetingClient greetingClient; @GetMapping ("/ get-greeting / {username}") public String getGreeting (Model model, @PathVariable ("username") String username) {model.addAttribute ("greeting", greetingClient.greeting (username)); returner "hilsen-visning"; }}

For at skelne dette eksempel fra det foregående ændrer vi applikationslytteporten i application.properties:

server.port = 8082

Endelig tester vi denne Feign-aktiverede forbruger som den fra det foregående afsnit. Det forventede resultat skal være det samme.

5. Cache Fallback With Hystrix

Nu skal vi tilføje Hystrix til vores Spring Cloud-projekt. I dette skyprojekt har vi en vurderingstjeneste, der taler til databasen og får vurderinger af bøger.

Lad os antage, at vores database er en ressource, der er efterspurgt, og dens svarlatens kan variere i tid eller måske ikke være tilgængelig i tider. Vi håndterer dette scenarie med Hystrix Circuit Breaker, der falder tilbage til en cache for dataene.

5.1. Opsætning og konfiguration

Lad os tilføje spring-cloud-starter-hystrix afhængighed af vores vurderingsmodul:

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

Når vurderinger indsættes / opdateres / slettes i databasen, replikerer vi det samme til Redis-cachen med en Datalager. For at lære mere om Redis, se denne artikel.

Lad os opdatere RatingService at pakke databaseforespørgselsmetoderne ind i en Hystrix-kommando med @HystrixCommand og konfigurer det med et tilbagefald til læsning fra Redis:

@HystrixCommand (commandKey = "ratingsByIdFromDB", fallbackMethod = "findCachedRatingById", ignoreExceptions = {RatingNotFoundException.class}) offentlig vurdering findRatingById (Long ratingId) {return Optional.ofNullable (ratingRepository.findOne (ratingId) () ny RatingNotFoundException ("Rating ikke fundet. ID:" + ratingId)); } offentlig vurdering findCachedRatingById (Long ratingId) {return cacheRepository.findCachedRatingById (ratingId); }

Bemærk, at reservemetoden skal have den samme signatur som en indpakket metode og skal opholde sig i samme klasse. Nu når findRatingById mislykkes eller bliver forsinket mere end en given tærskel, falder Hystrix tilbage til findCachedRatingById.

Da Hystrix-funktionerne indsprøjtes transparent som AOP-rådgivning, er vi nødt til at justere den rækkefølge, som rådgivningen er stablet i tilfælde af, hvis vi har andre råd som Spring's transaktionsrådgivning. Her har vi justeret forårets transaktions-AOP-rådgivning til at have lavere forrang end Hystrix AOP-rådgivning:

@EnableHystrix @EnableTransactionManagement (rækkefølge = Ordered.LOWEST_PRECEDENCE, mode = AdviceMode.ASPECTJ) offentlig klasse RatingServiceApplication {@Bean @Primary @Order (værdi = Ordered.HIGHEST_PRECEDENCE) offentlig HystrixCommandAspect hystrixAspectrix () kommando () returnering)) } // andre bønner, konfigurationer}

Her har vi justeret forårets AOP-rådgivning til at have lavere forrang end Hystrix AOP-rådgivning.

5.2. Test af Hystrix Fallback

Nu hvor vi har konfigureret kredsløbet, kan vi teste det ved at bringe H2-databasen ned, som vores lager samhandler med. Men lad os først køre H2-forekomsten som en ekstern proces i stedet for at køre den som en integreret database.

Lad os kopiere H2-biblioteket (h2-1.4.193.jar) til et kendt bibliotek og start H2-serveren:

> java -cp h2-1.4.193.jar org.h2.tools.Server -tcp TCP-server, der kører på tcp: //192.168.99.1: 9092 (kun lokale forbindelser)

Lad os nu opdatere vores moduls datakilde-URL i rating-service.properties at pege på denne H2-server:

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

Vi kan starte vores tjenester som beskrevet i vores forrige artikel fra Spring Cloud-serien og teste klassificeringer af hver bog ved at bringe den eksterne H2-forekomst, vi kører, ned.

Vi kunne se, at når H2-databasen ikke er tilgængelig, falder Hystrix automatisk tilbage til Redis for at læse klassificeringerne for hver bog. Kildekoden, der viser denne brugssag, kan findes her.

6. Brug af omfang

Normalt en @HytrixCommand annoteret metode udføres i en trådpulskontekst. Men nogle gange skal det køre i et lokalt omfang, for eksempel en @SessionScope eller a @RequestScope. Dette kan gøres ved at give argumenter til kommandobemærkningen:

@HystrixCommand (fallbackMethod = "getSomeDefault", commandProperties = {@HystrixProperty (navn = "udførelse.isolation.strategy", værdi = "SEMAPHORE")})

7. Hystrix Dashboard

En god valgfri funktion i Hystrix er evnen til at overvåge dens status på et dashboard.

For at aktivere det sætter vi spring-cloud-starter-hystrix-dashboard og fjeder-boot-starter-aktuator i pom.xml af vores forbruger:

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

Førstnævnte skal aktiveres via annotering af a @Konfiguration med @EnableHystrixDashboard og sidstnævnte aktiverer automatisk de krævede metrics i vores webapplikation.

Når vi har genstartet applikationen, peger vi en browser på // localhost: 8080 / hystrix, indtast metrics URL for en Hystrix-stream og begynd at overvåge.

Endelig skal vi se noget som dette:

Overvågning af en Hystrix-strøm er noget fint, men hvis vi skal se flere Hystrix-aktiverede applikationer, bliver det ubelejligt. Til dette formål leverer Spring Cloud et værktøj kaldet Turbine, som kan samle strømme til at blive præsenteret i et Hystrix-dashboard.

Konfiguration af turbine ligger uden for denne opskrivning, men muligheden skal nævnes her. Så det er også muligt at samle disse streams via messaging ved hjælp af Turbine stream.

8. Konklusion

Som vi hidtil har set, er vi nu i stand til at implementere Circuit Breaker-mønsteret ved hjælp af Spring Netflix Hystrix sammen med begge forår RestTemplate eller Spring Netflix Feign.

Dette betyder, at vi er i stand til at forbruge tjenester med inkluderet reserve ved hjælp af standarddata, og vi er i stand til at overvåge brugen af ​​disse data.

Som sædvanligt kan vi finde kilderne på GitHub.