Dans ce guide, vous apprendrez ce que sont les microservices Java, comment les concevoir et les créer. Il couvre également des questions sur les bibliothèques de microservices Java et la faisabilité de l'utilisation des microservices. Traduction et adaptation des microservices Java : un guide pratique .

Microservices Java : bases

Pour comprendre les microservices, vous devez d’abord définir ce qu’ils ne sont pas. N'est-ce pas un « monolithe » - Monolithe Java : qu'est-ce que c'est et quels sont ses avantages ou inconvénients ? Un guide des microservices Java.  Partie 1 : Bases et architecture des microservices - 1

Qu’est-ce qu’un monolithe Java ?

Imaginez que vous travaillez pour une banque ou une startup fintech. Vous fournissez aux utilisateurs une application mobile qu’ils peuvent utiliser pour ouvrir un nouveau compte bancaire. Dans le code Java, cela entraînera la présence d'une classe de contrôleur. En simplifié, cela ressemble à ceci :

@Controller
class BankController {

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        riskCheck(form);
        openBankAccount(form);
        // etc..
    }
}
Vous avez besoin du contrôleur pour :
  1. Confirmé le formulaire d'inscription.
  2. Vérification des risques liés à l'adresse de l'utilisateur pour décider de lui fournir ou non un compte bancaire.
  3. J'ai ouvert un compte bancaire.
La classe BankControllersera regroupée avec le reste de vos sources dans un fichier bank.jar ou bank.war pour le déploiement - il s'agit d'un bon vieux monolithe contenant tout le code nécessaire au fonctionnement de votre banque. À titre d'estimation approximative, la taille initiale d'un fichier .jar (ou .war) sera comprise entre 1 et 100 Mo. Vous pouvez désormais simplement exécuter le fichier .jar sur votre serveur... et c'est tout ce que vous devez faire pour déployer votre application Java. Un guide des microservices Java.  Partie 1 : Bases et architecture des microservices - 2Image, rectangle en haut à gauche : déploiement d'une banque mono(lithique) java -jar bank.jar (cp .war/.ear dans le serveur d'applications). Rectangle droit : ouvrez le navigateur.

Quel est le problème avec les monolithes Java ?

Il n’y a rien de mal en soi avec les monolithes Java. Cependant, l'expérience a montré que si dans votre projet :
  • De nombreux programmeurs/équipes/consultants travaillent...
  • ...sur le même monolithe sous la pression de clients aux exigences très vagues...
  • d'ici quelques années...
... alors dans ce cas, votre petit fichier bank.jar se transforme à lui seul en un immense gigaoctet de code, ce qui est effrayant même à approcher, et encore moins à déployer.

Comment réduire la taille d’un monolithe Java ?

Une question naturelle se pose : comment réduire la taille du monolithe ? À l'heure actuelle, votre bank.jar s'exécute sur une JVM, un processus sur un serveur. Ni plus ni moins. Et maintenant, une pensée logique peut me venir à l’esprit : « Mais le service de vérification des risques peut être utilisé par d’autres services de mon entreprise ! Ce n'est pas directement lié à mon application bancaire monolithique ! Peut-être devrait-il être découpé dans le monolithe et déployé en tant que produit distinct ? Autrement dit, techniquement parlant, il s’agit d’un processus Java distinct.

Qu'est-ce qu'un microservice Java ?

En pratique, cette phrase signifie que désormais l'appel de méthode riskCheck()ne sera plus effectué depuis BankController : cette méthode ou composant bean avec toutes ses classes auxiliaires sera déplacé vers son propre projet Maven ou Gradle. Il sera également déployé et placé sous contrôle de version indépendamment du monolithe bancaire. Cependant, l'ensemble de ce processus d'extraction ne transforme pas votre nouveau module RiskCheck en un microservice en soi, puisque la définition d'un microservice est sujette à interprétation. Cela conduit à des échanges fréquents au sein des équipes et des entreprises.
  • Est-ce que 5-7 classes sont dans un projet micro ou quoi ?
  • 100 ou 1000 cours... toujours du micro ?
  • Le microservice est-il généralement lié au nombre de classes ou non ?
Laissons de côté le raisonnement théorique et tenons-nous-en plutôt à des considérations pragmatiques et procédons comme suit :
  1. Appelons microservices tous les services déployés séparément, quelles que soient leur taille ou les limites de leur domaine.
  2. Réfléchissons à la manière d'organiser la communication interservices. Nos microservices ont besoin de moyens de communiquer entre eux.
Donc, pour résumer : auparavant, vous aviez un seul processus JVM, un monolithe solide pour gérer la banque. Vous disposez désormais d’un processus JVM monolithique bancaire et d’un microservice RiskCheck distinct qui s’exécute au sein de son propre processus JVM. Et maintenant, pour vérifier les risques, votre monolithe doit appeler ce microservice. Comment faire cela ?

Comment établir la communication entre les microservices Java ?

En général et en général, il existe deux options : la communication synchrone et asynchrone.

Communication synchrone : (HTTP)/REST

En règle générale, la communication synchronisée entre les microservices s'effectue via des services de type HTTP et REST qui renvoient XML ou JSON. Bien sûr, il peut y avoir d'autres options - prenez au moins les tampons de protocole Google . Si vous avez besoin d'une réponse immédiate, il est préférable d'utiliser la communication REST. Dans notre exemple, c’est exactement ce qu’il faut faire, puisqu’une vérification des risques est requise avant l’ouverture d’un compte. S’il n’y a pas de contrôle des risques, il n’y a pas de compte. Nous discuterons des outils ci-dessous, dans la section « Quelles bibliothèques sont les meilleures pour les appels Java REST synchrones ».

Messagerie - Communication asynchrone

La communication asynchrone par microservice est généralement réalisée en échangeant des messages avec une implémentation JMS et/ou en utilisant un protocole tel qu'AMQP . Nous avons écrit « généralement » ici pour une raison : disons que le nombre d’intégrations email/SMTP ne peut pas être sous-estimé. Utilisez-le lorsque vous n'avez pas besoin d'une réponse immédiate. Par exemple, l’utilisateur clique sur le bouton « acheter maintenant » et vous souhaitez à votre tour générer une facture. Ce processus ne devrait certainement pas avoir lieu dans le cycle demande-réponse d'achat de l'utilisateur. Nous décrirons ci-dessous quels outils sont les meilleurs pour la messagerie Java asynchrone .

Exemple : appel d'API REST en Java

Supposons que nous choisissions la communication synchrone par microservice. Dans ce cas, notre code Java (celui que nous avons présenté ci-dessus) à bas niveau ressemblera à ceci. (par bas niveau, nous entendons ici le fait que pour la communication par microservices, des bibliothèques clientes sont généralement créées pour vous abstraire des appels HTTP réels).

@Controller
class BankController {

    @Autowired
    private HttpClient httpClient;

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        httpClient.send(riskRequest, responseHandler());
        setupAccount(form);
        // etc..
    }
}
Sur la base du code, il devient clair que nous devons maintenant déployer deux (micro) services Java, Bank et RiskCheck. En conséquence, nous aurons deux processus JVM en cours d’exécution. Un guide des microservices Java.  Partie 1 : Bases et architecture des microservices - 3C'est tout ce dont vous avez besoin pour développer un projet de microservices Java : créez et déployez simplement des morceaux plus petits (fichiers .jar ou .war) au lieu d'un seul monolithique. La réponse à la question reste floue : comment découper le monolithe en microservices ? Quelle doit être la taille de ces pièces, comment déterminer la bonne taille ? Allons vérifier.

Architecture des microservices Java

En pratique, les entreprises développent des projets de microservices de différentes manières. L'approche dépend si vous essayez de transformer un monolithe existant en un projet de microservices ou si vous démarrez le projet à partir de zéro.

Du monolithe aux microservices

L’une des idées les plus logiques consiste à extraire des microservices d’un monolithe existant. Notez que le préfixe « micro » ici ne signifie pas réellement que les services extraits seront vraiment petits ; ce n'est pas nécessairement le cas. Examinons le contexte théorique.

Idée : diviser le monolithe en microservices

Une approche microservice peut être appliquée aux projets existants. Et c'est pourquoi:
  1. Le plus souvent, ces projets sont difficiles à maintenir/modifier/étendre.
  2. Tout le monde, des développeurs à la direction, souhaite la simplification.
  3. Vous avez des limites de domaine (relativement) claires, ce qui signifie que vous savez exactement ce que votre logiciel doit faire.
Pour revenir à notre exemple, cela signifie que vous pouvez examiner votre monolithe bancaire Java et essayer de le décomposer au-delà des frontières de domaine.
  • Il serait donc raisonnable de séparer le traitement des données utilisateur (telles que les noms, adresses, numéros de téléphone) dans un microservice distinct « Gestion des comptes ».
  • Ou le "Risk Checker Module" susmentionné qui vérifie les niveaux de risque de l'utilisateur et peut être utilisé par de nombreux autres projets ou même départements de l'entreprise.
  • Ou encore un module de facturation qui envoie les factures au format PDF ou par mail.

Mise en œuvre d’une idée : laisser quelqu’un d’autre le faire

L'approche décrite ci-dessus convient parfaitement aux diagrammes papier et de type UML. Pourtant, tout n’est pas si simple. Sa mise en œuvre pratique nécessite une préparation technique sérieuse : l'écart entre notre compréhension de ce qu'il serait agréable d'extraire d'un monolithe et le processus d'extraction lui-même est énorme. La plupart des projets d'entreprise atteignent un stade où les développeurs ont peur, par exemple, de mettre à niveau une version d'Hibernate vieille de 7 ans vers une version plus récente. Les bibliothèques seront mises à jour en même temps, mais il existe un réel danger de casser quelque chose. Ces mêmes développeurs doivent donc désormais fouiller dans du code ancien avec des limites de transaction de base de données peu claires et extraire des microservices bien définis ? Le plus souvent, ce problème est très complexe et ne peut être « résolu » sur un tableau blanc ou lors de réunions d’architecture. Un guide des microservices Java.  Partie 1 : Bases et architecture des microservices - 4Pour citer le développeur Twitter @simonbrown : je le répéterai encore et encore... si les gens ne peuvent pas construire correctement des monolithes, les microservices ne seront d'aucune aide. Simon Brun

Projet à partir de zéro basé sur une architecture de microservices

Dans le cas de nouveaux projets Java, les trois points numérotés de la partie précédente semblent légèrement différents :
  1. Vous commencez avec une table rase, il n’y a donc pas de « bagage » à entretenir.
  2. Les développeurs aimeraient garder les choses simples à l'avenir.
  3. Problème : Vous avez une image beaucoup plus floue des limites de domaine : vous ne savez pas ce que votre logiciel est réellement censé faire (indice : agile ;))
Cela conduit les entreprises à essayer de nouveaux projets avec des microservices Java.

Architecture technique des microservices

Le premier point semble être le plus évident pour les développeurs, mais il y a aussi ceux qui le déconseillent fortement. Hadi Hariri recommande le refactoring « Extract Microservice » dans IntelliJ. Et bien que l’exemple suivant soit très simplifié, les implémentations observées dans des projets réels ne s’en éloignent malheureusement pas trop. Avant les microservices

@Service
class UserService {

    public void register(User user) {
        String email = user.getEmail();
        String username =  email.substring(0, email.indexOf("@"));
        // ...
    }
}
Avec microservice Java de sous-chaîne

@Service
class UserService {

    @Autowired
    private HttpClient client;

    public void register(User user) {
        String email = user.getEmail();
        //теперь вызываем substring microservice via http
        String username =  httpClient.send(substringRequest(email), responseHandler());
        // ...
    }
}
Vous enveloppez donc essentiellement un appel de méthode Java dans un appel HTTP, sans raison évidente. Cependant, l'une des raisons est la suivante : le manque d'expérience et la tentative d'imposer une approche de microservices Java. Recommandation : ne faites pas cela.

Architecture de microservices orientée workflow

La prochaine approche courante consiste à diviser les microservices Java en modules basés sur des workflows. Exemple concret : en Allemagne, lorsque vous vous rendez chez un médecin (public), celui-ci doit enregistrer votre visite dans son système CRM médical. Pour obtenir le paiement de l'assurance, il enverra des données sur votre traitement (et celui des autres patients) à l'intermédiaire via XML. Le courtier examinera ce fichier XML et (simplifié) :
  1. Vérifie si le fichier XML correct est reçu.
  2. Il vérifiera la plausibilité des procédures : par exemple, un enfant d'un an qui a subi trois nettoyages de dents en une journée par un gynécologue semble quelque peu suspect.
  3. Combinera XML avec d'autres données bureaucratiques.
  4. Enverra le fichier XML à la compagnie d'assurance pour initier les paiements.
  5. Et il transmettra le résultat au médecin, en lui fournissant le message « succès » ou « veuillez renvoyer cet enregistrement dès que cela aura du sens ».
Note. Dans cet exemple, la communication entre les microservices ne joue aucun rôle, mais pourrait très bien être effectuée de manière asynchrone par un courtier de messages (par exemple RabbitMQ), puisque le médecin ne reçoit de toute façon pas de retour immédiat. Un guide des microservices Java.  Partie 1 : Bases et architecture des microservices - 5Encore une fois, cela semble bien sur le papier, mais des questions naturelles se posent :
  • Est-il nécessaire de déployer six applications pour traiter un fichier XML ?
  • Ces microservices sont-ils vraiment indépendants les uns des autres ? Peuvent-ils être déployés indépendamment les uns des autres ? Avec différentes versions et schémas d'API ?
  • Que fait le microservice de plausibilité des informations si le microservice de vérification ne fonctionne pas ? Le système fonctionne-t-il toujours ?
  • Ces microservices partagent-ils la même base de données (ils ont certainement besoin de données communes dans les tables de la base de données), ou ont-ils chacun les leurs ?
  • … et beaucoup plus.
Il est intéressant de noter que le diagramme ci-dessus semble plus simple car chaque service a désormais son propre objectif précis et bien défini. Auparavant, cela ressemblait à ce monolithe effrayant : Un guide des microservices Java.  Partie 1 : Bases et architecture des microservices - 6même si vous pouvez contester la simplicité de ces diagrammes, vous devez absolument maintenant résoudre ces défis opérationnels supplémentaires.
  • Vous n'avez pas besoin de déployer une seule application, mais au moins six.
  • Vous devrez peut-être même déployer plusieurs bases de données, en fonction du degré auquel vous souhaitez aller dans l'architecture des microservices.
  • Vous devez vous assurer que chaque système est en ligne et fonctionne correctement.
  • Vous devez vous assurer que vos appels entre microservices sont réellement résilients (voir Comment rendre un microservice Java résilient ?).
  • Et tout ce que cette configuration implique : des paramètres de développement local aux tests d’intégration.
La recommandation serait donc :
  • Si vous n'êtes pas Netflix (il y a de fortes chances que vous n'êtes pas Netflix)...
  • À moins que vous n'ayez de très bonnes compétences professionnelles dans lesquelles vous ouvrez l'environnement de développement et cela provoque un singe du chaos qui jette votre base de données de production qui est facilement restaurée en 5 secondes.
  • ou vous vous sentez comme @monzo et êtes prêt à essayer 1 500 microservices simplement parce que vous le pouvez.
→ Ne fais pas ça. Et maintenant, c’est moins hyperbolique. Essayer de modéliser des microservices au-delà des frontières de domaine semble tout à fait raisonnable. Mais cela ne signifie pas que vous devez prendre un flux de travail et le diviser en petites parties individuelles (recevoir du XML, valider du XML, transmettre du XML). Par conséquent, chaque fois que vous démarrez un nouveau projet avec des microservices Java et que les limites du domaine sont encore très vagues, essayez de maintenir la taille de vos microservices à un niveau bas. Vous pourrez toujours ajouter d'autres modules ultérieurement. Et assurez-vous que vous disposez d'un DevOps avancé dans l'équipe/l'entreprise/la division pour prendre en charge votre nouvelle infrastructure.

Architecture de microservices polyglotte ou orientée équipe

Il existe une troisième approche, presque libertaire, pour développer des microservices : permettre à des équipes ou même à des individus de mettre en œuvre des user stories en utilisant un nombre illimité de langages ou de microservices (les spécialistes du marketing appellent cette approche « programmation polyglotte »). Ainsi, le service de validation XML décrit ci-dessus pourrait être écrit en Java, tandis que le microservice de validation pourrait en même temps être écrit en Haskell (pour le rendre mathématiquement valable). Pour le microservice de transfert d'assurance, vous pouvez utiliser Erlang (car il a vraiment besoin d'évoluer ;)). Ce qui peut paraître amusant du point de vue d'un développeur (développer le système parfait avec votre langage parfait dans un environnement isolé) n'est en fait jamais ce que souhaite l'organisation : l'homogénéisation et la standardisation. Cela signifie un ensemble relativement standardisé de langages, de bibliothèques et d'outils afin que d'autres développeurs puissent continuer à prendre en charge votre microservice Haskell à l'avenir lorsque vous passerez à des pâturages plus verts. Un guide des microservices Java.  Partie 1 : Bases et architecture des microservices - 8L’histoire montre que la normalisation s’enracine généralement trop profondément. Par exemple, les développeurs de grandes entreprises Fortune 500 n'étaient parfois même pas autorisés à utiliser Spring parce que cela « ne faisait pas partie de la feuille de route technologique de l'entreprise ». Cependant, une transition complète vers l’approche polyglotte est presque la même chose, le revers de la même médaille. Recommandation : si vous envisagez d'utiliser une programmation polyglotte, essayez moins de variété au sein du même écosystème de langage de programmation. Il est donc préférable d'utiliser Kotlin et Java ensemble (les deux langages sont basés sur la JVM et sont 100 % compatibles entre eux), plutôt que Java et, disons, Haskell. Dans la partie suivante, vous découvrirez le déploiement et le test des microservices Java.