logo le blog invivoo blanc

VERT.X BASICS: Concurrence et scalabilité avec les verticles

13 avril 2018 | Java

Au-dessus de son modèle de concurrence de base, Vert.x fournit un modèle de concurrence, de distribution et de scalabilité de haut niveau avec le concept de verticle :

  • Les verticles constituent un modèle de concurrence car ils sont effectivement exécutés non seulement en concurrence, mais en plus avec la garantie qu’ils le sont toujours dans la même event-loop. La garantie qu’un verticle est exécuté par une même event loop permet de les préserver des situations de race condition, dont le développeur n’aura donc pas à se préoccuper. Cela n’est en réalité vrai que pour certains types de verticles, mais c’est ainsi que fonctionne le type de verticle standard
  • Modèle de distribution car les verticles sont pensés pour communiquer naturellement entre eux par messages asynchrones. Grace à l’isolation fournie par la communication par messages asynchrones, les environnements d’exécution des verticles peuvent être distribués à très faible coût.
  • Modèle de scalabilité car plusieurs instances peuvent être déployées pour être exécutées en parallèle sur les cœurs d’un processeur ou d’un cluster dans une ou plusieurs instances Vert.x.

Mais il est important de savoir que l’utilisation des verticles n’est pas une obligation pour écrire une application Vert.x. Il faut cela dit avoir de bonnes raisons pour en arriver là, lorsque l’on sait toutes les possibilités qu’ils offrent.

Création d’un verticle

Pour créer un verticle, il faut étendre la classe abstraite AbstractVerticle, et redéfinir la méthode héritée start qui est appelée au démarrage du verticle lorsqu’il est déployé. La méthode héritée stop appelée durant le retrait du verticle peut aussi être redéfinie si c’est nécessaire, pour le nettoyage de ressources par exemple.

public class SimpleVerticle extends AbstractVerticle {
     
    @Override
    public void start(){
        
    }
    
    @Override
    public void stop(){
        
    }
    
}

Listing 2‑6 Création d’un verticle

Déploiement d’un verticle

Un verticle doit être déployé explicitement dans Vert.x pour rentrer en exécution. Ce déploiement peut être effectué par programmation ou par des outils en ligne de commande. Nous n’allons cependant voir que la méthode par programmation. Mais l’outil de ligne de commande est très pratique et vaut le coup d’être examiné, une documentation pour débuter avec est disponible sur le site de vert.x : http://vertx.io/docs/vertx-core/java/#_the_vertx_command_line.

Par programmation, un verticle est déployé en appelant la méthode deployVerticle de l’objet vertx et en lui passant le nom qualifié du verticle ou une instance de la classe du verticle :

         Vertx vertx = Vertx.vertx();
         // déploiement du verticle à partir du nom qualifié
         vertx.deployVerticle("devoxx.demo.GreetingService");

         // dépploiement du verticle à partir d'une instance de la classe
         HelloWorld verticle = new HelloWorld();
         vertx.deployVerticle(verticle);

Listing 2‑7 Déploiement d’un verticle

Il est aussi possible de spécifier des options pour le déploiement. Par exemple dans l’extrait suivant, nous spécifions le nombre d’instances du verticle à déployer :

         DeploymentOptions options = new DeploymentOptions().setInstances(5);
         Vertx vertx = Vertx.vertx();
         vertx.deployVerticle("devoxx.demo.GreetingService", options);

Des propriétés propres à l’application peuvent également être ajoutées aux options de déploiement pour être utilisées par le verticle :

         JsonObject config = new JsonObject().put("lang", "en");
         DeploymentOptions options = new DeploymentOptions().setInstances(2).setConfig(config);
         vertx.deployVerticle("devoxx.demo.HelloWorld", options);

Et le verticle peut récupérer la valeur de la propriété comme suit :

         System.out.println("lang = "+config().getString("lang"));

Types de verticles

Il existe trois types de verticle qui se distinguent en fonction de leur contexte d’exécution.

Verticles standards

Ce sont les verticles à utiliser en situation normale, et les verticles sont comme tels par défaut, c’est-à-dire lorsqu’ils sont déclarés sans configuration particulière. Les verticles utilisés dans l’exemple d’introduction sont donc des verticles standards.

Les handlers d’évènement d’un verticle standard sont exécutés dans l’event loop, et sont garantis d’être toujours exécutés dans la même event loop. Cela procure un avantage considérable en libérant le développeur de toutes les contraintes liées à la programmation concurrente, vu que l’exécution du verticle se fait dans un seul thread, tout en lui permettant de faire de la programmation concurrente et parallèle, vu que plusieurs instances du verticle peuvent être déployés dans un ou plusieurs event loops.

Verticles workers

Au niveau de la déclaration ils sont similaires aux verticles standards. La distinction se fait au niveau du déploiement où il faut indiquer à Vert.x le type du verticle.

         Vertx vertx = Vertx.vertx();
         // déployer le verticle comme worker
         DeploymentOptions options = new DeploymentOptions().setWorker(true);
         vertx.deployVerticle("devoxx.demo.WorkerVerticle", options);

Listing 2‑8 Déploiement d’un verticle comme worker

Contrairement au verticle standard, le verticle worker n’est pas exécuté dans l’event loop, mais dans un pool de threads qui leur est dédié, afin de ne pas bloquer l’event loop. Et une instance de verticle worker peut être exécutée par différents threads, mais jamais en concurrence, toujours par un thread à la fois.

Verticles workers multi-threadés (multi-threaded worker verticles)

Ces verticles sont des verticles workers, avec la spécificité qu’ils peuvent être exécutés en concurrence par différents threads. La documentation de Vert.x met en garde contre l’usage de ces verticles qui demandent une maîtrise de la programmation concurrente pour éviter ses écueils. Comme pour les verticles workers, c’est au déploiement qu’il faut indiquer le type du verticle :

         Vertx vertx = Vertx.vertx();
         // déployer le verticle comme multi-threadé
         DeploymentOptions options = new DeploymentOptions().setMultiThreaded(true)
         vertx.deployVerticle("devoxx.demo.MultiThreadedVerticle", options);