{"id":277,"date":"2021-02-17T23:09:20","date_gmt":"2021-02-17T22:09:20","guid":{"rendered":"http:\/\/baptiste-meynier.com\/?p=277"},"modified":"2023-02-18T18:56:10","modified_gmt":"2023-02-18T17:56:10","slug":"vert-x","status":"publish","type":"post","link":"https:\/\/baptiste-meynier.com\/index.php\/2021\/02\/17\/vert-x\/","title":{"rendered":"Vert.x"},"content":{"rendered":"\n<p>Lors du d\u00e9veloppement d&#8217;une application nous pensons souvent \u00e0 la maintenabilit\u00e9 du code, sa robustesse et la performance. Il y a un crit\u00e8re que nous mettons souvent de cot\u00e9 c&#8217;est la notion de co\u00fbt de l&#8217;infrastructure. Cette probl\u00e9matique se pose de plus en plus, que se soit dans le monde des Cloud publics ou du BigData fort consommateur en ressources. Les frameworks conventionnelles remplissent leurs r\u00f4les lorsqu&#8217;il s&#8217;agit de cr\u00e9er une applications Web, mais ne sont pas r\u00e9ellement con\u00e7ut pour r\u00e9pondre aux exigences de BigData. Il existe pourtant des paradigmes simples connu depuis des ann\u00e9es permettant d&#8217;exploiter le hardware de mani\u00e8re efficiente. Vert.x n&#8217;est pas un framework mais un ensemble d&#8217;outils permettant de r\u00e9pondre efficacement \u00e0 ces probl\u00e9matiques. <\/p>\n\n\n\n<p>J&#8217;ai souvent entendu que pour avoir de meilleurs performances il fallait augmenter la m\u00e9moire ou le nombre de threads. Mais est-ce aussi simple que \u00e7a ?<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"509\" height=\"298\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/pool_goulot-1.gif\" alt=\"\" class=\"wp-image-388\"\/><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Qu&#8217;est ce qu&#8217;un pools de threads ?<\/h3>\n\n\n\n<p>Illustrons notre explication en prenant l&#8217;exemple d<strong>es caisses d&#8217;un supermarch\u00e9<\/strong><\/p>\n\n\n\n<p><em>Les clients sont r\u00e9partis sur l&#8217;ensemble des caisses et paient chacun leurs tours. <\/em><\/p>\n\n\n\n<p>Ce n&#8217;est ni plus ni moins qu&#8217;un pool de threads !<\/p>\n\n\n\n<p><em>En cas de forte affluence il est possible d&#8217;ouvrir de nouvelles caisses pour d\u00e9sengorger les files d&#8217;attentes.<\/em><\/p>\n\n\n\n<p>En informatique chaque pool porte une responsabilit\u00e9 qui lui est propres, entr\u00e9es\/sorties, transactions, acc\u00e8s \u00e0 la base de donn\u00e9es etc etc.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Il existe plusieurs fa\u00e7ons de d\u00e9clarer un pool de thread, notamment en lui d\u00e9finissant une taille minimal et maximal.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">ThreadPoolExecutor executorPool = new ThreadPoolExecutor(5, 10; 3, TimeUnit.SECONDS, new ArrayBlockingQueue(50));<\/code><\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"608\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/executor_service.png\" alt=\"\" class=\"wp-image-400\" srcset=\"https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/executor_service.png 1024w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/executor_service-300x178.png 300w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/executor_service-768x456.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Les limites<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Sa taille:<\/h4>\n\n\n\n<p>Reprenons notre exemple du supermarch\u00e9:<\/p>\n\n\n\n<p><em>En heure de pointe, il est toujours possible d&#8217;ouvrir des caisses pour traiter d&#8217;avantage de paiement, mais le magasin poss\u00e8de une surface finie!<\/em><\/p>\n\n\n\n<p>Un pool est limit\u00e9 par sa taille et son hardware, sa scalabilit\u00e9 n&#8217;est pas infini!<\/p>\n\n\n\n<p>Un pool de thread est un goulot d&#8217;\u00e9tranglement, il peut aussi \u00eatre vue comme un outils de Back-Pressure. Le dimensionnement d&#8217;un pool est un \u00e9l\u00e9ment critique de votre application et doit porter toute votre attention! Une \u00e9tude de la production est essentiel en tenant compte des pics de charge journaliers ainsi que des tests de charges. N&#8217;oubliez pas que la production reste malgr\u00e9 tout difficile \u00e0 pr\u00e9dire. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Son empreinte m\u00e9moire:<\/h4>\n\n\n\n<p>Chaque thread poss\u00e8de sa propre pile d\u2019ex\u00e9cution, multiplier les threads impacte la taille de la m\u00e9moire disponible pour les traitements m\u00e9tiers.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">La concurrence:<\/h4>\n\n\n\n<p>Avoir plusieurs threads implique de prendre en compte des probl\u00e9matiques de concurrence comme  les locks qui bloquent les traitements de la Jvm etc.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1025\" height=\"662\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/multi-threading.png\" alt=\"\" class=\"wp-image-331\" srcset=\"https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/multi-threading.png 1025w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/multi-threading-300x194.png 300w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/multi-threading-768x496.png 768w\" sizes=\"auto, (max-width: 1025px) 100vw, 1025px\" \/><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Mais que se passe t&#8217;il sous le capot?<\/h5>\n\n\n\n<p>Nous le savons en informatique les threads sont ex\u00e9cut\u00e9s par le CPU et cela dans la limites des c\u0153urs disponibles. Au del\u00e0, la machine \u00e9mulera la parall\u00e9lisation en ex\u00e9cutant alternativement ses processus et effectuera ce que l&#8217;on appelle des switchs de context.<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">Le switch de context:<\/h6>\n\n\n\n<p>C&#8217;est le nom donn\u00e9 \u00e0 l&#8217;action du processeur lorsqu&#8217;il passe du traitement d&#8217;un thread \u00e0 un autre. <\/p>\n\n\n\n<p>Pour cela le CPU \u00e0 besoin:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>de sauvegarder l&#8217;\u00e9tat du thread <\/li>\n\n\n\n<li>de changer ses pointeurs en m\u00e9moires <\/li>\n<\/ul>\n\n\n\n<p>Cette op\u00e9ration n&#8217;est pas gratuite et ce n&#8217;est pas une op\u00e9rations que l&#8217;on souhaite invoquer outre mesure !<\/p>\n\n\n\n<p>La commande pidstat permet d&#8217;observer les commutations de contextes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">[baptiste@localhost ~]$ pidstat -w -d -t -p 3583 -h\n Linux 5.9.16-200.fc33.x86_64 (localhost.localdomain)     28\/12\/2020  <em>x86_64<\/em>    (16 CPU)\n Time        UID      TGID       TID   kB_rd\/s   kB_wr\/s kB_ccwr\/s iodelay   cswch\/s nvcswch\/s  Command\n03:14:46    1000      -      3714      0,00      0,00      0,00       0      2,76      0,01  |__default I\/O-1\n03:14:46    1000      -      3715      0,00      0,00      0,00       0      2,76      0,02  |__default I\/O-2\n03:14:46    1000      -      3716      0,00      0,00      0,00       0      2,72      0,02  |__default I\/O-3\n03:14:46    1000      -      3717      0,00      0,00      0,00       0      2,76      0,02  |__default I\/O-4\n03:14:46    1000      -      3718      0,00      0,00      0,00       0      2,83      0,01  |__default I\/O-5\n03:14:46    1000      -      3719      0,00      0,00      0,00       0      6,34      0,46  |__default <\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<pre id=\"block-a147d9bf-2100-4582-b688-e28f60e20745\" class=\"wp-block-preformatted\">cswch\/s\nNombre total de commutation de contexte volontaire effectu\u00e9 par seconde. Une commutation de contexte volontaire est r\u00e9alis\u00e9e quand un traitement ne parvient pas \u00e0 acc\u00e9der \u00e0 une ressource.<\/pre>\n\n\n\n<pre id=\"block-ae75974b-06ea-44d7-a040-0406e32340a3\" class=\"wp-block-preformatted\">nvcswch\/s\nNombre total de commutation de contexte involontaire effectu\u00e9 par seconde. Une commutation de contexte involontaire est r\u00e9alis\u00e9e quand une tache lors de sa fen\u00eatre d'\u00e9xecution est forc\u00e9e de renoncer \u00e0 son traitement.<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Existe-t-il une architecture qui permet d&#8217;\u00e9viter ces probl\u00e8mes ?<\/h2>\n\n\n\n<p>La r\u00e9ponse est oui et ce n&#8217;est pas une nouveaut\u00e9 ! Les applications avec interface graphique comme AWT\/Swing et plus r\u00e9cemment NodeJs connaissent bien ces probl\u00e9matiques. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Le design pattern Reactor:<\/h3>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1023\" height=\"392\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/event-loop.png\" alt=\"\" class=\"wp-image-327\" srcset=\"https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/event-loop.png 1023w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/event-loop-300x115.png 300w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/event-loop-768x294.png 768w\" sizes=\"auto, (max-width: 1023px) 100vw, 1023px\" \/><\/figure>\n<\/div>\n\n\n<p>Ce pattern permet de traiter des \u00e9v\u00e9nements les un \u00e0 la suite des autres. Il s&#8217;agit d&#8217;une variante du pattern Observateur mais traitant des \u00e9v\u00e8nements de plusieurs sources. On le nomme autrement boucle de d\u00e9multiplexage.<\/p>\n\n\n\n<p>Pour mieux comprendre je vous propose de lire l&#8217;impl\u00e9mentation de Julien Ponges tir\u00e9 du livre Vert.x in Action.<\/p>\n\n\n\n<pre title=\"Event loop tir\u00e9e du livre VertX in Action de Julien Ponge\" class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">import java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentLinkedDeque;\nimport java.util.function.Consumer;\n\npublic final class EventLoop {\n\n  public static final class Event {\n    private final String key;\n    private final Object data;\n\n    public Event(String key, Object data) {\n      this.key = key;\n      this.data = data;\n    }\n  }\n\n  private final ConcurrentLinkedDeque&lt;Event&gt; events = new ConcurrentLinkedDeque&lt;&gt;();\n  private final ConcurrentHashMap&lt;String, Consumer&lt;Object&gt;&gt; handlers = new ConcurrentHashMap&lt;&gt;();\n\n  public EventLoop on(String key, Consumer&lt;Object&gt; handler) {\n    handlers.put(key, handler);\n    return this;\n  }\n\n  public void dispatch(Event event) {\n    events.add(event);\n  }\n\n  public void run() {\n    while (!(events.isEmpty() &amp;&amp; Thread.<em>interrupted<\/em>())) {\n      if (!events.isEmpty()) {\n        Event event = events.pop();\n        if (handlers.containsKey(event.key)) {\n          handlers.get(event.key).accept(event.data);\n        } else {\n          System.<em>err<\/em>.println(\"No handler for key \" + event.key);\n        }\n      }\n    }\n  }\n\n  public void stop() {\n    Thread.<em>currentThread<\/em>().interrupt();\n  }\n\n  public static void main(String[] args) {\n    EventLoop eventLoop = new EventLoop();\n\n    new Thread(() -&gt; {\n      for (int n = 0; n &lt; 6; n++) {\n        <em>delay<\/em>(1000);\n        eventLoop.dispatch(new EventLoop.Event(\"tick\", n));\n      }\n      eventLoop.dispatch(new EventLoop.Event(\"stop\", null));\n    }).start();\n\n    new Thread(() -&gt; {\n      <em>delay<\/em>(2500);\n      eventLoop.dispatch(new EventLoop.Event(\"hello\", \"beautiful world\"));\n      <em>delay<\/em>(800);\n      eventLoop.dispatch(new EventLoop.Event(\"hello\", \"beautiful universe\"));\n    }).start();\n\n    eventLoop.dispatch(new EventLoop.Event(\"hello\", \"world!\"));\n    eventLoop.dispatch(new EventLoop.Event(\"foo\", \"bar\"));\n\n    eventLoop\n      .on(\"hello\", s -&gt; System.<em>out<\/em>.println(\"hello \" + s))\n      .on(\"tick\", n -&gt; System.<em>out<\/em>.println(\"tick #\" + n))\n      .on(\"stop\", v -&gt; eventLoop.stop())\n      .run();\n\n    System.<em>out<\/em>.println(\"Bye!\");\n  }\n\n  private static void delay(long millis) {\n    try {\n      Thread.<em>sleep<\/em>(millis);\n    } catch (InterruptedException e) {\n      throw new RuntimeException(e);\n    }\n  }\n}\n<\/code><\/pre>\n\n\n\n<p>Output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">hello world!\n tick #0\n No handler for key foo\n tick #1\n hello beautiful world\n tick #2\n hello beautiful universe\n tick #3\n tick #4\n tick #5\n Bye!<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Les taches sont trait\u00e9es les une apr\u00e8s les autres de mani\u00e8re s\u00e9quentielle. Ce n&#8217;est pas un pattern sans failles ! Les traitements longs ne doivent pas \u00eatre ex\u00e9cut\u00e9s au sein de la boucle, cela reviendrait \u00e0 bloquer tous les autres traitements! <\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"392\" data-id=\"333\" src=\"https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/event-loop_bloking.png\" alt=\"\" class=\"wp-image-333\" srcset=\"https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/event-loop_bloking.png 1024w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/event-loop_bloking-300x115.png 300w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/event-loop_bloking-768x294.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/figure>\n\n\n\n<p>Soyons honn\u00eate je ne connais pas un seul programme ne poss\u00e9dant pas de longues taches bloquantes. L&#8217;id\u00e9e est de les d\u00e9composer en taches courtes, mais cela n&#8217;est pas toujours possible! Les exemples ne manquent pas, les appels \u00e0 une base de donn\u00e9es, un appel \u00e0 une API Rest tiers etc etc. Vert.x en grand seigneur laisse la possibilit\u00e9 d&#8217;utiliser des pools de threads plus conventionnels permettant d&#8217;ex\u00e9cuter ces longs traitements. Ils sont appel\u00e9s les Workers.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"608\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/vertx-threads.png\" alt=\"\" class=\"wp-image-421\" srcset=\"https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/vertx-threads.png 1024w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/vertx-threads-300x178.png 300w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/01\/vertx-threads-768x456.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-pullquote\"><blockquote><p>Vert.x repose sur une variante de ce m\u00e9canisme, le pattern Multi-Reactor.<\/p><\/blockquote><\/figure>\n\n\n\n<p>Vert.x am\u00e9liore l&#8217;usage de ce pattern en multipliant le nombre d&#8217;events loop. Chacune d&#8217;entre elles sont associ\u00e9es \u00e0 un c\u0153ur, permettant ainsi de r\u00e9soudre la probl\u00e9matique de commutation de contexte. Son nombre peut varier et est en cons\u00e9quence limit\u00e9 par l&#8217;architecture du processeur.<\/p>\n\n\n\n<p>Pour y voir plus clair essayons de calculer le nombre maximum d&#8217;event loop pour ma machine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">[baptiste@localhost bin]$ lscpu\n Architecture&nbsp;:                          x86_64\n Processeur(s)&nbsp;:                         16\n Liste de processeur(s) en ligne&nbsp;:       0-15\n Thread(s) par c\u0153ur&nbsp;:                    2\n C\u0153ur(s) par socket&nbsp;:                    8\n Socket(s)&nbsp;:                             1\n N\u0153ud(s) NUMA&nbsp;:                          1<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Vert.x applique la r\u00eagle suivante:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote has-text-align-center is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Nombre de processeurs *  2 <\/p>\n<\/blockquote>\n\n\n\n<p class=\"has-text-align-center\">ce qui donne dans mon cas: 16 * 2 = 32<\/p>\n\n\n\n<p>C&#8217;est cod\u00e9 en une ligne <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/eclipse-vertx\/vert.x\/blob\/master\/src\/main\/java\/io\/vertx\/core\/VertxOptions.java#L38\" target=\"_blank\">ici<\/a><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>A noter que Vert.x est en quelque sorte, une sur-couche au c\u00e9l\u00e8bre framework Netty et facilite son usage.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">mvn dependency:tree\n...\n[INFO] +- io.vertx:vertx-service-proxy:jar:4.0.2:compile\n[INFO] |  \\- io.vertx:vertx-core:jar:4.0.2:compile\n[INFO] |     +- io.netty:netty-common:jar:4.1.52.Final:compile\n[INFO] |     +- io.netty:netty-buffer:jar:4.1.52.Final:compile\n[INFO] |     +- io.netty:netty-transport:jar:4.1.52.Final:compile\n[INFO] |     +- io.netty:netty-handler:jar:4.1.52.Final:compile\n[INFO] |     |  \\- io.netty:netty-codec:jar:4.1.52.Final:compile\n[INFO] |     +- io.netty:netty-handler-proxy:jar:4.1.52.Final:compile\n[INFO] |     |  \\- io.netty:netty-codec-socks:jar:4.1.52.Final:compile\n[INFO] |     +- io.netty:netty-codec-http:jar:4.1.52.Final:compile\n[INFO] |     +- io.netty:netty-codec-http2:jar:4.1.52.Final:compile\n[INFO] |     +- io.netty:netty-resolver:jar:4.1.52.Final:compile\n[INFO] |     \\- io.netty:netty-resolver-dns:jar:4.1.52.Final:compile\n[INFO] |        \\- io.netty:netty-codec-dns:jar:4.1.52.Final:compile<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/netty_icon_64px.svg\" alt=\"\" class=\"wp-image-449\" width=\"98\" height=\"98\"\/><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Commen\u00e7ons par cr\u00e9er notre premier programme<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">import io.vertx.core.AbstractVerticle;\nimport io.vertx.core.DeploymentOptions;\nimport io.vertx.core.Promise;\nimport io.vertx.core.Vertx;\n\npublic class MainVerticle extends AbstractVerticle {\n  @Override\n  public void start(Promise&lt;Void&gt; startPromise) throws Exception {\n    vertx.createHttpServer().requestHandler(req -&gt; {\n      req.response()\n        .putHeader(\"content-type\", \"text\/plain\")\n        .end(\"Hello from Vert.x!\");\n    }).listen(8888, http -&gt; {\n      if (http.succeeded()) {\n        startPromise.complete();\n        System.<em>out<\/em>.println(\"HTTP server started on port 8888\");\n      } else {\n        startPromise.fail(http.cause());\n      }\n    });\n  }\n}<\/code><\/pre>\n\n\n\n<p>Dans ce programme je cr\u00e9e un serveur Http qui nous dit bonjour. Ce code \u00e9tend un objet central de Vert.x, les Verticles.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Vert.x repose sur le pattern Actor Model.<\/h3>\n\n\n\n<p>Ce <a rel=\"noreferrer noopener\" href=\"https:\/\/fr.wikipedia.org\/wiki\/Mod%C3%A8le_d%27acteur\" target=\"_blank\">model <\/a>a \u00e9t\u00e9 con\u00e7u pour faciliter la conception d&#8217;application ayant de fortes contraintes concurrentielles.<\/p>\n\n\n\n<p>Au m\u00eame titre que la programmation objet consid\u00e8re que tout est objet, le model Acteur consid\u00e8re que tout est acteur.<\/p>\n\n\n\n<p>Un acteur est une entit\u00e9 capable de calculer et qui en r\u00e9ponse d&#8217;un message, peut:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>envoyer un nombre fini de messages \u00e0 d\u2019autres acteurs&nbsp;;<\/li>\n\n\n\n<li>cr\u00e9er un nombre fini de nouveaux acteurs&nbsp;;<\/li>\n\n\n\n<li>sp\u00e9cifier le comportement \u00e0 avoir lors de la prochaine r\u00e9ception de messages.<\/li>\n<\/ul>\n\n\n\n<p>En r\u00e9sum\u00e9 un Verticle est un acteur:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>qui communique avec les autres acteurs en envoyant des messages trait\u00e9s de mani\u00e8re asynchrone<\/li>\n\n\n\n<li>modifie uniquement son \u00e9tat (chacun dispose de son propre ClassLoader)<\/li>\n\n\n\n<li>d\u00e9finit un traitement pour un type de message<\/li>\n<\/ul>\n\n\n\n<p>En appart\u00e9, il est extr\u00eamement simple de multiplier les instances d&#8217;un Verticle.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">Vertx.vertx().deployVerticle(FishDatabaseVerticle.class.getName(), new DeploymentOptions().setInstances(5));<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Comment envoyer un message ?<\/h3>\n\n\n\n<p>La communication entre les Verticles s&#8217;effectue via un bus d&#8217;\u00e9v\u00e9nement partag\u00e9 \u00e0 l&#8217;ensemble des Verticles on y acc\u00e8de de la mani\u00e8re suivante:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">EventBus eb = vertx.eventBus();<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Il est possible d&#8217;effectuer une communication de type point \u00e0 point:<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">eventBus.send(\"fish.purchase\", \"Discus\");<\/code><\/pre>\n\n\n\n<p>Le message est envoy\u00e9 \u00e0 une instance cliente en suivant une strat\u00e9gie de round robin.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">De type Broadcast:<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">eventBus.publish(\"fish.sell\", \"Hi everyone, the Discus fish was sold\");<\/code><\/pre>\n\n\n\n<p>Le message est envoy\u00e9 \u00e0 l&#8217;ensemble des clients en \u00e9coute.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Point \u00e0 point avec r\u00e9ponse:<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">eventBus.request(\"fish.purchase\", \"Scalare\", ar -&gt; {\n   if (ar.succeeded()) {\n     System.out.println(ar.result().body());\n   }\n });<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\"><code>MessageConsumer&lt;String&gt; consumer = eventBus.consumer(\"fish.purchase\"); <\/code>\n<code>consumer.handler(message -&gt; {   <\/code>\n<code>System.out.println(\"I have received a purchase: \" + message.body()); <\/code>\n<code> message.reply(\"The price of the fish is \" + priceMapping.get(message.body())); <\/code>\n<code>});<\/code><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Les Handlers<\/h2>\n\n\n\n<p>Vous le trouverez partout et pour cause, il s&#8217;agit de d\u00e9finir un petit traitement qui sera ensuite envoy\u00e9 dans l&#8217;event loop.  Prenons l&#8217;exemple d&#8217;un traitement qui parse un long flux d&#8217;objet Json.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">JsonParser.<em>newParser<\/em>(asyncFishFile).objectValueMode()\n.handler(event -&gt; {\n  if (Objects.<em>nonNull<\/em>(event.value())) {\n    Fish fish = event.mapTo(Fish.class);\n    System.<em>out<\/em>.println(\"Fish = \" + fish);\n   }\n })\n .exceptionHandler(t -&gt; {\n   t.printStackTrace();\n   asyncFishFile.close();\n })\n.endHandler(v -&gt; {\n   System.<em>out<\/em>.println(\"Done!\");\n   asyncFishFile.close();\n });<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Vert.x est r\u00e9actif<\/h2>\n\n\n\n<p>En regardant de plus pr\u00eat l&#8217;activit\u00e9 de la JVM d&#8217;une application au paradigme Imp\u00e9ratif, vous remarquerez que votre application passe beaucoup de temps \u00e0 attendre. C&#8217;est un gaspillage de ressource ! A contrario Vert.x utilise massivement l\u2019asynchrone.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Les futures<\/h3>\n\n\n\n<p>Voici quelques op\u00e9rateur de l&#8217;objet Future:<\/p>\n\n\n\n<pre id=\"block-3cb017f1-3713-4594-8426-56df6d4e62c7\" class=\"wp-block-preformatted\"><strong>Map <\/strong>effectue une op\u00e9ration sur le future.<\/pre>\n\n\n\n<pre id=\"block-63622604-33f6-43fe-a4a4-0f2d01629b11\" class=\"wp-block-preformatted\"><strong>Recover <\/strong>est une sorte de catch, il permet de lancer un traitement en cas d'exception..<\/pre>\n\n\n\n<pre id=\"block-63622604-33f6-43fe-a4a4-0f2d01629b11\" class=\"wp-block-preformatted\"><strong>Eventualy<\/strong> est une sorte de finally, il est syst\u00e9matiquement appel\u00e9.<\/pre>\n\n\n\n<pre id=\"block-2665bce2-0312-42ef-a905-ab8ba26758f2\" class=\"wp-block-preformatted\"><strong>onSuccess, onFailure <\/strong>sont des syst\u00e8mes de notification, ils ne modifient pas le future.<\/pre>\n\n\n\n<pre id=\"block-aa31cab4-0bae-400f-9d2a-94f7f679bafa\" class=\"wp-block-preformatted\"><strong>Bien d'autres m\u00e9thodes<\/strong><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\"><code>vertx.fileSystem().props(\"fishs.json\")\n  .map(FileProps::size)<\/code>\n  .recover(err -&gt; Future.<em>succeededFuture<\/em>(0l))<code>\n  .onSuccess(size -&gt; System.<em>out<\/em>.println(\"File size = \" + size))\n  .onFailure(res -&gt;System.<em>out<\/em>.println(\"Failure: \" + res.getCause().getMessage()));<\/code><\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Vert.x dispose de sa propre impl\u00e9mentation des Futures, sachez qu&#8217;elle est enti\u00e8rement compatible avec l&#8217;API CompletionStage fournit par le JDK et qu&#8217;il est possible d&#8217;utiliser RxJava.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/reactivex.svg\" alt=\"\" class=\"wp-image-456\" width=\"114\" height=\"109\"\/><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>RxJava  est une impl\u00e9mentation Java de l&#8217;initiative <a rel=\"noreferrer noopener\" href=\"http:\/\/reactivex.io\/\" target=\"_blank\">ReactiveX<\/a> qui propose de standardiser les API r\u00e9actives quelque soit le langage.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Son application r\u00e9pond \u00e0 l&#8217;ensemble des crit\u00e8res du <a rel=\"noreferrer noopener\" href=\"https:\/\/www.reactivemanifesto.org\/fr\" target=\"_blank\">Manifest Reactif<\/a>:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"608\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/reactif_manifesto-1-1024x608.png\" alt=\"\" class=\"wp-image-534\" srcset=\"https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/reactif_manifesto-1-1024x608.png 1024w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/reactif_manifesto-1-300x178.png 300w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/reactif_manifesto-1-768x456.png 768w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/reactif_manifesto-1-1536x912.png 1536w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/reactif_manifesto-1.png 2016w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Comment tester ?<\/h2>\n\n\n\n<p>De par sa conception avec le model Acteur, un traitement est isol\u00e9 au sein de son Verticle, en revanche son cot\u00e9 asynchrone rend les choses l\u00e9g\u00e8rement  plus compliqu\u00e9. Pour palier ce probl\u00e8me Vert.x nous fournit plusieurs outils.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">VertxTestContext:<\/h4>\n\n\n\n<p>Dans l&#8217;exemple ci-dessous, nous souhaitons v\u00e9rifier que notre serveur http est correctement lanc\u00e9.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\"><code>@ExtendWith(VertxExtension.class) <\/code>\n<code>class DatabaseVerticleDeploymentTest {   <\/code>\n\n   <code>Vertx vertx = Vertx.vertx();   <\/code>\n\n   <code>@Test   <\/code>\n   <code>void it_should_start_database_verticle() throws Throwable {     <\/code>\n     VertxTestContext testContext = new VertxTestContext();\n\n     vertx.deployVerticle(new FishDatabaseVerticle())\n       .onSuccess(res -&gt; testContext.completeNow()) (1)\n       .onFailure(res -&gt; System.<em>out<\/em>.println(\"An error occur\"));\n\n<em>     assertThat<\/em>(testContext.awaitCompletion(5, TimeUnit.<em>SECONDS<\/em>)).isTrue(); (2)\n\n     if (testContext.failed()) {\n       throw testContext.causeOfFailure(); (3)\n     }\n   <code>} <\/code>\n<code>}<\/code>\n (1) est l'instruction qui d\u00e9finit le succ\u00e8s de notre test.\n (2) awaitCompletion v\u00e9rifie que completeNow soit d\u00e9clench\u00e9 avant 5 secondes.\n (3) dans le cas contraire le test sera en echec. <\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Vert.x vous laisse l&#8217;usage de votre librairie d&#8217;assertion pr\u00e9f\u00e9r\u00e9, il suffira d&#8217;encapsuler votre v\u00e9rification dans l&#8217;une des m\u00e9thodes suivantes verify, succeeding ou failing du VertxTestContext.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\"><code>@Test\nvoid it_should_insert_fish(Vertx vertx, VertxTestContext testContext) {\n  String fishName = \"Scalare\";\n  WebClient client = WebClient.<em>create<\/em>(vertx);\n  client.post(<em>PORT<\/em>, <em>HOST<\/em>, <em>APPLICATION_CONTEXT <\/em>+ \"?name=\" + fishName)\n    .as(BodyCodec.<em>string<\/em>())\n    .send(testContext.succeeding(response -&gt; testContext.verify(() -&gt; {\n      <em>assertThat<\/em>(response.body()).isNotBlank();\n      testContext.completeNow();\n    })));\n}<\/code><\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Les checkpoints:<\/h3>\n\n\n\n<p>Ce m\u00e9canisme permet de v\u00e9rifier les traitements multiples en d\u00e9finissant un nombre de d\u00e9clenchement \u00e0 atteindre.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\"><code>@Test\nvoid it_should_get_existing_fish2(VertxTestContext testContext) {\n  String fish1 = \"Discus\";\n  String fish2 = \"Scalare\";\n  Checkpoint checkpoint = testContext.checkpoint(2); (1)\n\n  createFish(fish1).map(createFish(fish2)).onSuccess(nothing -&gt; {\n      dbService.existFishByName(fish1, res -&gt; {\n        if (res.succeeded()) {\n          checkpoint.flag(); (2)\n        }});\n    dbService.existFishByName(fish2, res -&gt; {\n      if (res.succeeded()) {\n        checkpoint.flag(); (3)\n      }});\n    });\n}<\/code>\n(1) Ici je d\u00e9clare un compteur de deux unit\u00e9s\n(2) (3) L'instruction flag va d\u00e9compter une unit\u00e9 de son compteur<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Et si on codait une v\u00e9ritable application ?<\/h2>\n\n\n\n<p>Pour ceux qui me suivent, vous connaisez ma passion pour l&#8217;aquariophilie. Il s&#8217;agira cette fois d&#8217;une simple application r\u00e9pertoriant les poissons que j&#8217;ai pu acheter. Il s&#8217;agit d&#8217;une application toute simple exposant des op\u00e9rations de type CRUD via une API Rest. <\/p>\n\n\n\n<p>Faisons ensemble un tour de quelques fonctionnalit\u00e9s que j&#8217;ai pu utiliser.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Je lance mon application de la fa\u00e7on suivante:<\/h5>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">[baptiste@localhost target]$ java -jar target\/vertx-fishs-1.0.0-SNAPSHOT-fat.jar<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Avec un poids de<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">[baptiste@localhost target]$ ls -alhs | grep -i snapshot \n 24M -rw-rw-r--.  1 baptiste baptiste  24M 16 f\u00e9vr. 21:23 vertx-fishs-1.0.0-SNAPSHOT-fat.jar<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Et une empreinte m\u00e9moire de<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">[baptiste@localhost target]$ jcmd 5780 GC.heap_info\n 5780:\n  garbage-first heap   total 516096K, used 62101K [0x000000060d200000, 0x0000000800000000)\n   region size 2048K, 29 young (59392K), 4 survivors (8192K)\n  Metaspace       used 32591K, capacity 33798K, committed 33920K, reserved 1079296K\n   class space    used 3700K, capacity 4192K, committed 4224K, reserved 1048576K<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">OpenApi<\/h3>\n\n\n\n<p>Le contrat de mon API est d\u00e9clar\u00e9e dans un fichier yaml.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"yaml\" class=\"language-yaml line-numbers\">openapi: 3.0.0\ninfo:\n  version: 1.0.0\n  title: Swagger Fishstore\n  license:\n    name: MIT\nservers:\n  - url: http:\/\/localhost:8080\/v1\npaths:\n  \/fishs:\n    get:\n      summary: List fishs\n      operationId: listFishs\n      tags:\n        - fishs\n      parameters:\n        - name: name\n          in: query\n          description: Restrict fish detail by name\n          required: false\n          schema:\n            type: string\n      responses:\n        200:\n          description: List of fishs\n          content:\n            application\/json:\n              schema:\n                $ref: \"#\/components\/schemas\/Fishs\"\n...\ncomponents:\n  schemas:\n    Fish:\n      type: object\n      required:\n        - id\n        - name\n      properties:\n        id:\n          type: integer\n          format: int64\n        name:\n          type: string\n        tag:\n          type: string\n    Fishs:\n      type: array\n      items:\n        $ref: \"#\/components\/schemas\/Fish\"<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Cot\u00e9 Java l&#8217;application source ce fichier de la fa\u00e7on suivante:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">RouterBuilder.<em>create<\/em>(vertx, \"src\/main\/resources\/webroot\/fishStore.yaml\").onComplete(ar -&gt; {\n  if (ar.succeeded()) {\n    Router global = this.getOpenApiRouter(ar.result());\n\n    vertx.createHttpServer()\n      .requestHandler(global)\n      .onSuccess(res -&gt; {});\n}<\/code><\/pre>\n\n\n\n<p>Et je route mes contextes vers mes op\u00e9rations en base de donn\u00e9es.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">private Router getOpenApiRouter(RouterBuilder routerBuilder) {\n  routerBuilder\n    .operation(\"listFishs\")\n    .handler(this::allFishsHandler)\n    .failureHandler(this::faillureHandler);\n\n  routerBuilder.operation(\"createFish\")\n    .handler(this::fishCreateHandler)\n    .failureHandler(this::faillureHandler);\n\n...\n\n  Router global = Router.<em>router<\/em>(vertx);\n\n  Router generated = routerBuilder.createRouter();\n  global.mountSubRouter(<em>\"v1\"<\/em>, generated);<\/code><\/pre>\n\n\n\n<p>En plus de pouvoir y brancher un Swagger, utiliser OpenAPI facilite la validation des param\u00e8tres et l&#8217;int\u00e9gration d&#8217;un syst\u00e8me d&#8217;authentification.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">HealthCheck<\/h3>\n\n\n\n<p>Pour d\u00e9finir un HealthCheck digne de ce nom, il faut qu&#8217;il soit en mesure de v\u00e9rifier que la base de donn\u00e9es  est disponible. Pour cela l&#8217;API de Health monitoring de Vert.x permet de facilement ajouter autant de contr\u00f4les que vous le souhaitez.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">private HealthCheckHandler healthHandler() {\n  HealthCheckHandler healthCheckHandler = HealthCheckHandler.<em>create<\/em>(vertx);\n  healthCheckHandler.register(\"check-database\", promise -&gt; {\n    dbService.isAvailable(res -&gt; {\n      promise.complete(res.succeeded() ? Status.<em>OK<\/em>() : Status.<em>KO<\/em>());\n    });\n  });\n  return healthCheckHandler;\n}<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Le r\u00e9sultat est consultable sur la route que vous avez d\u00e9finit et retourne un Json. <\/p>\n\n\n\n<p>Elle est compos\u00e9e de deux parties:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Une liste de contr\u00f4les additionnels, ici la pr\u00e9sence de la base de donn\u00e9es<\/li>\n\n\n\n<li>Un status global de l&#8217;application, produit cart\u00e9sien des v\u00e9rifications (status et outcome sont calcul\u00e9s de la m\u00eame fa\u00e7on)<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">{\"status\":\"UP\",\"checks\":[{\"id\":\"check-database\",\"status\":\"UP\"}],\"outcome\":\"UP\"}<\/code><\/pre>\n\n\n\n<p>L&#8217;API de Health est enti\u00e8rement compatible avec les normes du Cloud. Dans mon cas je me suis content\u00e9 d&#8217;impl\u00e9menter un seul HealthCheck mais rien ne vous emp\u00e8che d&#8217;impl\u00e9menter un contexte pour le Live et Ready ness.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Metrics<\/h3>\n\n\n\n<p>Pour information Vert.x utilise deux objects pour se lancer, un Launcher et un Verticle. Par d\u00e9faut  vous n&#8217;avez rien \u00e0 faire, pour la mise en place de Micrometer nous avons besoin de les impl\u00e9menter.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">public class FishLauncher extends Launcher {\n  public static void main(String[] args) {\n    new FishLauncher().dispatch(args);\n  }\n\n  @Override\n  public void beforeStartingVertx(VertxOptions options) {\n    \/\/ METRICS\n    options.setMetricsOptions(new MicrometerMetricsOptions()\n      .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true)\n        .setStartEmbeddedServer(true)\n        .setEmbeddedServerOptions(new HttpServerOptions().setPort(8081))\n        .setEmbeddedServerEndpoint(\"\/metrics\"))\n      .setEnabled(true));\n   }\n...\n}<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Ici je d\u00e9cide d&#8217;utiliser Micrometer (plusieurs impl\u00e9mentations sont disponibles). Sa mise en place s&#8217;effectue \u00e0 l&#8217;exterieur d&#8217;un Verticle. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"\" class=\"\"># HELP vertx_http_server_request_bytes Size of requests in bytes \n# TYPE vertx_http_server_request_bytes \nhistogram vertx_http_server_request_bytes_bucket{method=\"GET\",le=\"1.0\",} 3.0 \n...\nvertx_pool_usage_seconds_count{pool_type=\"worker\",} 1617.0 \nvertx_pool_usage_seconds_sum{pool_type=\"worker\",} 1.147378429 \n# HELP vertx_pool_usage_seconds_max Time using a resource \n# TYPE vertx_pool_usage_seconds_max gauge vertx_pool_usage_seconds_max{pool_type=\"datasource\",} 0.0 vertx_pool_usage_seconds_max{pool_type=\"worker\",} 0.001223763 \n# HELP vertx_eventbus_delivered_total Number of messages delivered to handlers \n# TYPE vertx_eventbus_delivered_total counter \nvertx_eventbus_delivered_total{side=\"local\",} 2.0 \n# HELP vertx_eventbus_processed_total Number of processed messages \n# TYPE vertx_eventbus_processed_total counter \nvertx_eventbus_processed_total{side=\"local\",} 2.0 \n# HELP vertx_pool_completed_total Number of elements done with the resource \n# TYPE vertx_pool_completed_total counter \nvertx_pool_completed_total{pool_type=\"datasource\",} 2.0 \nvertx_pool_completed_total{pool_type=\"worker\",} 1617.0<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Et voila un flux tout beau tout propre pr\u00eat \u00e0 \u00eatre exploit\u00e9 par Prometheus !<\/p>\n\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Vert.x Shell<\/h3>\n\n\n\n<p>En bonus un petit service qui fait toujours plaisirs, une CLI pour interagir votre application!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">ShellService service = ShellService.<em>create<\/em>(vertx,\n  new ShellServiceOptions().setTelnetOptions(\n    new TelnetTermOptions().\n      setHost(\"localhost\").\n      setPort(4000)\n  )\n);\nservice.start();<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"354\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/image-1024x354.png\" alt=\"\" class=\"wp-image-459\" srcset=\"https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/image-1024x354.png 1024w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/image-300x104.png 300w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/image-768x266.png 768w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/image.png 1371w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<p>Je vous invite a consulter l&#8217;int\u00e9gralit\u00e9 du code sur GitLab, vous y trouverez la partie persistance, l&#8217;utilisation de Service proxy, la gestion des confs le Hot Reload etc etc.<\/p>\n\n\n\n<p class=\"has-text-align-center\"><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/gitlab.com\/bmeynier\/Vert.x\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2020\/11\/gitlab.png\" alt=\"\" class=\"wp-image-176\" width=\"109\" height=\"101\"\/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"has-text-align-center\"><em>Code source<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Conclusion<\/h1>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"490\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/conclusion-2-1024x490.png\" alt=\"\" class=\"wp-image-529\" srcset=\"https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/conclusion-2-1024x490.png 1024w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/conclusion-2-300x144.png 300w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/conclusion-2-768x368.png 768w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/conclusion-2-1536x735.png 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Les questions que tu te poses <\/h2>\n\n\n\n<p><strong>C&#8217;est un framework tr\u00e8s bas niveau compliqu\u00e9 \u00e0 utiliser ?<\/strong><\/p>\n\n\n\n<p>Non, ces concepts sont diff\u00e9rents de ceux utilis\u00e9s dans le monde du backend Java standard, mais son API est particuli\u00e8rement riche et agr\u00e9able \u00e0 utiliser. Un d\u00e9veloppeur Front-End ne serait absolument pas d\u00e9pays\u00e9. Vous trouverez \u00e9norm\u00e9ment de documentation sur le net.<\/p>\n\n\n\n<p><strong>Est-il possible d&#8217;utiliser Spring et Vert.x en meme temps ?<\/strong><\/p>\n\n\n\n<p>Oui n&#8217;oubliez pas qu&#8217;il s&#8217;agit d&#8217;une boite \u00e0 outils et non d&#8217;un framework, vous trouverez facilement des <a rel=\"noreferrer noopener\" href=\"https:\/\/www.baeldung.com\/spring-vertx\" target=\"_blank\">tutoriaux <\/a>sur le net.<\/p>\n\n\n\n<p><strong>Est il possible d&#8217;utiliser un Spring Config Server Store ?<\/strong><\/p>\n\n\n\n<p>Oui, direction la <a href=\"https:\/\/vertx.io\/docs\/vertx-config\/java\/#_spring_config_server_store\" target=\"_blank\" rel=\"noreferrer noopener\">documentation officielle<\/a>.<\/p>\n\n\n\n<p><strong>Pour quel genre d&#8217;application est il pertinent d&#8217;utiliser Vert.x ?<\/strong><\/p>\n\n\n\n<p>Vert.x exc\u00e8le dans le traitement des flux volumineux. je vous invite \u00e0 consulter sa fonctionnalit\u00e9 de parsing des <a href=\"https:\/\/github.com\/vert-x3\/vertx-examples\/tree\/4.x\/core-examples\/src\/main\/java\/io\/vertx\/example\/core\/net\/stream\" target=\"_blank\" rel=\"noreferrer noopener\">Streams<\/a> et son API de <a href=\"https:\/\/github.com\/vert-x3\/vertx-examples\/tree\/4.x\/core-examples\/src\/main\/java\/io\/vertx\/example\/core\/jsonstreaming\" target=\"_blank\" rel=\"noreferrer noopener\">traitement de fichiers<\/a>.<\/p>\n\n\n\n<p><strong>Dois-je utiliser Vert.x si la base de donn\u00e9es de mon application est de type Sql relationnel ?<\/strong><\/p>\n\n\n\n<p>Vous l&#8217;avez vu dans l&#8217;exemple, il est tout \u00e0 fait possible d&#8217;utiliser JDBC avec Vert.x, cependant n&#8217;oubliez pas que JDBC n&#8217;en reste pas moins une  API bloquante. A noter que pour palier ce probl\u00e8me Vert.x d\u00e9ploiera un pool de type worker.  <\/p>\n\n\n\n<p><strong>Est il possible de convertir son application Vert.x en code natif via GraalVM?<\/strong> <\/p>\n\n\n\n<p><a href=\"https:\/\/how-to.vertx.io\/graal-native-image-howto\/\" target=\"_blank\" rel=\"noreferrer noopener\">Oui<\/a><\/p>\n\n\n\n<p><strong>Je n&#8217;ai jamais entendu parler de Vert.x qui l&#8217;utilise ?<\/strong><\/p>\n\n\n\n<p>Vert.x est tr\u00e8s largement utilis\u00e9, voici une liste non exhaustive:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"46\" src=\"http:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/banderole_companies.png\" alt=\"\" class=\"wp-image-505\" srcset=\"https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/banderole_companies.png 1024w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/banderole_companies-300x13.png 300w, https:\/\/baptiste-meynier.com\/wp-content\/uploads\/2021\/02\/banderole_companies-768x35.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-default\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Twitter<\/h2>\n\n\n\n<p><a href=\"https:\/\/twitter.com\/timfox?lang=fr\">https:\/\/twitter.com\/timfox<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/twitter.com\/clementplop?lang=fr\">https:\/\/twitter.com\/clementplop<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/twitter.com\/jponge\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/twitter.com\/jponge<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/twitter.com\/tsegismont\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/twitter.com\/tsegismont<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/twitter.com\/vertx_project\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/twitter.com\/vertx_project<\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Sources<\/h2>\n\n\n\n<p><a href=\"https:\/\/vertx.io\/\">https:\/\/vertx.io\/<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/start.vertx.io\/\">https:\/\/start.vertx.io\/<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/www.reactivemanifesto.org\/fr\">https:\/\/www.reactivemanifesto.org\/fr<\/a><\/p>\n\n\n\n<p><a href=\"http:\/\/reactivex.io\/\">http:\/\/reactivex.io\/<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/www.manning.com\/books\/vertx-in-action\">https:\/\/www.manning.com\/books\/vertx-in-action<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/fr.wikipedia.org\/wiki\/Mod%C3%A8le_d%27acteur\">https:\/\/fr.wikipedia.org\/wiki\/Mod%C3%A8le_d%27acteur<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_enterprise_linux_atomic_host\/7\/html\/managing_containers\/finding_running_and_building_containers_with_podman_skopeo_and_buildah\">https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_enterprise_linux_atomic_host\/7\/html\/managing_containers\/finding_running_and_building_containers_with_podman_skopeo_and_buildah<\/a><\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/www.youtube.com\/watch?v=8aGhZQkoFbQ&amp;ab_channel=JSConf\" target=\"_blank\">https:\/\/www.youtube.com\/watch?v=8aGhZQkoFbQ&amp;ab_channel=JSConf<\/a><\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/www.youtube.com\/watch?v=3_CRKfs4Zzo&amp;ab_channel=OracleDevelopers\" target=\"_blank\">https:\/\/www.youtube.com\/watch?v=3_CRKfs4Zzo&amp;ab_channel=OracleDevelopers<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/burrsutter\/vertx_ha_demo\">https:\/\/github.com\/burrsutter\/vertx_ha_demo<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/vert-x3\/vertx-examples\">https:\/\/github.com\/vert-x3\/vertx-examples<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/sdkman.io\/sdks#vertx\">https:\/\/sdkman.io\/sdks#vertx<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lors du d\u00e9veloppement d&#8217;une application nous pensons souvent \u00e0 la maintenabilit\u00e9 du code, sa robustesse et la performance. Il y a un crit\u00e8re que nous mettons souvent de cot\u00e9 c&#8217;est la notion de co\u00fbt de l&#8217;infrastructure. Cette probl\u00e9matique se pose de plus en plus, que se soit dans le monde des Cloud publics ou du &hellip;<\/p>\n","protected":false},"author":1,"featured_media":439,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[8],"tags":[],"class_list":["post-277","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bigdata"],"_links":{"self":[{"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/posts\/277","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/comments?post=277"}],"version-history":[{"count":246,"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/posts\/277\/revisions"}],"predecessor-version":[{"id":1853,"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/posts\/277\/revisions\/1853"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/media\/439"}],"wp:attachment":[{"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/media?parent=277"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/categories?post=277"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/baptiste-meynier.com\/index.php\/wp-json\/wp\/v2\/tags?post=277"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}