Présentation de Spring Cloud Netflix - Eureka

1. Vue d'ensemble

Dans ce didacticiel, nous présenterons la découverte de services côté client via « Spring Cloud Netflix Eureka ».

La découverte de service côté client permet aux services de se trouver et de communiquer entre eux sans codage en dur du nom d'hôte et du port. Le seul «point fixe» dans une telle architecture consiste en un registre de services auprès duquel chaque service doit s'enregistrer.

Un inconvénient est que tous les clients doivent implémenter une certaine logique pour interagir avec ce point fixe. Cela suppose un aller-retour réseau supplémentaire avant la demande réelle.

Avec Netflix Eureka, chaque client peut agir simultanément en tant que serveur, pour répliquer son statut à un pair connecté. En d'autres termes, un client récupère une liste de tous les homologues connectés d'un registre de services et fait toutes les demandes supplémentaires à tous les autres services via un algorithme d'équilibrage de charge.

Pour être informé de la présence d'un client, il doit envoyer un signal de pulsation au registre.

Pour atteindre l'objectif de cet article, nous allons implémenter trois microservices :

  • un registre de services ( Eureka Server ),
  • un service REST qui s'enregistre au registre ( Eureka Client ) et
  • une application Web, qui consomme le service REST en tant que client prenant en charge le registre ( Spring Cloud Netflix Feign Client ).

2. Serveur Eureka

La mise en œuvre d'un serveur Eureka pour le registre de services est aussi simple que:

  1. ajout de spring-cloud-starter-netflix-eureka-server aux dépendances
  2. activer le serveur Eureka dans une @SpringBootApplication en l'annotant avec @EnableEurekaServer
  3. configurer certaines propriétés

Mais nous le ferons étape par étape.

Tout d'abord, nous allons créer un nouveau projet Maven et y placer les dépendances. Vous devez noter que nous importons le spring-cloud-starter-parent dans tous les projets décrits dans ce tutoriel:

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

Remarque: nous pouvons consulter les dernières versions de Spring Cloud dans la documentation des projets de Spring.

Ensuite, nous créons la classe d'application principale:

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

Enfin, nous configurons les propriétés au format YAML ; donc un fichier application.yml sera notre fichier de configuration:

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

Ici, nous configurons un port d'application - 8761 est celui par défaut pour les serveurs Eureka . Nous disons au client Eureka intégré de ne pas s'enregistrer sur «lui-même» car notre application doit agir en tant que serveur.

Nous allons maintenant pointer notre navigateur vers // localhost: 8761 pour afficher le tableau de bord Eureka , où nous inspecterons plus tard les instances enregistrées.

Pour le moment, nous voyons des indicateurs de base tels que les indicateurs d'état et de santé.

3. Client Eureka

Pour qu'une @SpringBootApplication soit sensible à la découverte, nous devons inclure un client Spring Discovery (par exemple spring-cloud-starter-netflix-eureka-client ) dans notre chemin de classe .

Ensuite, nous devons annoter une @Configuration avec @EnableDiscoveryClient ou @EnableEurekaClient - notez que cette annotation est facultative si nous avons la dépendance spring-cloud-starter-netflix-eureka-client sur le chemin de classe .

Ce dernier indique à Spring Boot d'utiliser explicitement Spring Netflix Eureka pour la découverte de services. Pour remplir notre application cliente avec un exemple de durée de vie, nous allons également inclure le package spring-boot-starter-web dans le pom.xml et implémenter un contrôleur REST .

Mais d'abord, nous ajouterons les dépendances. Encore une fois, nous pouvons laisser à la dépendance spring-cloud-starter-parent le soin de déterminer les versions d'artefact pour nous:

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

Ici, nous allons implémenter la classe d'application principale:

@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()); } }

Et l' interface GreetingController :

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

Ici, au lieu de l'interface, nous pourrions également simplement déclarer le mappage dans la classe EurekaClientApplication . L'interface peut être utile si nous voulons la partager entre le serveur et le client.

Ensuite, nous avons à mettre en place un application.yml avec une configuration Spring nom de l' application pour identifier notre client dans la liste des applications enregistrées.

Nous pouvons laisser Spring Boot choisir un port aléatoire pour nous car plus tard, nous accédons à ce service avec son nom.

Enfin, nous devons dire à notre client, où il doit localiser le registre:

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

Lorsque nous avons décidé de configurer notre client Eureka de cette manière, nous avons pensé que ce type de service devrait plus tard être facilement évolutif.

Maintenant, nous allons exécuter le client et pointer à nouveau notre navigateur vers // localhost: 8761 , pour voir son statut d'enregistrement sur le tableau de bord Eureka. En utilisant le tableau de bord, nous pouvons effectuer une configuration supplémentaire, par exemple lier la page d'accueil d'un client enregistré au tableau de bord à des fins administratives. Les options de configuration, cependant, sortent du cadre de cet article.

4. Feignez le client

Pour finaliser notre projet avec trois microservices dépendants, nous allons maintenant implémenter une application Web consommant REST à l' aide de Spring Netflix Feign Client .

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.

Enfin, nous avons une vue d'ensemble de l'utilisation de la découverte de services dans une architecture de microservices.

Comme d'habitude, vous trouverez les sources sur GitHub, qui comprend également un ensemble de fichiers liés à Docker à utiliser avec docker-compose pour créer des conteneurs à partir de notre projet.