What is Vert.x? What is it for?
Vert.x is a multi-language toolkit based on the JVM and used in software applications to implement
asynchronous and event driven structures.
However, to better understand its use, we must take a step back and explain what asynchronous programming is.
Usually a program executes instructions sequentially on a single thread and while a function is running,
it waits for it to finish before continuing with the next instruction, this is known as blocking execution.
Task B blocking execution:
Main Thread: |_Task A_| --> |______Task B______| --> |_Task C_|
Fortunately, modern computers are equipped with processors that are made of multiple cores that can execute instructions
in parallel (multithreading). A program can therefore proceed normally on the main thread while one of its
functions executes its own code on another thread in parallel.
However, the process is still synchronous, because if the main thread at some point needs the result of the
function on the other thread, and the calculation is still ongoing, then an exception is thrown.
Task C ends after the start of task D then an exception is thrown (task D needs the result of task C):
Main Thread: |_Task A_| --> |_Task B_| --> |_Task D_| --> exception Secondary Thread: --> |______Task C______|
To solve this problem, asynchronous programming comes into play with the use of special APIs, which allow you to define actions to be performed as soon as the result of a specific function becomes available.
Task C generates the promise of a value while Task D knows that it must wait for this asynchronous result before processing its code:
Main Thread: |_Task A_| --> |_Task B_| --> async-result --> |_Task D_| Promise: --> |______Task C______|
One tool that allows you to use the asynchronous programming is Vert.x
- highly modular and consists of several components that can be used according to one's needs, in fact it cannot be defined as a framework, rather it should be considered a set of libraries.
- light (the core is about 650kB), high-performance and simple to use. Therefore, ideal for the development of microservices and more ...
- Core: basic functionality with support for HTTP, TCP, file system access and various other features.
- Web: tool-kit to write sophisticated web applications and HTTP microservices.
- Data Access: asynchronous clients that can be used to access your PostgreSql, MySql, MongoDb, ...
- Testing: integration and support of unit tests on asynchronous code.
- Authentication and Authorisation: provides API for authentication and authorization with JWT, OAuth 2, JDBC auth, Mongo auth, ...
- Devops: offers several components to monitoring the app while it runs in production (metrics, health checks, ...)
- Reactive: add-ons to make an application even more responsive.
- Microservices: components to build applications based on microservices.
- MQTT: provides clients and servers which are able to open, manage and close a communication through MQTT.
- Messaging: provides clients and servers which are able to communicate via AMQP, STOMP or RabbitMQ protocol.
- Integration: provides clients to interact with Apache Kafka, Consul or send SMTP emails.
- Event Bus Bridge: offers several "bridges" to extend the use of the Event Bus outside the app via TCP ports.
- Clustering: supports different types of clustering (Hazelcast, Infinispan, Apache Ignite, Apache Zookeeper).
- Services: useful services for encapsulating reusable functionality in other places, which are distributed using an identifier.
- Cloud: tool to build an OpenShift platform for cloud applications.
- Advanced: advanced tools to be used in particular projects but which are not normally used.
To understand how Vert.x allows implementing asynchronous programming, two key concepts must be clarified: what is a Verticle and what are Event Buses for?
Verticle is the deployment unit in Vert.x, which processes incoming events using an Event Loop on a specific Thread. By default, two Event Loops are connected to each Thread Core of the CPU. A Verticle can be instantiated several times.
On the other hand, when we talk about Events we mean, for example, the reception of "network buffers", "timing events" or the reception of messages from other Verticles.
The Event Bus is the communication channel that Verticles used to send messages asynchronously. The type of data exchanged can be of any type, but it is preferable to use the JSON format since it can be understood by all languages.
The supported communication patterns are: Point-to-Point messaging (direct message), Request / Response messaging and Publish / Subscribe messaging (to send messages in broadcast).
The Event Bus can also be distributed, meaning Verticles that are not necessarily running on the same machine can communicate with each other. In addition, thanks to the "bridges" it can also communicate with generic messaging protocols such as AMQP and STOMP.
After understanding the architecture behind Vert.x, now let's try to understand the two main constructs of asynchronous programming: Promise and Future.
In abstract terms, Future and Promise can be thought of as values that at a certain point in time become available and therefore require a certain amount of time to be calculated or retrieved. For this reason, two states in which a Future / Promise can be found are generally recognized: Completed / Determined when the value is available or Incomplete / Indeterminate when the value has not yet been calculated.
In Vert.x there are Promise and Future constructs that refer to these abstractions:
- Future: reference, read-only, at a value yet to be calculated
- Promise: variable, assignable only once, to which Future refers
In other words, a Future shows the value previously written in a Promise in read-only mode.
NOTE: do not confuse Vert.x futures with Java ones!
So in conclusion Vert.x is a very useful tool that allows us to use asynchronous programming in different areas and
which however carries some advantages and disadvantages.
- scalability, being modular allows it to be used only where it is deemed necessary
- microservices, being light but at the same time performing it is ideal for the development of microservices
- versatility, by supporting different languages you are not bound to use one that you don't know or don't like
- learning curve, it takes time to fully understand the mechanisms behind the Vert.x modules
- backpressure, which must be managed to avoid memory problems
- delays, if an event is not properly handled it can generate unexpected delays