Learn Vert.x And Build Ultra High Performance Servers With The Language You Want

Vert.x Provides Top Tier Performance and Allows You To Use Almost Any Major Language Out There

Connection network in dark servers data center room storage systems 3D rendering

Vert.x is one of the top performing server frameworks on Techempower. Most benchmarks have it within roughly 20% or less of the top performer, which is usually Rust Actix. Realistically that difference is nothing. It is also orders of magnitude faster than Node and Python related frameworks. On top of all this performance goodness, Vert.x is Polyglot. Since Vert.x uses the GraalVM runtime it supports the use of multiple languages including JavaScript, Kotlin, Scala, Java, Groovy, and Ruby.

If you prefer video learning

Where To Start

Let’s start at a high level in understanding Vert.x. Vert.x at its core is not a server framework. It’s more like a set of components for building event driven high performance applications. In other words Vert.x provides base level components that allow you to go off and build almost anything that requires very high performance. The main feature that allows this is the event loop (they also use the label Reactor Pattern).

If you’re a node developer you’ve probably already heard of the event loop concept. The event loop is an iteration looping mechanism that allows code to run asynchronously without using threads. In other words the system depends on callbacks instead of threads to scale. For programming old timers this may seem strange. But the reality is that threads do not scale. Although threads are generally tiny they still take up memory and require management by the operating system, not to mention having contention issues for shared memory. This ultimately limits their maximum scalability. You can see this is true because most thread based servers on Techempower don’t even make it to the top twenty.

So then why does asynchronous IO work better than threads. Because scalability for services is about simultaneous connections, more than CPU brute force. In other words it is an inherently IO bound activity. Threads on the other hand perform better for CPU bound activity. Note I’ll start writing vertx as the name to make it easier to type.

Verticle, The Core of Vert.x

So what else is there to know about Vert.x? Vertx at its core is made up of several sub components. Foremost is the verticle. A verticle is the minimum possible structure needed to create a vertx application. So you can think of it as a parent or container object, even though it’s possible to have more than one. All other components within a vertx application need to be initiated and setup from a verticle.

Inside every verticle is at least one event loop inside of a thread. Event loops live inside a thread because it is possible to have more than one event loop per verticle instance. Therefore having threads allows more cpu cores to be used to enhance scalability. There is an event loop thread pool from which verticle instances can get their event loops. As mentioned the event loop is the main “engine” that does the work of iterating in a loop. Each iteration will execute some action, for example accepting and then handling some request. Note the event loop itself is not inherently asynchronous. It’s only a mechanism to execute tasks in an iteration loop. So it is important not to have blocking code running in your event loop. There are several ways to avoid this which we’ll get into in a later article.

Next is something called the Context. The Context, as the name implies, is where data is shared within an event loop thread or worker thread. You can think of it as a simple session state for sharing data. According to the docs a context object is associated to a single event loop thread. Now because event loops exist inside a thread pool and can be shared among several vertx instances its not clear to me how constraining data to a specific set of services might work. I suppose you could simply add a prefix to your data keys to indicate some sort of grouping. But since the docs don’t comment I think this is a case specific implementation detail you’re going to need to work out. If you need to share data at a higher level, between verticles or vertx cluster nodes you can use the SharedData API.

EventBus, Vert.x Central Nervous System

In vertx it is possible to have multiple verticle instances. For example if you have a web server you might create a verticle handling http requests. Since a typical http server has numerous routes and some of them have complex handler logic it is possible that you might create a separate verticle for each route, both for logical structure and performance. Additionally, because vertx is Polyglot, you might write the http verticle in Java and some of the route handler verticles in JavaScript, in order to take advantage of language features or dependencies specific to that verticle business logic. So now you have multiple verticles that are distinct but need to communicate with each other. The EventBus allows this communication. It’s more complex than this simple explanation of course, and the docs say so as well, but I like to think of it as basically a pub/sub system for sending messages. By the way the default message passing format is JSON.

Simple Starter App

To get started let’s create a new project. One easy way to create a new project is to use the project creator on the vertx.io website. Go to the url https://start.vertx.io/ and select the following settings as displayed in the following.

Let’s take this project and open it with VSCode. Once you have downloaded it and opened it you should see a folder structure like this

Every vertx project will use a project and package manager. In our case we selected Maven. The pom.xml file will store our dependencies and list our basic configuration information for the app like the name and the main launching class name. In this case MainVerticle. We also selected Java as the main language, but in a later article I’ll show you how you can also create verticles using JavaScript.

Let’s start writing code. Open the file MainVerticle.java and add this code.

package com.example.starter;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;

public class MainVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> start) throws Exception {
    
  } 
  
  public static void main(String[] args){ 
    Vertx.vertx().deployVerticle(new MainVerticle());
  }
}

As you can see a verticle must inherit from the base AbstractVerticle interface. Now normally you do not need to create a main method, because the pom.xml file is already telling the project which class to run on load. However if you want to use the VSCode debugger you do need this method as the debugger looks for it. So then let’s setup debugging for this project. Go to the debugger section and select the create launch configuration link. It will create a file for you and pre-populate it. Your’s should look like this.

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "java",
            "name": "Debug (Launch)-MainVerticle<starter>",
            "request": "launch",
            "mainClass": "com.example.starter.MainVerticle",
            "projectName": "starter",
            "cwd": "${workspaceFolder}/src"
        }
    ]
}

Notice the cwd variable. Any source files should go there, like our MainVerticle.java, and also any config files should also go there. Now going back to the MainVerticle.java code if you look at the method main you will see that vertx is being instantiated there by calling deployVerticle and instantiating itself with new MainVerticle. Place a break point on that line and run the debugger we just created previously. It should break on that break point.

Now let’s update our start function and startup an http server. Add this code to MainVerticle.java

@Override
  public void start(Future<Void> startFuture) throws Exception {
    vertx.createHttpServer().requestHandler(req -> {
      req.response()
        .putHeader("content-type", "text/plain")
        .end("Hello from Vert.x!");
    }).listen(8888, http -> {
      if (http.succeeded()) {
        System.out.println("HTTP server started on port 8888");
      } 
    });
  }

If you run this code with the debugger it will go to the main method first and then run start. Start is the function that is supposed to initialize anything inside of your verticle. In this case we are enabling http services with the call to createHttpServer. However we could also use deployVerticle to create other verticles that are specialized to do specific tasks for our app. For example the route handling that I mentioned previously. Once you run this code you should see this on the terminal and browser.

In this article we covered the conceptual details of how Vert,x works and showed a simple example of how to get a base project started. In the next article I’ll show how to create route handlers for the http server. And how to deploy additional verticles.

Published by David Choi

Developer Lead DzHaven.com. Where devs help devs and make money.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: