Ein Leitfaden für Spring Cloud Netflix - Hystrix

Ein Leitfaden für Spring Cloud Netflix - Hystrix

1. Überblick

In diesem Tutorial werden dieSpring Cloud Netflix Hystrix - die Fehlertoleranzbibliothek - behandelt. Wir werden die Bibliothek verwenden und das Unternehmensmuster vonCircuit Breakerimplementieren, das eine Strategie gegen das Kaskadieren von Fehlern auf verschiedenen Ebenen in einer Anwendung beschreibt.

Das Prinzip ist analog zur Elektronik:Hystrix überwacht Methoden, um Anrufe bei verwandten Diensten fehlzuschlagen. Wenn ein solcher Fehler auftritt, wird der Stromkreis geöffnet und der Anruf an eine Fallback-Methode weitergeleitet.

Die Bibliothek toleriert Ausfälle bis zu einem bestimmten Schwellenwert. Darüber hinaus bleibt der Stromkreis offen. Das bedeutet, dass alle nachfolgenden Aufrufe an die Fallback-Methode weitergeleitet werden, um zukünftige Fehler zu vermeiden. This creates a time buffer for the related service to recover from its failing state.

2. REST Produzent

Um ein Szenario zu erstellen, das dasCircuit Breaker-Muster demonstriert, benötigen wir zuerst einen Service. Wir nennen es "REST Producer", da es Daten für die Hystrix-fähigen "REST Consumer" liefert, die wir im nächsten Schritt erstellen werden.

Erstellen wir ein neuesMaven-Projekt unter Verwendung derspring-boot-starter-web-abhängigkeit:


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

Das Projekt selbst ist bewusst einfach gehalten. Es besteht aus einer Controller-Schnittstelle mit einer mit@RequestMapping kommentierten GET-Methode, die einfach einString,, ein@RestController, das diese Schnittstelle implementiert, und ein@SpringBootApplication zurückgibt.

Wir beginnen mit der Benutzeroberfläche:

public interface GreetingController {
    @GetMapping("/greeting/{username}")
    String greeting(@PathVariable("username") String username);
}

Und die Umsetzung:

@RestController
public class GreetingControllerImpl implements GreetingController {

    @Override
    public String greeting(@PathVariable("username") String username) {
        return String.format("Hello %s!\n", username);
    }
}

Als Nächstes schreiben wir die Hauptanwendungsklasse auf:

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

Um diesen Abschnitt zu vervollständigen, müssen Sie nur noch einen Anwendungsport konfigurieren, den wir abhören werden. Der Standardport 8080 wird nicht verwendet, da der Port für die im nächsten Schritt beschriebene Anwendung reserviert bleiben sollte.

Darüber hinaus definieren wir einen Anwendungsnamen, um unsereREST Producerin der Client-Anwendung nachschlagen zu können, die wir später einführen werden. Erstellen wir einapplication.properties mit folgendem Inhalt:

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

Jetzt können wir unsere "REST Producer" mit curl testen:

$> curl http://localhost:9090/greeting/Cid
Hello Cid!

3. REST Verbraucher mitHystrix

Für unser Demonstrationsszenario implementieren wir eine Webanwendung, die den DienstRESTaus dem vorherigen Schritt mitRestTemplate undHystrix verwendet. Der Einfachheit halber nennen wir es "REST Consumer".


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


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


    org.springframework.boot
    spring-boot-starter-thymeleaf
    1.4.0.RELEASE

DamitCircuit Breaker funktioniert, durchsuchtHystix die mit Anmerkungen versehenen Klassen von@Component or @Servicenach mit Anmerkungen versehenen Methoden von@HystixCommand, implementiert einen Proxy dafür und überwacht seine Aufrufe.

Wir werden zuerst eine@Service-Klasse erstellen, die in eine@Controller eingefügt wird. Da wirweb-application using Thymeleaf, erstellen, benötigen wir auch eine HTML-Vorlage als Ansicht.

Dies sind unsere injizierbaren@Service, die ein@HystrixCommand mit einer zugehörigen Fallback-Methode implementieren. Für diesen Fallback muss dieselbe Signatur wie für das Original verwendet werden:

@Service
public class GreetingService {
    @HystrixCommand(fallbackMethod = "defaultGreeting")
    public String getGreeting(String username) {
        return new RestTemplate()
          .getForObject("http://localhost:9090/greeting/{username}",
          String.class, username);
    }

    private String defaultGreeting(String username) {
        return "Hello User!";
    }
}

RestConsumerApplication wird unsere Hauptanwendungsklasse sein. Die Annotation@EnableCircuitBreakerdurchsucht den Klassenpfad nach kompatiblen Implementierungen vonCircuit Breaker.

UmHystrix explizit zu verwenden, müssen Sie diese Klasse mit@EnableHystrix versehen:

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

Wir richten den Controller mit unserenGreetingService ein:

@Controller
public class GreetingController {

    @Autowired
    private GreetingService greetingService;

    @GetMapping("/get-greeting/{username}")
    public String getGreeting(Model model, @PathVariable("username") String username) {
        model.addAttribute("greeting", greetingService.getGreeting(username));
        return "greeting-view";
    }
}

Und hier ist die HTML-Vorlage:



    
        Greetings from Hystrix
    
    
        

Um sicherzustellen, dass die Anwendung einen definierten Port überwacht, fügen wir Folgendes in eineapplication.properties-Datei ein:

server.port=8080

Um einen Hystix-Leistungsschalter in Aktion zu sehen, starten wir unsereREST Consumer und zeigen unseren Browser aufhttp://localhost:8080/get-greeting/Cid. Unter normalen Umständen wird Folgendes angezeigt:

Hello Cid!

Um einen Fehler unserer "REST Producer" zu simulieren, stoppen wir ihn einfach. Nach Abschluss der Aktualisierung des Browsers sollte eine generische Meldung angezeigt werden, die von der Fallback-Methode in unseren@Service zurückgegeben wird:

Hello User!

4. REST Verbraucher mitHystrix undFeign

Jetzt werden wir das Projekt aus dem vorherigen Schritt so ändern, dassSpring Netflix Feign als deklarativer REST-Client anstelle von SpringRestTemplate verwendet wird.

Der Vorteil ist, dass wir später unsere Feign-Client-Oberfläche einfach umgestalten können, umSpring Netflix Eureka für die Serviceerkennung zu verwenden.

Um das neue Projekt zu starten, erstellen wir eine Kopie unserer "REST Consumer" und fügen die "REST Producer" undspring-cloud-starter-feignals Abhängigkeiten hinzu:


    com.example.spring.cloud
    spring-cloud-hystrix-rest-producer
    1.0.0-SNAPSHOT


    org.springframework.cloud
    spring-cloud-starter-feign
    1.1.5.RELEASE

Jetzt können wir unsereGreetingController verwenden, um einen Feign-Client zu erweitern. Wir implementieren den Fallback vonHystrixals statische innere Klasse, die mit@Component versehen ist.

Alternativ könnten wir eine mit@Beanannotierte Methode definieren, die eine Instanz dieser Fallback-Klasse zurückgibt.

Die Eigenschaft name von@FeignClient ist obligatorisch. Es wird verwendet, um die Anwendung entweder durch Diensterkennung überEureka Client oder über URL nachzuschlagen, wenn diese Eigenschaft angegeben ist. Weitere Informationen zur Verwendung von Spring Netflix Eureka für die Serviceerkennung finden Sie unterat this article:

@FeignClient(
  name = "rest-producer"
  url = "http://localhost:9090",
  fallback = GreetingClient.GreetingClientFallback.class
)
public interface GreetingClient extends GreetingController {

    @Component
    public static class GreetingClientFallback implements GreetingController {

        @Override
        public String greeting(@PathVariable("username") String username) {
            return "Hello User!";
        }
    }
}

InRestConsumerFeignApplication werden wir eine zusätzliche Anmerkung einfügen, um die Integration vonFeign, tatsächlich@EnableFeignClients, in die Hauptanwendungsklasse zu ermöglichen:

@SpringBootApplication
@EnableCircuitBreaker
@EnableFeignClients
public class RestConsumerFeignApplication {

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

Wir werden den Controller so ändern, dass anstelle der zuvor injizierten@Service ein automatisch verdrahteter Feign-Client verwendet wird, um unsere Begrüßung abzurufen:

@Controller
public class GreetingController {
    @Autowired
    private GreetingClient greetingClient;

    @GetMapping("/get-greeting/{username}")
    public String getGreeting(Model model, @PathVariable("username") String username) {
        model.addAttribute("greeting", greetingClient.greeting(username));
        return "greeting-view";
    }
}

Um dieses Beispiel vom vorherigen zu unterscheiden, ändern wir den Anwendungs-Listening-Port inapplication.properties:

server.port=8082

Schließlich werden wir dieseFeign-fähigen "REST Consumer" wie im vorherigen Abschnitt testen. Das erwartete Ergebnis sollte dasselbe sein.

5. Cache Fallback mitHystrix

Jetzt werden wir Hystrix zu unseremSpring Cloud-Projekt hinzufügen. In diesem Cloud-Projekt haben wir einen Bewertungsservice, der mit der Datenbank kommuniziert und Bewertungen von Büchern abruft.

Nehmen wir an, dass unsere Datenbank eine nachgefragte Ressource ist und ihre Antwortlatenz zeitlich variieren kann oder zeitlich nicht verfügbar ist. Wir werden dieses Szenario behandeln, indemHystrixCircuit-Breaker auf einen Cache für die Daten zurückgreifen.

5.1. Setup und Konfiguration

Fügen wir die Abhängigkeit vonspring-cloud-starter-hystrixzu unserem Bewertungsmodul hinzu:


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

Wenn Bewertungen in die Datenbank eingefügt / aktualisiert / gelöscht werden, replizieren wir diese mit einemRepository in den Redis-Cache. Wenn Sie mehr über Redis erfahren möchten, aktivieren Siethis article.

Aktualisieren Sie dieRatingService, um die Datenbankabfragemethoden in einen Hystrix-Befehl mit@HystrixCommand zu verpacken, und konfigurieren Sie sie mit einem Fallback zum Lesen aus Redis:

@HystrixCommand(
  commandKey = "ratingsByIdFromDB",
  fallbackMethod = "findCachedRatingById",
  ignoreExceptions = { RatingNotFoundException.class })
public Rating findRatingById(Long ratingId) {
    return Optional.ofNullable(ratingRepository.findOne(ratingId))
      .orElseThrow(() ->
        new RatingNotFoundException("Rating not found. ID: " + ratingId));
}

public Rating findCachedRatingById(Long ratingId) {
    return cacheRepository.findCachedRatingById(ratingId);
}

Beachten Sie, dass die Fallback-Methode dieselbe Signatur wie eine umschlossene Methode haben und sich in derselben Klasse befinden muss. Wenn nunfindRatingById ausfällt oder mehr als einen bestimmten Schwellenwert verzögert wird, fälltHystrix auffindCachedRatingById. zurück

Da die Funktionen vonHystrixtransparent als Ratschläge vonAOPeingefügt werden, müssen wir die Reihenfolge anpassen, in der die Ratschläge gestapelt sind, falls wir andere Ratschläge wie den Transaktionsrat von Spring haben. Hier haben wir die Transaktions-AOP-Empfehlung des Frühlings so angepasst, dass sie eine niedrigere Priorität hat als die Empfehlung vonHystrix AOP:

@EnableHystrix
@EnableTransactionManagement(
  order=Ordered.LOWEST_PRECEDENCE,
  mode=AdviceMode.ASPECTJ)
public class RatingServiceApplication {
    @Bean
    @Primary
    @Order(value=Ordered.HIGHEST_PRECEDENCE)
    public HystrixCommandAspect hystrixAspect() {
        return new HystrixCommandAspect();
    }

    // other Beans, Configurations
}

Hier haben wir den Ratschlag vonSpring’sder TransaktionAOPo angepasst, dass er eine niedrigere Priorität hat als der Ratschlag vonHystrix AOP.

5.2. Testen von Hystrix Fallback

Nachdem wir die Schaltung konfiguriert haben, können wir sie testen, indem wir dieH2-Datenbank herunterfahren, mit der unser Repository interagiert. Lassen Sie uns zunächst die Instanz vonH2als externe Prozesse ausführen, anstatt sie als eingebettete Datenbank auszuführen.

Kopieren wir dieH2 library (h2-1.4.193.jar) in ein bekanntes Verzeichnis und starten den H2-Server:

>java -cp h2-1.4.193.jar org.h2.tools.Server -tcp
TCP server running at tcp://192.168.99.1:9092 (only local connections)

Aktualisieren wir die Datenquellen-URL unseres Moduls inrating-service.properties, um auf diesen H2-Server zu verweisen:

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

Wir können unsere Dienste wie in unseren vorherigenarticle aus der Spring-Cloud-Reihe angegeben starten und die Bewertungen jedes Buches testen, indem wir die von uns ausgeführte externe H2-Instanz herunterfahren.

Wir konnten sehen, dassHystrix automatisch aufRedis zurückgreift, wenn die DatenbankH2nicht erreichbar ist, um die Bewertungen für jedes Buch zu lesen. Der Quellcode, der diesen Anwendungsfall demonstriert, befindet sich inhere.

6. Bereiche verwenden

Normalerweise wird die mit Anmerkungen versehene Methode@HytrixCommandin einem Thread-Pool-Kontext ausgeführt. Manchmal muss es jedoch in einem lokalen Bereich ausgeführt werden, z. B.@SessionScope oder@RequestScope. Dies kann durch Angabe von Argumenten für die Befehlsanmerkung erfolgen:

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

7. DasHystrix Dashboard

Eine nette optionale Funktion vonHystrix ist die Möglichkeit, den Status auf einem Dashboard zu überwachen.

Um dies zu aktivieren, fügen wirspring-cloud-starter-hystrix-dashboard undspring-boot-starter-actuator in die pom.xml unserer "REST Consumer" ein:


    org.springframework.cloud
    spring-cloud-starter-hystrix-dashboard
    1.1.5.RELEASE


    org.springframework.boot
    spring-boot-starter-actuator
    1.4.0.RELEASE

Ersteres muss durch Annotieren von@Configuration mit@EnableHystrixDashboard aktiviert werden, und letzteres aktiviert automatisch die erforderlichen Metriken in unserer Webanwendung.

Nach dem Neustart der Anwendung zeigen wir einen Browser aufhttp://localhost:8080/hystrix, geben die Metrik-URL eineshystrix.stream ein und beginnen mit der Überwachung.

Schließlich sollten wir so etwas sehen:

image

Das Überwachen eineshystrix.stream ist in Ordnung, aber wenn Sie mehrereHystrix-fähige Anwendungen ansehen müssen, wird dies unpraktisch. Zu diesem Zweck bietetSpring Cloud ein Tool namensTurbine, mit dem Streams inHystrix Dashboard zusammengefasst werden können.

Die Konfiguration vonTurbine würde den Rahmen dieses Aufsatzes sprengen, aber die Möglichkeit sollte hier erwähnt werden. Es ist also auch möglich, diese Streams mithilfe vonTurbine Stream per Messaging zu erfassen.

8. Fazit

Wie wir bisher gesehen haben, können wir jetzt dasCircuit Breaker-Muster mithilfe vonSpring Netflix Hystrix zusammen mitSpring RestTemplate oderSpring Netflix Feign implementieren.

Dies bedeutet, dass wir Services mit eingeschlossenem Fallback mithilfe von statischen oder Standarddaten nutzen und die Verwendung dieser Daten überwachen können.

Wie üblich finden Sie die Quellen aufGitHub.