Comment Quarkus combine programmation impérative et réactive

Cette année, nous prévoyons de développer sérieusement des thèmes de conteneurs, Java cloud natif и Kubernetes. Une suite logique de ces sujets sera une histoire sur le framework Quarkus, déjà considéré sur Habré. L'article d'aujourd'hui porte moins sur la conception du "Java subatomique ultra-rapide" que sur la promesse que Quarkus apporte à Enterprise.

Comment Quarkus combine programmation impérative et réactive

Java et la JVM sont toujours extrêmement populaires, mais lorsque l'on travaille avec des technologies sans serveur et des microservices cloud natifs, Java et d'autres langages JVM sont de moins en moins utilisés car ils occupent trop d'espace mémoire et sont trop lents à charger, ce qui les rend mal adapté à une utilisation avec des conteneurs à durée de vie courte. Heureusement, cette situation commence maintenant à changer grâce à Quarkus.

Java subatomique ultra-rapide a atteint un nouveau niveau !

42 versions, 8 mois de travail communautaire et 177 développeurs incroyables - le résultat de tout cela a été la sortie en novembre 2019 Quarkus1.0, une version qui marque une étape importante dans le développement du projet et offre de nombreuses fonctionnalités et capacités intéressantes (vous pouvez en savoir plus à leur sujet dans annonce).

Aujourd'hui, nous allons vous montrer comment Quarkus combine des modèles de programmation impératifs et réactifs en un seul noyau réactif. Nous commencerons par un bref historique, puis entrerons dans les détails sur ce qu'est le dualisme réactif de Quarkus et comment Java-Les développeurs peuvent profiter de ces avantages.

Microservices, architectures événementielles и sans serveur-fonctions – tout cela est, comme on dit, en augmentation aujourd’hui. Récemment, la création d'architectures centrées sur le cloud est devenue beaucoup plus facile et accessible, mais des problèmes subsistent, notamment pour les développeurs Java. Par exemple, dans le cas des fonctions et des microservices sans serveur, il existe un besoin urgent de réduire le temps de démarrage, de réduire la consommation de mémoire, tout en rendant leur développement plus pratique et plus agréable. Java a apporté plusieurs améliorations ces dernières années, telles que des fonctionnalités ergonomiques améliorées pour les conteneurs, etc. Cependant, faire fonctionner Java correctement dans un conteneur reste un défi. Nous allons donc commencer par examiner certaines des complexités inhérentes à Java, qui sont particulièrement aiguës lors du développement d'applications Java orientées conteneurs.

Tout d’abord, regardons l’histoire.

Comment Quarkus combine programmation impérative et réactive

Flux et conteneurs

À partir de la version 8u131, Java a commencé à prendre plus ou moins en charge les conteneurs en raison des améliorations apportées aux fonctionnalités ergonomiques. En particulier, la JVM sait désormais sur combien de cœurs de processeur elle s'exécute et peut configurer les pools de threads (généralement des pools de fork/join) en conséquence. Bien sûr, c'est génial, mais disons que nous avons une application Web traditionnelle qui utilise des servlets HTTP et s'exécute dans Tomcat, Jetty, etc. En conséquence, cette application attribuera à chaque requête un thread distinct et lui permettra de bloquer ce thread en attendant les opérations d'E/S, par exemple lors de l'accès à la base de données, aux fichiers ou à d'autres services. Autrement dit, la taille d'une telle application ne dépend pas du nombre de cœurs disponibles, mais du nombre de requêtes simultanées. De plus, cela signifie que les quotas ou les limites dans Kubernetes sur le nombre de cœurs ne seront pas d'une grande aide ici, et l'affaire finira par aboutir à une limitation.

Épuisement de la mémoire

Les fils sont de la mémoire. Et les limitations de mémoire intra-conteneur ne sont en aucun cas une panacée. Commencez simplement à augmenter le nombre d'applications et de threads, et tôt ou tard, vous rencontrerez une augmentation critique de la fréquence de commutation et, par conséquent, une dégradation des performances. De plus, si votre application utilise des frameworks de microservices traditionnels, ou se connecte à une base de données, ou utilise la mise en cache, ou utilise de la mémoire d'une autre manière, vous avez évidemment besoin d'un outil qui vous permet de regarder à l'intérieur de la JVM et de voir comment elle gère la mémoire sans la tuer. JVM elle-même (par exemple, XX:+UseCGroupMemoryLimitForHeap). Et même si, depuis Java 9, la JVM a appris à accepter les groupes de contrôle et à s'adapter en conséquence, réserver et gérer la mémoire reste une affaire assez complexe.

Quotas et limites

Java 11 a introduit la prise en charge des quotas de processeur (comme PreferContainerQuotaForCPUCount). Kubernetes offre également une prise en charge des limites et des quotas. Oui, tout cela a du sens, mais si l'application dépasse à nouveau le quota alloué, nous nous retrouvons à nouveau avec une taille - comme c'est le cas pour les applications Java traditionnelles - déterminée par le nombre de cœurs et avec l'attribution d'un thread séparé pour chacun. demande, alors tout cela n’a pas de sens.
De plus, si vous utilisez des quotas et des limites ou les fonctions scale-out de la plateforme sous-jacente à Kubernetes, le problème ne se résout pas non plus. Nous dépensons simplement plus de ressources pour résoudre le problème initial ou finissons par dépenser trop. Et s’il s’agit d’un système à forte charge dans un cloud public, nous finissons presque certainement par utiliser plus de ressources que ce dont nous avons réellement besoin.

Et que faire de tout ça ?

Pour faire simple, utilisez des bibliothèques et des frameworks d'E/S asynchrones et non bloquants comme Netty, Vert.x ou Akka. Ils sont bien mieux adaptés au travail dans des conteneurs en raison de leur nature réactive. Grâce aux E/S non bloquantes, le même thread peut traiter plusieurs requêtes simultanées. Pendant qu'une requête attend les résultats d'E/S, le thread qui la traite est libéré et repris par une autre requête. Et lorsque les résultats des E/S arrivent enfin, le traitement de la première requête se poursuit. Grâce au traitement entrelacé des requêtes au sein du même thread, vous pouvez réduire le nombre total de threads et réduire la consommation de ressources pour le traitement des requêtes.

Avec les E/S non bloquantes, le nombre de cœurs devient un paramètre clé car il détermine le nombre de threads d'E/S pouvant être exécutés en parallèle. Lorsqu'il est utilisé correctement, cela vous permet de répartir efficacement la charge entre les cœurs et de gérer des charges de travail plus élevées avec moins de ressources.

Comment, c'est tout ?

Non, il y a autre chose. La programmation réactive permet de mieux utiliser les ressources, mais a également un prix. Il faudra notamment réécrire le code selon les principes de non-blocage et éviter de bloquer les threads d'E/S. Et c’est un modèle de développement et d’exécution complètement différent. Et bien qu’il existe ici de nombreuses bibliothèques utiles, cela représente toujours un changement radical dans la façon de penser habituelle.

Tout d’abord, vous devez apprendre à écrire du code qui s’exécute de manière asynchrone. Une fois que vous commencez à utiliser les E/S non bloquantes, vous devez spécifier explicitement ce qui doit se passer lorsqu'une réponse à une requête est reçue. Le simple blocage et l'attente ne fonctionneront plus. Au lieu de cela, vous pouvez transmettre des rappels, utiliser une programmation réactive ou une continuation. Mais ce n'est pas tout : pour utiliser des E/S non bloquantes, il faut à la fois des serveurs et des clients non bloquants, de préférence partout. Dans le cas du HTTP, tout est simple, mais il existe également des bases de données, des systèmes de fichiers et bien plus encore.

Et même si une réactivité totale de bout en bout maximise l’efficacité, un tel changement peut être difficile à supporter en pratique. Ainsi, la capacité à combiner code réactif et impératif devient un prérequis afin de :

  1. Utiliser efficacement les ressources dans les zones les plus chargées du système logiciel ;
  2. Utilisez un code de style plus simple dans ses parties restantes.

Présentation de Quarkus

En fait, c'est l'essence de Quarkus : combiner des modèles réactifs et impératifs dans un seul environnement d'exécution.

Quarkus est basé sur Vert.x et Netty, avec une gamme de frameworks et d'extensions réactifs pour aider le développeur. Quarkus est conçu pour créer non seulement des microservices HTTP, mais également des architectures basées sur les événements. De par son caractère réactif, il fonctionne très efficacement avec les messageries (Apache Kafka, AMQP…).

L'astuce consiste à savoir comment utiliser le même moteur réactif pour le code impératif et réactif.

Comment Quarkus combine programmation impérative et réactive

Quarkus le fait avec brio. Le choix entre impératif et réactif est évident : utilisez un noyau réactif pour les deux. Ce que cela aide vraiment, c'est un code rapide et non bloquant qui gère presque tout ce qui passe par le thread de boucle d'événements, alias le thread IO. Mais si vous disposez d'applications REST classiques ou côté client, Quarkus dispose d'un modèle de programmation impératif. Par exemple, le support HTTP dans Quarkus repose sur l'utilisation d'un moteur non bloquant et réactif (Eclipse Vert.x et Netty). Toutes les requêtes HTTP reçues par votre application sont d'abord passées dans une boucle d'événements (IO Thread) puis envoyées à la partie du code qui gère les requêtes. Selon la destination, le code de gestion des requêtes peut être appelé dans un thread distinct (appelé thread de travail, utilisé dans le cas des servlets et Jax-RS) ou utiliser le thread d'E/S source (route réactive).

Comment Quarkus combine programmation impérative et réactive

Les connecteurs du système de messagerie utilisent des clients non bloquants exécutés sur le moteur Vert.x. Par conséquent, vous pouvez envoyer, recevoir et traiter efficacement des messages à partir de systèmes middleware de messagerie.

Le site Quarkus.io Voici quelques bons tutoriels pour vous aider à démarrer avec Quarkus :

Nous avons également créé des didacticiels pratiques en ligne pour vous enseigner divers aspects de la programmation réactive dans un simple navigateur, sans IDE ni ordinateur requis. Vous pouvez retrouver ces leçons ici.

Ressources utiles

10 leçons vidéo sur Quarkus pour se familiariser avec le sujet

Comme on dit sur le site Quarkus.io, quarkus - Est KubernetesPile Java orientée, adaptée pour GraalVM et OpenJDK HotSpot et assemblée à partir des meilleures bibliothèques et normes Java.

Pour vous aider à comprendre le sujet, nous avons sélectionné 10 didacticiels vidéo qui couvrent divers aspects de Quarkus et des exemples de son utilisation :

1. Présentation de Quarkus : le framework Java de nouvelle génération pour Kubernetes

Par Thomas Qvarnstrom et Jason Greene
L'objectif du projet Quarkus est de créer une plate-forme Java pour Kubernetes et les environnements sans serveur, et de combiner des modèles de programmation réactifs et impératifs dans un environnement d'exécution unique afin que les développeurs puissent varier leur approche de manière flexible lorsqu'ils travaillent avec un large éventail d'architectures d'applications distribuées. Découvrez-en davantage dans la conférence d’introduction ci-dessous.

2. Quarkus : Java subatomique ultra-rapide

Par : Burr Sutter
Ce didacticiel vidéo de DevNation Live montre comment utiliser Quarkus pour optimiser les applications Java d'entreprise, les API, les microservices et les fonctions sans serveur dans un environnement Kubernetes/OpenShift, les rendant beaucoup plus petits, plus rapides et plus évolutifs.

3. Quarkus et GraalVM : accélérer Hibernate à des vitesses élevées et le réduire à des tailles subatomiques

Auteur : Sanne Grinovero
À partir de la présentation, vous apprendrez comment Quarkus est né, comment il fonctionne et comment il vous permet de créer des bibliothèques complexes, comme Hibernate ORM, compatibles avec les images GraalVM natives.

4. Apprenez à développer des applications sans serveur

Auteur : Martin Luther
La vidéo ci-dessous montre comment créer une application Java simple à l'aide de Quarkus et la déployer en tant qu'application sans serveur sur Knative.

5. Quarkus : Amusez-vous à coder

Auteur : Edson Yanaga
Un guide vidéo pour créer votre premier projet Quarkus, vous permettant de comprendre pourquoi Quarkus gagne le cœur des développeurs.

6. Java et conteneurs : quel sera leur avenir ensemble

Publié par Mark Little
Cette présentation présente l'histoire de Java et explique pourquoi Quarkus est l'avenir de Java.

7. Quarkus : Java subatomique ultra-rapide

Auteur : Dimitris Andreadis
Un aperçu des avantages de Quarkus qui ont été reconnus par les développeurs : simplicité, vitesses ultra-élevées, meilleures bibliothèques et standards.

8. Quarkus et systèmes de fusées subatomiques

Auteur : Clément Escoffier
Grâce à l'intégration avec GraalVM, Quarkus offre une expérience de développement ultra-rapide et un environnement d'exécution subatomique. L'auteur parle du côté réactif de Quarkus et de la manière de l'utiliser pour créer des applications réactives et en streaming.

9. Quarkus et développement rapide d'applications dans Eclipse MicroProfile

Auteur : John Clingan
En combinant Eclipse MicroProfile et Quarkus, les développeurs peuvent créer des applications MicroProfile conteneurisées complètes qui se lancent en quelques dizaines de millisecondes. La vidéo explique en détail comment coder une application MicroProfile conteneurisée pour un déploiement sur la plateforme Kubernetes.

10. Java, version "Turbo"

Auteur : Marcus Bienne
L'auteur montre comment utiliser Quarkus pour créer des conteneurs Java ultra-petits et ultra-rapides qui permettent de véritables avancées, en particulier dans les environnements sans serveur.



Source: habr.com

Ajouter un commentaire