vert.x 3
TRANSCRIPT
Vert.x 3high performance polyglot application toolkit
Xavier MARIN
@XavMarinhttps://github.com/Giwi
Architecte chez @cmarkeaCTO chez @qaobee
Petite histoire
● Créé par Tim Fox @timfox ● en 2011 ● sous le nom de Node.x● 24/06/2015 sortie de la v3
Vocabulaire pour commerciaux
Simple threadSafe concurrent
asynchronous eventDriven reactive
eventBus over a scalable polyglot
embeddable toolkit plateform
Le problème
● Répondre à un grand nombre de clients en même temps
● C10k = 10 000 connexions simultanées
C10k
C10k
C10k
C10k
C10k
Tomcat : 200 threads = 200 connexionsLes appels suivants doivent attendre
C10k
● scalable verticalement et horizontalement● distribué● événementiel et asynchrone● I/O non bloquantes● tolérant à la panne● extensible
Fonctionnalités
Le déploiement :
● Compilation à la volée du source : Java, Groovy, etc...
● Trouve les ressources sur en local ou dans un repo maven
● CLI / main(String[] args) / Maven / Gradle ● Classloader :Isolation par classloader
optionnelle
Fonctionnalités
La stack native :
● Vert.x core● Vert.x Web
○ Routages et sous-routages○ Sessions○ Cookies○ Sécurité (basic auth, shiro, JWT, …)○ Templates (Handlebars, Jade, MVEL, Thymeleaf)○ SockJS○ Static files○ …
Fonctionnalités
● Accès aux données○ MongoDB, JDBC, Redis, SQL Common
● Intégration○ Mail et JCA
● Sécurité○ basic auth, shiro, JWT, JDBC Auth
● Reactive○ Vert.X Rx, Reactive streams
● Metrics● Vert.X unit
Fonctionnalités
● Clients / Serveurs TCP/SSL● Clients / Serveurs HTTP/HTTPS● REST et Multipart● Websockets et Sock.js● Accès distribué de l'Event-bus● Maps et Sets partagés● Logging
Nouveautés Vert.x 3
● Les API Vert.x 2 sont maintenues à la main ● Vert.x 3 génère les API
○ Codegen○ Basé sur des templates MVEL
● JavaScript, Groovy, RxJava – Ruby à venir, etc ...
● Maintenance automatique● Les API de la stack entière sont générées● Documentation polyglotte
Nouveautés Vert.x 3
● L’API Core reste fondamentalement identique
● Supprime les inconvénients de Vert.x 2● Déploiement de services ● Support de Java8
○ streams et lamdas (yummi yummi !)● Support de RxJava, RxGroovy, RxJS ● Une stack “supportée” : composant *
langage
JVM polyglotte
Dois-je coder en java pour exécuter un programme sur la JVM?
Oui, mais pas que, fais-toi plaisir!
JVM polyglotte
On peut programmer en plus de 200 langages
Java, JavaFX, Ceylon, Gosu, Groovy, Clojure, Rhino Nashorn, Mirah, Scala, JRuby, Xtend, JPython, Fantom, Oxygene, Kotlin, …
L’intérêt : à chaque problème sa solution“Quand on n’a qu’un marteau dans la main, les vis
ressemblent à des clous”
Polyglottevar vertx = require('vertx-js/vertx');
var server = vertx.createHttpServer(); var response = request.response(); response.putHeader('content-type', 'text/plain'); response.end('Hello World!');});
server.listen(8080);
$> vertx run server.js --instances 32$> java -jar my-app-fat.jar --instances 32
Polyglotteserver = vertx.create_http_server()
server.request_handler() { |request| response = request.response() response.put_header("content-type", "text/plain") response.end("Hello World!")}
server.listen(8080)
$> vertx run server.rb --instances 32$> java -jar my-app-fat.jar --instances 32
Polyglottedef server = vertx.createHttpServer()
server.requestHandler({ request -> def response = request.response() response.putHeader("content-type", "text/plain") response.end("Hello World!")})
server.listen(8080)
$> vertx run Server.groovy --instances 32$> java -jar my-app-fat.jar --instances 32
Polyglottepublic class Main {
public static void main(String[] args) {
HttpServer server = vertx.createHttpServer(); server.requestHandler(request -> { HttpServerResponse response = request.response();
response.putHeader("content-type", "text/plain"); response.end("Hello World!"); }); server.listen(8080); }
}
$> vertx run Server.java --instances 32$> java -jar my-app-fat.jar --instances 32
Cluster et haute disponibilité
Clustering$> java -jar my-app-fat.jar --instances 32 -cluster
Automatic failover● Quand un noeud tombe, ses verticles sont redéployés
sur les autres noeuds du cluster
$> vertx run my-app.js -cluster -ha
Verticle
● Unité de déploiement de base● Model Actor● S’exécute toujours dans le même thread● Peut avoir plusieurs instances● Isolé dans son classLoader● Communique via l’event-bus● Peut se partager des données
○ maps○ counters○ locks
VerticlesJsonObject config = config().getObject("verticle_conf");
// Start the verticles that make up the app
vertx.deployVerticle("verticle1.js");
DeploymentOptions options = new DeploymentOptions().setInstances(16);vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options);
DeploymentOptions options2 = new DeploymentOptions().setConfig(config);
vertx.deployVerticle("verticle2.rb", options2);
vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", res -> {
if (res.succeeded()) {
System.out.println("Deployment id is: " + res.result());
} else {
System.out.println("Deployment failed!");
}
});
Event-bus
Event-bus
● Permet aux Verticles de communiquer● Agnostique du langage utilisé● Fonctionne au travers du cluster● S'étend jusqu'à la partie client● Types de messages
○ number○ string○ boolean○ JSON object○ Vert.x Buffer
Event-bus
● Enregistrer un handler● Dé-référencer un handler● Adresses● Messages
○ Publish / subscribe○ Point à point
Event-bus
Enregistrer un handler
EventBus eb = vertx.eventBus();eb.consumer("news.uk.sport", message -> {
System.out.println("I have received a message: " + message.body());
message.reply("how interesting!");});
Event-bus
Enregistrer un handlerMessageConsumer<String> consumer = eb.consumer("news.uk.sport");consumer.completionHandler(res -> { if (res.succeeded()) { System.out.println("Registration has reached all nodes"); } else { System.out.println("Registration failed!"); }});
consumer.unregister(res -> { if (res.succeeded()) { System.out.println("Un-registration has reached all nodes"); } else { System.out.println("Un-registration failed!"); }});
Event-bus
Publish Subscribe :eventBus.publish("news.uk.sport", "You kicked a ball");
Point à point :eventBus.send("news.uk.sport","You kicked a ball",ar ->{ if (ar.succeeded()) { System.out.println("reply: " + ar.result().body()); }});
Ajout d'en-têteDeliveryOptions options = new DeliveryOptions();options.addHeader("some-header", "some-value");eventBus.send("news.uk.sport", "You kicked a ball",
options);
Module Web
Le routeur :
Route route = router.route(HttpMethod.PUT, "myapi/orders") .consumes("application/json") .produces("application/json");
route.handler(routingContext -> {
// This would be match for any PUT method to paths starting with
// "myapi/orders" with a content-type of "application/json" // and an accept header matching "application/json"
});
Module Web
Le routeur : Router restAPI = Router.router(vertx);restAPI.get("/products/:productID").handler(rc -> { // TODO Handle the lookup of the product.... rc.response().write(productJSON);});restAPI.put("/products/:productID").handler(rc -> { // TODO Add a new product... rc.response().end();});Router mainRouter = Router.router(vertx);// Handle static resourcesmainRouter.route("/static/*").handler(myStaticHandler);mainRouter.route(".*\\.templ").handler(myTemplateHandler);mainRouter.mountSubRouter("/productsAPI", restAPI);
$curl http://localhost:8080/productsAPI/products/product/1234
Module Web
Le routeur : router.route().path("/*")
.consumes("application/json")
.handler(routingContext -> {HttpServerResponse response = routingContext.response();response.putHeader("content-type", "application/json");routingContext.next();
});
router.get("/beers/").handler(routingContext -> {JsonObject query = new JsonObject();mongoClient.find("beers", query, res -> {
if (res.succeeded()) {JsonArray jar = new JsonArray();res.result().forEach(jar::add);routingContext.response().end();
} else { res.cause().printStackTrace(); } });}
Benchmarks
Source : https://www.techempower.com/benchmarks/#section=data-r8&hw=i7&test=plaintext
Cloud ready
● Vert.x OpenShift Cartridge○ https://github.com/vert-x3/vertx-openshift-cartridge
● Vert.x OpenShift Using DIY Cartridge○ https://github.com/vert-x3/vertx-openshift-diy-quickstart
● Vert.x Docker Images○ https://github.com/vert-x3/vertx-stack/tree/master/stack-docker
Production ready
Bonus
Si vous aimez vraiment Tomcat :
Exposer une API REST : http://sparkjava.comimport static spark.Spark.*;
public class HelloWorld { public static void main(String[] args) { get("/hello", (req, res) -> "Hello World"); }}
Bonus
Si vous aimez vraiment Tomcat :
Consommer une API REST : http://unirest.ioHttpResponse<JsonNode> jsonResponse = Unirest.post("http://httpbin.org/post") .queryString("name", "Mark") .field("last", "Polo") .asJson();
The end ...
« Si vous avez compris ce que je viens de vous dire, c’est que je me suis probablement mal exprimé »
A. Greenspan
https://github.com/Giwi/vertx3-angular-beers