Einführung in Spring Cloud Netflix - Eureka

1. Übersicht

In diesem Tutorial stellen wir die clientseitige Serviceerkennung über „ Spring Cloud Netflix Eureka “ vor.

Mit der clientseitigen Diensterkennung können Dienste ohne feste Codierung von Hostname und Port suchen und miteinander kommunizieren. Der einzige "feste Punkt" in einer solchen Architektur besteht aus einer Dienstregistrierung, bei der sich jeder Dienst registrieren muss.

Ein Nachteil ist, dass alle Clients eine bestimmte Logik implementieren müssen, um mit diesem Fixpunkt zu interagieren. Dies setzt eine zusätzliche Netzwerk-Roundtrip vor der eigentlichen Anforderung voraus.

Mit Netflix Eureka kann jeder Client gleichzeitig als Server fungieren, um seinen Status auf einen verbundenen Peer zu replizieren. Mit anderen Worten, ein Client ruft eine Liste aller verbundenen Peers einer Dienstregistrierung ab und stellt alle weiteren Anforderungen über einen Lastausgleichsalgorithmus an andere Dienste.

Um über die Anwesenheit eines Clients informiert zu werden, muss dieser ein Heartbeat-Signal an die Registrierung senden.

Um das Ziel dieses Aufsatzes zu erreichen, werden wir drei Microservices implementieren :

  • eine Serviceregistrierung ( Eureka Server ),
  • ein REST- Service, der sich bei der Registrierung registriert ( Eureka Client ) und
  • Eine Webanwendung, die den REST- Service als registrierungsbewussten Client verwendet ( Spring Cloud Netflix Feign Client ).

2. Eureka Server

Die Implementierung eines Eureka-Servers für die Serviceregistrierung ist so einfach wie:

  1. Hinzufügen von Spring-Cloud-Starter-Netflix-Eureka-Server zu den Abhängigkeiten
  2. Aktivieren Sie den Eureka-Server in einer @ SpringBootApplication, indem Sie ihn mit @ EnableEurekaServer kommentieren
  3. Konfigurieren Sie einige Eigenschaften

Aber wir werden es Schritt für Schritt tun.

Zuerst erstellen wir ein neues Maven-Projekt und fügen die Abhängigkeiten ein. Sie müssen beachten, dass wir das Spring-Cloud-Starter-Parent in alle in diesem Tutorial beschriebenen Projekte importieren :

 org.springframework.cloud spring-cloud-starter-netflix-eureka-server     org.springframework.cloud spring-cloud-starter-parent Greenwich.RELEASE pom import   

Hinweis: Wir können die neuesten Spring Cloud-Versionen in der Dokumentation zu Spring's Projects überprüfen.

Als Nächstes erstellen wir die Hauptanwendungsklasse:

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

Schließlich konfigurieren wir die Eigenschaften im YAML- Format. Eine application.yml ist also unsere Konfigurationsdatei:

server: port: 8761 eureka: client: registerWithEureka: false fetchRegistry: false

Hier konfigurieren wir einen Anwendungsport - 8761 ist der Standardport für Eureka- Server. Wir weisen den integrierten Eureka-Client an, sich nicht bei "sich selbst" zu registrieren, da unsere Anwendung als Server fungieren sollte.

Jetzt zeigen wir unseren Browser auf // localhost: 8761, um das Eureka- Dashboard anzuzeigen , in dem wir später die registrierten Instanzen überprüfen werden.

Derzeit sehen wir grundlegende Indikatoren wie Status- und Gesundheitsindikatoren.

3. Eureka Client

Damit eine @ SpringBootApplication Discovery- fähig ist , müssen wir einen Spring Discovery-Client (z. B. Spring-Cloud-Starter-Netflix-Eureka-Client ) in unseren Klassenpfad aufnehmen.

Dann müssen wir eine @Configuration entweder mit @EnableDiscoveryClient oder @EnableEurekaClient mit Anmerkungen versehen. Beachten Sie, dass diese Anmerkung optional ist, wenn die Spring-Cloud-Starter-Netflix-Eureka-Client- Abhängigkeit vom Klassenpfad besteht.

Letzteres weist Spring Boot an, Spring Netflix Eureka explizit für die Serviceerkennung zu verwenden. Um unsere Client-Anwendung mit einigen Beispielen zu füllen, werden wir auch das Spring-Boot-Starter-Web- Paket in die pom.xml aufnehmen und einen REST- Controller implementieren .

Aber zuerst fügen wir die Abhängigkeiten hinzu. Auch hier können wir es der Abhängigkeit von Spring-Cloud-Starter-Parent überlassen , die Artefaktversionen für uns herauszufinden:

 org.springframework.cloud spring-cloud-starter-netflix-eureka-starter   org.springframework.boot spring-boot-starter-web 

Hier implementieren wir die Hauptanwendungsklasse:

@SpringBootApplication @RestController public class EurekaClientApplication implements GreetingController { @Autowired @Lazy private EurekaClient eurekaClient; @Value("${spring.application.name}") private String appName; public static void main(String[] args) { SpringApplication.run(EurekaClientApplication.class, args); } @Override public String greeting() { return String.format( "Hello from '%s'!", eurekaClient.getApplication(appName).getName()); } }

Und die GreetingController- Oberfläche:

public interface GreetingController { @RequestMapping("/greeting") String greeting(); }

Hier können wir anstelle der Schnittstelle auch einfach die Zuordnung innerhalb der EurekaClientApplication- Klasse deklarieren . Die Schnittstelle kann nützlich sein, wenn wir sie zwischen Server und Client teilen möchten.

Als Nächstes müssen wir eine application.yml mit einem konfigurierten Spring- Anwendungsnamen einrichten , um unseren Client in der Liste der registrierten Anwendungen eindeutig zu identifizieren.

Wir können Spring Boot einen zufälligen Port für uns auswählen lassen , da wir später mit seinem Namen auf diesen Dienst zugreifen.

Schließlich müssen wir unserem Kunden mitteilen, wo er die Registrierung finden muss:

spring: application: name: spring-cloud-eureka-client server: port: 0 eureka: client: serviceUrl: defaultZone: ${EUREKA_URI://localhost:8761/eureka} instance: preferIpAddress: true

Als wir beschlossen, unseren Eureka-Client auf diese Weise einzurichten, hatten wir vor Augen, dass diese Art von Service später leicht skalierbar sein sollte.

Jetzt führen wir den Client aus und zeigen unseren Browser erneut auf // localhost: 8761 , um den Registrierungsstatus im Eureka-Dashboard anzuzeigen. Mithilfe des Dashboards können wir weitere Konfigurationen vornehmen, z. B. die Homepage eines registrierten Clients zu Verwaltungszwecken mit dem Dashboard verknüpfen. Die Konfigurationsoptionen gehen jedoch über den Rahmen dieses Artikels hinaus.

4. Kunden vortäuschen

Um unser Projekt mit drei abhängigen Microservices abzuschließen, werden wir jetzt eine REST- konsumierende Webanwendung mit Spring Netflix Feign Client implementieren .

Think of Feign as discovery-aware SpringRestTemplate using interfaces to communicate with endpoints. This interfaces will be automatically implemented at runtime and instead of service-urls, it is using service-names.

Without Feign we would have to autowire an instance of EurekaClient into our controller with which we could receive a service-information by service-name as an Application object.

We would use this Application to get a list of all instances of this service, pick a suitable one and use this InstanceInfo to get hostname and port. With this, we could do a standard request with any http client.

For example:

@Autowired private EurekaClient eurekaClient; public void doRequest() { Application application = eurekaClient.getApplication("spring-cloud-eureka-client"); InstanceInfo instanceInfo = application.getInstances().get(0); String hostname = instanceInfo.getHostName(); int port = instanceInfo.getPort(); // ... }

A RestTemplate can also be used to access Eureka client-services by name, but this topic is beyond this write-up.

To set up our Feign Client project, we're going to add the following four dependencies to its pom.xml:

 org.springframework.cloud spring-cloud-starter-feign   org.springframework.cloud spring-cloud-starter-netflix-eureka-client   org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-thymeleaf 

The Feign Client is located in the spring-cloud-starter-feign package. To enable it, we have to annotate a @Configuration with @EnableFeignClients. To use it, we simply annotate an interface with @FeignClient(“service-name”) and auto-wire it into a controller.

A good method to create such FeignClients is to create interfaces with @RequestMapping annotated methods and put them into a separate module. This way they can be shared between server and client. On server-side, you can implement them as @Controller, and on client-side, they can be extended and annotated as @FeignClient.

Furthermore, the spring-cloud-starter-eureka package needs to be included in the project and enabled by annotating the main application class with @EnableEurekaClient.

The spring-boot-starter-web and spring-boot-starter-thymeleaf dependencies are used to present a view, containing fetched data from our REST service.

This will be our Feign Client interface:

@FeignClient("spring-cloud-eureka-client") public interface GreetingClient { @RequestMapping("/greeting") String greeting(); }

Here we will implement the main application class which simultaneously acts as a controller:

@SpringBootApplication @EnableFeignClients @Controller public class FeignClientApplication { @Autowired private GreetingClient greetingClient; public static void main(String[] args) { SpringApplication.run(FeignClientApplication.class, args); } @RequestMapping("/get-greeting") public String greeting(Model model) { model.addAttribute("greeting", greetingClient.greeting()); return "greeting-view"; } } 

This will be the HTML template for our view:

   Greeting Page   

At least the application.yml configuration file is almost the same as in the previous step:

spring: application: name: spring-cloud-eureka-feign-client server: port: 8080 eureka: client: serviceUrl: defaultZone: ${EUREKA_URI://localhost:8761/eureka}

Now we can build and run this service. Finally, we'll point our browser to //localhost:8080/get-greeting and it should display something like the following:

Hello from SPRING-CLOUD-EUREKA-CLIENT!

5. ‘TransportException: Cannot Execute Request on Any Known Server'

While running Eureka server we often run into exceptions like:

com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server

Basically, this happens due to the wrong configuration in application.properties or application.yml. Eureka provides two properties for the client that can be configurable.

  • registerWithEureka: If we make this property as true then while the server starts the inbuilt client will try to register itself with the Eureka server.
  • fetchRegistry: The inbuilt client will try to fetch the Eureka registry if we configure this property as true.

Now when we start up the Eureka server, we don't want to register the inbuilt client to configure itself with the server.

If we mark the above properties as true (or don't configure them as they're true by default) while starting the server, the inbuilt client tries to register itself with the Eureka server and also tries to fetch registry which is not yet available. As a result, we get TransportException.

So we should never configure these properties as true in the Eureka server applications. The correct settings that should be put in application.yml are given below:

eureka: client: registerWithEureka: false fetchRegistry: false

6. Conclusion

As we've seen, we're now able to implement a service registry using Spring Netflix Eureka Server and register some Eureka Clients with it.

Because our Eureka Client from step 3 listens on a randomly chosen port, it doesn't know its location without the information from the registry. With a Feign Client and our registry, we can locate and consume the REST service, even when the location changes.

Schließlich haben wir ein umfassendes Bild der Verwendung der Serviceerkennung in einer Microservice-Architektur.

Wie üblich finden Sie die Quellen auf GitHub, das auch eine Reihe von Docker- bezogenen Dateien enthält, die Sie mit Docker-Compose verwenden können , um Container aus unserem Projekt zu erstellen.