Publié le 24/01/2019 Par Soufiane ZENIOU

L’utilisation et la gestion d’event dans les systèmes distribués (ou pas) est de plus en plus courante. Soufiane nous présente la librairie Vert.x qui permet le transport et le dispatch des événements de votre système. Pour la visite c’est par ici !!

Avez-vous déjà entendu parler de Vert.x ? Non ? Dans ce cas, vous êtes au bon endroit pour le découvrir ! Dans ce qui suit, vous trouverez l’essentiel pour commencer à développer avec ce toolkit de programmation asynchrone.

Le pattern Reactor

Vert.x utilise principalement le pattern Reactor. Ce pattern est une des implémentations de l’architecture orientée événements.

On distingue deux éléments clés dans ce pattern :

  • Reactor : il réagit aux événements en les dispatchant vers les handlers correspondants, il s’exécute dans un thread séparé.
  • Event handlers : ils effectuent le traitement sur les événements.

Dans ce pattern, une event loop est utilisée et s’exécute dans un thread unique. Ce mécanisme bloque les ressources émettant des événements afin de les distribuer aux handlers correspondants. Ainsi, les I/O ne devraient pas bloquer du moment que des handlers adéquats sont enregistrés pour les traiter.

En d’autres termes, le pattern Reactor permet aux applications orientées événements de démultiplexer d’une manière synchrone et de dispatcher selon l’ordre d’arrivée des événements depuis un ou plusieurs clients, aux handlers correspondants. Un événement peut être une requête, une nouvelle connexion… Ce modèle de conception a pour but d’éviter le problème de création d’un thread pour chaque requête/connexion.

NB : en électronique, un démultiplexeur est un circuit qui a une entrée et plusieurs sorties.

Qu’est-ce que Vert.x ?

  1. Vert.x est un toolkit qui permet de développer des applications réactives qui s’exécutent dans une JVM. Il a été créé par Tim Fox en 2011 sous le nom de Node.x et est devenu par la suite Vert.x en 2012.
  2. Vert.x est maintenant un projet de la fondation Eclipse. Le Core de ce toolkit propose une API de base pour développer des applications asynchrones. Le fait qu’il soit modulaire permet de choisir les modules adéquats pour chaque application (par exemple, l’API asynchrone de connexion à la BDD). En interne, Vert.x est basé sur la libraire Netty qui est une librairie réseau asynchrone très performante.
  3. Vert.x est polyglotte, on peut écrire des applications avec la plupart des langages supportés par la JVM. Citons-en quelques-uns : Java, Groovy, Scala, Kotlin, JavaScript, Ruby et Ceylon.

Quels sont les concepts de base ?

Les concepts de base sont le Verticle et l’Event bus.

Le Verticle

Pour faire simple, le Verticle est l’unité (le composant de base) de déploiement de Vert.x. Le verticle réalise le traitement des événements sur l’event loop. En effet, l’event loop vérifie l’arrivée des nouveaux événements et fait intervenir le verticle correspondant pour les traiter. Le traitement doit être effectué dans un laps de temps court afin de ne pas bloquer cet event loop. Dans le cas d’événements bloquants comme les IO, Vert.x propose aux développeurs un autre mécanisme en dehors de l’event loop (les workers). A une event loop est associé un thread. Par défaut, Vert.x associe deux event loops par CPU, ce qui fait que chaque verticle traite les événements dans le même thread, d’où l’absence de besoin de synchronisation. Le verticle peut être déployé en plusieurs instances. Dans ce cas, les événements seront distribués en round robin aux verticles.

PS : Les workers sont des verticles dédiés pour traiter les opérations bloquantes. Chaque worker s’exécute dans un thread séparé et différent de celui de l’event loop.

L’Event bus

C’est le système nerveux de Vert.x. Chaque instance de Vert.x est associée à une instance de l’event bus. L’event bus assure la communication entre des verticles de la même instance ou d’une autre instance. La communication se fait en utilisant des messages asynchrones. Les messages sont envoyés à des adresses. Le format d’échange privilégié dans l’event bus est le JSON. Cependant, d’autres formats sont supportés. Les messages sont reçus dans des handlers enregistrés à une adresse particulière. L’event bus supporte trois modes de communication :

  • Le point à point : les messages sont envoyés à une adresse. Vert.x les acheminera ensuite au handler enregistré à cette adresse.
  • La requête / réponse : les messages sont envoyés à une adresse. Vert.x les acheminera ensuite au handler enregistré à cette adresse. Le récepteur peut répondre à l’émetteur du message. Dans ce cas, un handler de réponse est appelé. L’émetteur peut répondre à nouveau. Ce mécanisme peut se répéter indéfiniment, permettant un dialogue entre deux verticles.
  • Le publish / subscribe : les messages sont publiés à une adresse. Ces messages seront ensuite livrés à tous les handlers enregistrés à cette adresse.

D’accord, et l’architecture ?

L’architecture de Vert.x peut être schématisée de la manière suivante :

Il est temps pour un peu de code ^^, n’est-ce pas ?

Commençons par créer un projet dont la structure est la suivante :

De mon côté, j’ai utilisé Maven et Intellij mais vous pouvez utiliser d’autres outils similaires.

Comme j’utilise Maven, le fichier pom.xml est utilisé pour configurer le projet.

Ici, le fichier “pom.xml” est simple, il contient :

  • La déclaration d’une dépendance à “vertx-core”,
  • Un plugin de compilation configuré pour utiliser le JDK 8,

Important : Vert.x nécessite au minimum Java 8.

Comment implémenter un Verticle ?


Un verticle est une classe qui étend io.vertx.core.AbstractVerticle. En héritant de cette classe, on peut accéder au champ vertx et à l’instance vertx sur laquelle ce verticle est déployée.

La méthode start() est appelée par Vert.x lorsque le verticle est déployé. Le paramètre passé à la méthode est un Future qui permet de vérifier que le verticle est correctement déployé. Le démarrage du verticle est asynchrone. Quand son démarrage est terminé (succès ou échec), c’est à l’aide du Future que Vert.x est notifié.

Dans la méthode start(), un serveur HTTP est créé auquel est attaché le request handler. Ce dernier reçoit une fonction lambda qui est appelée à chaque fois que le serveur reçoit une requête et qui renvoie un simple message comme réponse. Le serveur HTTP créé est configuré pour écouter le port 8080.

La classe AbstractVerticle propose aussi la méthode stop() à redéfinir. Cette méthode est utilisée pour spécifier un traitement particulier (des opérations de nettoyage ou du log) avant que le verticle ne soit arrêté par Vert.x.

Note : Vert.x arrête automatiquement tout serveur en cours d’exécution lorsque aucun verticle n’est plus déployé.

Déployer un Verticle

Pour exécuter le verticle créé, il doit être déployé dans Vert.x :

On peut aussi déployer un verticle depuis un autre verticle :

Test de l’implémentation !

Dans le fichier “pom.xml”, ajoutez les dépendances suivantes :

Ensuite, créez une classe de test :

Ce test utilise vertx-unit avec un Runner personnalisé fourni par Vert.x qui est plus approprié pour tester du code asynchrone.

Dans la méthode init(), une instance de Vert.x est créée et notre verticle est déployé. Le paramètre testContext permet de gérer l’aspect asynchrone du test. On remarque que le second paramètre de la méthode deployVerticle() est un handler, ce dernier met le test en échec si le verticle ne démarre pas correctement.

La méthode stopVerticles() permet d’arrêter l’instance Vert.x, ce qui implique l’arrêt de tous les verticles déployés sur cette instance.

Dans la méthode testHttpServerWorksWell(), un client HTTP est créé et utilisé pour requêter le serveur déployé dans la méthode init(). Un objet async créé est utilisé pour notifier le framework de test du succès de ce dernier en utilisant async.complete().

Important : il faut utiliser les assertions de test de Vert.x (par exemple testContext.assert) car Vert.x est asynchrone et si l’assertion est en échec, le test est immédiatement interrompu.

Packaging

Ajoutez le code snippet suivant au “pom.xml” :

Le maven-shade-plugin est utilisé pour créer le fat jar qu’on va trouver dans le dossier target. La commande à utiliser est : mvn clean package en ligne de commande. On peut également utiliser l’IDE et exécuter le goal maven : clean package.

Exécution

Pour utiliser l’application qu’on a développée, exécutez le fat jar comme suit.

Ouvrez votre terminal dans le dossier target et taper la commande suivante :

java -jar intro-to-vertx-1.0-SNAPSHOT-fat.jar

Ensuite, ouvrez le navigateur à l’adresse http://localhost:8080/ :

Enfin, pour stopper l’application, utilisez CTRL+C dans le terminal.

Dans Intellij en mode débug, on voit bien le thread unique de l’event loop :

Conclusion

Dans cet article, j’ai voulu aborder les concepts de base de Vert.x pour proposer une sorte de “starter pack” pour tout développeur ayant envie de commencer à utiliser Vert.x.

Il ne me reste qu’à vous dire : Enjoy coding !!

Références

Pas encore de commentaires

Publier un commentaire

Auteur

Soufiane ZENIOU

Sofiane est un développeur junior passionné par l'écosystème Java et avide de nouveaux challenges.