Java et les microservices
Photo de Robert MODOUX sur Unsplash

Cet article est le premier d’une série abordant les concepts de la nouvelle machine virtuelle GraalVM.

Nous allons aborder ici des notions de bases sur les microservices, sur Java et sa JVM HotSpot. Cela nous donnera une première idée sur l’adéquation de Java au monde des conteneurs et notammement des microservices.



Qu’est-ce qu’un microservice ?

On peut, pour les plus vieux d’entre nous, considérer les microservices comme le prolongement du concept de SOA (Architecture Orientée Service) avec l’avènement du cloud.

Un microservice peut se caractériser comme étant :

  • Un service conçu pour gĂ©rer une seule fonctionnalitĂ© (par exemple, la gestion des utilisateurs)
  • Elastique, c’est Ă  dire facilement scalable. Ceci implique un dĂ©ploiement rapide, un service lĂ©ger, tout cela, dans un conteneur, voire dans le Cloud.
  • AutomatisĂ©, du processus de build jusqu’au dĂ©ploiement. GĂ©nĂ©ralement, il est maintenu par une Ă©quipe dĂ©diĂ©e et rĂ©duite, avec des tests automatisĂ©s pour dĂ©ployer rapidement une nouvelle version.

Microservice vs FaaS

FaaS, pour Functions-as-a-Service, va un peu plus loin dans ce concept, en ajoutant les notions de « serverless » (l’infrastructure nécessaire au service est de la responsabilité du fournisseur) et « sans état » (cher à la programmation fonctionnelle, x -> f(x), toujours !)


Qu’est-ce que Java ?

Tout le monde connait Java ! Un langage interprété par une JVM et portable sur différents systèmes. Révisons tout de même quelques notions sur son fonctionnement interne pour bien en saisir la portée.

Le fonctionnement de la JVM


L’interprétation

Les étapes de l'interprétation du Bytecode par la JVM
Les étapes de l'interprétation du Bytecode par la JVM
  1. La JVM est un exécutable qui lit du bytecode puis l’interprète.
  2. Le bytecode est dans des packages .jar sous forme de fichiers .class
  3. La JVM recherche le fichier .class dans les packages .jar, vérifie le fichier .class puis le charge
  4. Une fois que le bytecode est chargé, la JVM peut l’exécuter (le semi-interpréter)

Exécuter du bytecode a donc un coût :

  • Le bytecode est recherchĂ©, vĂ©rifiĂ© puis interprĂ©tĂ© par la JVM qui elle-mĂŞme s’exĂ©cute sur le processeur.

Le compilateur Just-In-Time (JIT)

Les Ă©tapes de l'optimisation JIT du Bytecode par la JVM
Les Ă©tapes de l'optimisation JIT du Bytecode par la JVM

1.  Lors de l’exécution d’une méthode Java, le compilateur C1 de JIT (just-in-time, à la volée) va la compiler en code natif et le Profiler va commencer à recueillir des informations sur son utilisation.

C1 est un compilateur léger et rapide mais il ne produit pas du code natif optimisé.

2.  Losrque le profiler détecte une méthode très utilisée, « Hot », le compilateur C2 va se servir des informations du Profiler pour produire un code natif, agressif, optimisé et très bien adapté au contexte d’utilisation.

C2 est un compilateur lourd et lent mais il produit un code natif très bien optimisé et très rapide.

Il y a en réalité un cycle entre la compilation C1 et C2. Le compilateur C2 va souvent recompiler des morceaux de bytecode avec de nouvelles informations provenant du profiler pour produire un binaire toujours plus optimal.

3.  Au bout d’un certain temps, lorsque de nombreux morceaux de bytecode auront été compilés par le compilateur C2, l’application Java fonctionnera très rapidement.

  • Il faut donc un temps de chauffe, « warm-up », Ă  une application Java pour ĂŞtre pleinement rĂ©active.
  • C’est un rĂ©el problème pour un microservice qui doit pouvoir ĂŞtre dĂ©ployĂ© et opĂ©rationnel très rapidement.

L’empreinte mémoire

Architecture générale de la JVM
Les différentes couches mises en jeu dans une JVM
Les différentes couches mises en jeu dans une JVM

Lorsque l’on regarde l’architecture générale d’une JVM, on ne peut que constater qu’il y a beaucoup de composants. On voit aussi que son espace mémoire est compartimenté.

Concentrons-nous sur 2 d’entre eux.

Détail de 2 espaces mémoires
Détails de 2 espaces mémoires de la JVM
Détails de 2 espaces mémoires de la JVM

La JVM alloue de la mémoire pour l’application mais aussi pour ses propres métadonnées et son fonctionnement :

  1. Le « Java Heap » stocke les instances des objets Java. Il est divisé en 2 parties : le « Young Generation » qui contient les objets récemment créés et le « Tenured Generation » qui contient lui des objets qui ont résisté au ramasse-miettes (« Garbage Collector »).

  2. Le « Metaspace » (anciennement «PermGen») contient les métadonnées des classes (le bytecode des méthodes, les symboles, les «constant pools», les annotations…).

  • Pour une application de 10Mo, la JVM occupe souvent une taille de 100Mo.
  • LĂ  encore, c’est un problème pour un microservice qui doit avoir une empreinte mĂ©moire la plus petite possible.

Le fonctionnement des Frameworks Java

Il est, à present, usuel d’embarquer plusieurs frameworks dans une application Java afin de simplifier certains aspects techniques ou bien d’organiser ses couches applicatives.

Prenons le cas de 2 frameworks, sans doute, les plus utilisés dans le monde Java : Spring et Hibernate.

Voici ce qu’une application Java qui utilise ces frameworks, va exécuter à son démarrage :

  1. Lecture et parsing des fichiers de configuration,
  2. Scanne complet des classes pour récupérer les métadonnées (annotations, accesseurs,…),
  3. Création d’un métamodèle,
  4. Préparation de la réflexion,
  5. Création des proxies (beaucoup de proxies !),…

Ce sont pourtant des frameworks très utilisés par les développeurs et, en réalité, très bien adaptés aux applications monolithiques.

  • Les frameworks Java amplifient les problèmes de temps de dĂ©marrage et de consommation mĂ©moire de la JVM.

On fait comment à présent ?

Pour résumer

Nous avons vu les problèmes de Java :

  • Consommation importante de la mĂ©moire
  • NĂ©cessitĂ© d’un temps de chauffe au dĂ©marrage
  • Optimisation du code natif au fil de l’eau

A priori, tout ce qu’il ne faut pas pour un microservice.

Alors, que fait-on à présent ? On oublie Java et on se met tous au C++ ??

Rien de tout cela bien sûr. La réponse dans l’article suivant présentant GraalVM. Et vous allez voir que ça déménage !

Cheers…

Jean-Jerome Levy

Ecrit par

Jean-JĂ©rĂ´me LĂ©vy

Consultant DevOps

Professionnel chevronné dans le domaine de l’informatique, cumulant plus de 20 années d’expérience au sein de DSI de grandes entreprises, mon expertise diversifiée m’a permis de jouer un rôle clé dans de nombreux projets, caractérisés par la mise en place de pratiques DevOps innovantes.