23

Microservices are gaining traction as an software architecture style that will better support continuous delivery, provide a model for rapid deployment and separation of concerns.

Vert.x 3 and Vert.x-Apex provide an interesting model for building a microservices. As one of the examples shows, a simple verticle can expose an HTTP service, so a REST service is available. The verticle binds its own tcp port.

When scaling up to multiple micro-services to support a full application you end up with a number of choices. Any thoughts on what style could eventually support continuous delivery, and minimizing downtime on upgrades?

Options

  1. Run multiple verticles could be a solution, all containing there own routing, so http handling is contained in the verticle. A request/response can be handled completely by the verticle. This could mean that every verticle runs on it's own tcp port.
  2. Using a router you can expose all paths on a single port, and handle them accordingly. Data will be handled by the verticle that contains the router, possible passing it on to other verticles. This then starts to look like a more monolithic approach.
  3. Run separate instances of vert.x containing the service (possible cluster them). This could make it easier use continuous delivery, because the whole thing is self-contained.
  4. Other possible options?

Deployment

On the deployment side rapid deployment of new services would be desirable, without bringing the whole application down.

  • Option 3. could provide a way for this, but can also cause overhead, especially when there is a DB verticle running in every verticle.
  • Option 1. could be easier, but what about reloading the new and updated verticles.

Separate micro-services offer an interesting way of development, but offers some challenges in orchestration and deployment.

Any thoughts?

Wieki
  • 395
  • 2
  • 11

3 Answers3

14

Let's start with terminology.

  • A verticle is a Java class that usually extends AbstractVerticle and implements a start(..) method. A verticle can expose one or more HTTP endpoints and expore one or more eventbus endpoints.
  • A verticle runs inside a Vert.x application (previously called a 'module'). An application can contain one or more verticles. I usually keep it 1:1 to keep things small and simple.
  • A Vert.x application runs inside a Vert.x instance. You can run multiple instances of an application to increase parallelization.
  • A Vert.x instance runs inside a Vert.x container. A container is a running process with one or more instances of an application.
  • A Vert.x container runs inside a JVM.

When building a microservices-style application with Vert.x, you typically want small independent logical units of work, call them services. Such a service should ideally run in its own process, be self-contained and indepedently upgradeable. Mapping it to the terminology above: build the service as a Vert.x application containing a single Verticle with the service logic.

Vert.x applications communicate with each other using the distributed eventbus, built with Hazelcast. This means that multiple JVM's running on the same server, or even on multiple servers, can communicate with each other over the Vert.x eventbus.

A web application built with Vert.x usually consists of one or more Vert.x applications exposing REST endpoints communicating over the eventbus with one or more Vert.x applications exposing (internal) eventbus endpoints.

To answer your question: option 3 is the most common in Vert.x setups, and stays the closest to a microservices architecture. You can choose between 2 options there: you either run 1 application with a REST endpoint that handles all HTTP calls and delegates request processing over the eventbus to other applications, or you give each service (or at least, each service providing functionality for end users) its own REST endpoint. The latter is a bit more complex to setup since there are multiple HTTP endpoints to connect to from the frontend, but it's more scalable and has less single points of failure.

Bert Jan Schrijver
  • 1,521
  • 10
  • 16
  • Would you be able to expand on "an application can contain one or more verticles"? I'm not following the difference between vx application and a vx verticle, specifically in the case of a "main" class that extends AbstractVerticle and is started with `$ vertx run com.my.verticles.Main`. What would the "application" be here? – Draculater Sep 25 '18 at 16:15
  • A Vert.x application needs a Verticle as entry point. So you need at least 1 Verticle. But, you can also deploy other Verticles programmatically from the "main" verticle. See https://github.com/bertjan/vertx3-examples/blob/master/basic-eventbus/src/main/java/nl/revolution/vertx3/eventbus/basic/VertxStarter.java for an example. – Bert Jan Schrijver Sep 26 '18 at 18:08
  • 1
    I was referring to the `vertx.deployVerticle(..);` statements in the example. Don't let the fact that the VertxStarter class has a (Java) main method that gets an instance of Vertx using Vertx.vertx(); confuse you ;-) (and it's not necessary to extend AbstractVerticle in that case, too) – Bert Jan Schrijver Sep 26 '18 at 18:10
3

Vert.x currently has a number of official modules for creating microservices architectures, that - I believe - did not exist at the time your question was phrased.

These are the official Microservices modules:

  • Vert.x Service Discovery - publish, lookup and bind to any type of services.
  • Vert.x Circuit Breaker - provides an implementation of the circuit breaker pattern for Vert.x
  • Vert.x Config - provides an extensible way to configure Vert.x applications.

And there are more official modules that come in handy:

  • Metrics using Dropwizard - gets metrics from core components and sends to Dropwizard.
  • Metrics using Micrometer - gets metrics from core components and sends to Micrometer.
  • Vert.x Health Check - provides a simple way to expose health checks.
  • Vert.x Clustering - support for Hazelcast, Zookeeper, Apache Ignite and Infinicast
  • Vert.x Services - simple and effective way to encapsulate reusable functionality for use elsewhere.

There are many more official modules you can incorporate in your microservices design.

And also there are some great articles on how to apply them in practice:

And finally if you want to see code that goes much further than HelloWorld, then look at:

And there is much more code to be had (like an API Gateway, though Readme in Chinese).

Arnold Schrijver
  • 3,588
  • 3
  • 36
  • 65
0

I think you've got to have solid scalability reasons for partitioning your services, and there isn't any one-size-fits-all approach to dealing with the lifecycle and addressing issues you'll run into getting those services interacting with each other. Whether a 'verticle' or some other thing is listening on a socket, I'd have thought that limiting the number of endpoints/addresses would cause the fewest headaches in that direction. In any case, the code-entity responsible for associating a given verticle to its socket would need to expose lifecycle-controls to some orchestration framework somehow ... just as it would if it were not a verticle listening there.

David Bullock
  • 6,112
  • 3
  • 33
  • 43