Microservice : la découverte automatique de services

Le dernier billet de ce blog entamait une mini-série sur les microservices qui espère traiter des sujets suivants :

  • comment gérer une fédération d’identité (one login to rule them all)
  • gérer une configuration distribuée
  • le routage
  • le load balancing
  • dispatcher des évènements sur plusieurs services
  • les jobs
  • la découverte de services
  • simplifier l’écriture des appels de services
  • la composition de page
  • la résistance aux pannes
  • le monitoring
  • le déploiement

Le dernier billet s’attardait sur la composition de page. Pour ce billet, nous allons parler de « service discovery », la découverte de service pour les francophones.

Comme je l’évoquais dans le billet précédent, une architecture en micro services implique l’utilisation de plusieurs services qui apparaissent comme un seul service pour l’utilisateur final. Par exemple le visiteur sur Hopwork voit un seul domaine avec de multiples pages, la recherche, les annonces d’emploi, la page d’accueil qui sont en réalité plusieurs applications web sur le serveur :

microservice

 

Parmi les intérêts de ce type de solution, vous pouvez augmenter le nombre de services qui vont gérer la recherche et laisser les autres inchangé. Si tout avait été dans la même application, vous auriez du dupliquer l’ensemble de votre bloc applicatif alors qu’une grande partie ne le nécessite sans doute pas.

microservices

 

La problématique qui se pose alors, c’est de pouvoir ajouter un nouveau service de type « search », qu’il soit automatiquement découvert par le reste de l’applicatif et que les requêtes lui parviennent.

Si vous utilisiez nginx, vous pourriez déjà avoir un système de load balancing sur vos différents services de search préalablement configuré. Ceci vous impose cependant de relancer nginx. Il existe malgré tout une solution de reconfiguration à chaud pour nginx PLUS.

Si vous avez aussi une configuration inter micro services, une solution à base de nginx vous pousserait également à placer un frontal nginx devant chaque grappe de service. Envisageable, mais sans doute un peu pénible. Et dans ce cas de figure, nginx devient un spof (single point of failure). Il vous faut alors envisager de mettre en place de la haute disponibilité sur chaque frontal nginx pour chaque grappe de microservice.

Ca serait envisageable mais nous allons voir une autre approche, toujours avec les outils de netflix qui ont été intégrés dans Spring Cloud.

Eureka

Eureka est un composant utilisé par Netflix en tant que, je cite, « AWS Service registry for resilient mid-tier load balancing and failover ». Et en réalité ce n’est pas restreint à AWS.

C’est donc un outil qui va permettre de réaliser de la découverte de service et que vous allez interroger pour avoir des informations sur les applications qui rendent un service donné.

eureka

La cinématique est donc la suivante :

  • pour chaque service, inscription auprès d’Eureka en tant que fournisseur d’un service X
  • pour chaque consommateur de service :
    • récupération au démarrage puis périodiquement de la liste des fournisseurs pour chaque service
    • appel direct vers un fournisseur

Pour bien clarifier, le consommateur de service n’appelle pas Eureka à chaque fois qu’il a besoin de réaliser un appel vers un fournisseur de service !

La liste des fournisseurs de service est mise à jour périodiquement à travers un « heartbeat » communiqué à l’ensemble des clients Eureka. Mais un client peut très bien tomber sur un fournisseur down à un instant T.

Mais c’est pas un SPOF tout ça ?

Eh bien Eureka est lui-même un fournisseur de service et peut donc lui-même s’enregistrer auprès d’autres serveurs eureka pour former un cluster de serveur Eureka. C’est bien sûr la configuration recommandée pour tourner en production.

Mise en oeuvre

Avant de démarrer, vous pouvez retrouver l’ensemble des sources disponible ici : https://github.com/hlassiege/microservice-sandbox/tree/master/discovery

Sur ce repo github, nous avons 3 applications :

  • le serveur Eureka
  • un fournisseur de service
  • un client du service fourni

Pour le serveur Eureka, il ne s’agit que d’un main avec deux annotations spécifiques à Eureka :

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

Pour le fournisseur de service, l’annotation devient :

@EnableEurekaClient

Par contre il faut bien préciser l’url du serveur eureka et le nom du service proposé dans le fichier de configuration :

server.port: 8081

eureka:
  instance:
    leaseRenewalIntervalInSeconds: 10
  client:
    registryFetchIntervalSeconds: 5
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

spring.application.name: service1

Enfin le client du service qui est également un EurekaClient utilise la même annotation :

@EnableEurekaClient

Et pour nous assurer que tout fonctionne, nous allons créer un endpoint pour afficher l’adresse d’un fournisseur de service déclaré dans le registre Eureka :

@Autowired
private DiscoveryClient discoveryClient;

@RequestMapping("/")
public String serviceUrl() {
    InstanceInfo instance = discoveryClient.getNextServerFromEureka("service1", false);
    return instance.getHomePageUrl();
}

Une fois toutes les applications lancées, vous pouvez retrouver la page de Eureka sur http://localhost:8761

eurekaui

Vous noterez donc que 3 services sont enregistrés car le serveur et le client sont aussi des fournisseurs de services.

Et vous avez un nouvel endpoint http://localhost:8761/eureka/apps/ qui vous donne la liste des services enregistrés ainsi que toutes les instances de fournisseur déclarés. Par exemple pour moi ici :

  
    SERVICE1
    
      hugo_pro
      SERVICE1
      192.168.50.1
      UP
      UNKNOWN
      8081
      443
      1
      
        MyOwn
      
      
        10
        90
        1430824522750
        1430824522750
        0
        1430824492689
      
      
      http://hugo_pro:8081/
      http://hugo_pro:8081/info
      http://hugo_pro:8081/health
      service1
      false
      1430824522750
      1430824522656
      ADDED
    
  

Voilà, nous avons fait une petite introduction à Eureka. Pour l’instant nous allons en rester là mais nous allons voir par la suite comment combiner Eureka et Zuul pour faire du loadbalancing. Puis nous verrons comment utiliser Eureka pour faire des appels Rest.
C’est loin d’être fini 🙂


Also published on Medium.

 

hlassiege