Building microservices with Vert.x by Bert Jan Schrijver

Source

My name is Bert-Jan Schrijver. I'm a software craftsman at J-Point in the Netherlands. Until last Monday, I also worked at Malmberg in the Netherlands, which is an educational publisher. I just had my last day there, not because I hated the place.

I loved the place, but it was time for me to do something else. However, this story is about what we're doing at Malmberg. In my spare time, I'm also a Java User Group leader for NLJUG, the Dutch Java User Group. There are a few cameras in here, right up front, and a few over there.

Good to see you. For the next 15 minutes, I will start with an introduction to set the context of the company where we are using Vertex. I will explain why we chose Vertex, which was about three years ago. I will be doing a lot of demonstrations, including a basic demo as well as some more advanced features.

I will dive into the details of Vertex. I will talk about how we're using Vertex to build microservices and whether Vertex is a good match for building microservices. Of course, I’ll share how we're using Vertex and our experience over the last few years. So, how about Malmberg? Malmberg is an educational publisher, which means that Malmberg produces books for schools. In addition to books, Malmberg also creates web applications, which are e-learning systems used in primary education, secondary education, and professional education.

So, these are basically digital books used in classrooms and on iPads, where students can complete exercises and read the lesson material. Teachers can view the progress of students and plan assessments and such. Essentially, they are building digital classrooms. We're using some impressive resources to accomplish that. Everything is running on the Amazon cloud somewhere in Ireland. We're utilizing Java 8, Vert.x, Angular, and MongoDB.

So, the basics of Vertex. It's a toolkit for building reactive applications on the JVM. It's very general-purpose and opinionated, so you could see it as a Swiss Army knife for building modern web apps. It's event-driven and non-blocking, which I'll be talking a bit more about in a moment. It's polyglot, so you can use it to build applications with a variety of programming languages.

It's very lightweight, it's very fast, and it's by far the most fun to work with. I enjoy creating applications with Vertex as a developer. So, why did we choose Vertex? About three years ago, there was a movement at Malmberg where we shifted from using externally built applications to developing tools internally with on-site teams. We were looking for direction regarding what to use.

Should it be Scala or Java? Which web framework should we use? These projects typically start as a pilot. Monberg launches a new product, and we begin with a pilot that runs for half a year or so, involving around 50 users and a few schools. When the pilot succeeds, we apply to a broader audience and aim for about a thousand or a few thousand concurrent users. Therefore, scalability is very important for us.

And at that time, we looked for modern guidelines for building web applications and found that reactive characteristics described pretty well what we were looking for. More about reactive later. Open source is a significant part of our development. Most of the tools we're using are open source, including Jenkins, Nexus, Sonar, and various open source Java frameworks. We only use a few commercial tools for aspects that aren't readily available in open source, mainly in the security domain. Additionally, Vert.x has a powerful module system, which allows us to build reusable modules, as most educational applications share similar characteristics.

You typically want something with user profile management, and you want to manage sessions. You might also want to display some educational content to the user. Therefore, we aimed to build reusable modules. Vertex has a very powerful module system that allows you to reuse Vertex modules across different projects. So, let's discuss the reactive aspect.

Vertex is reactive. Reactive applications were defined, well, let's say a few years ago, and they were described in a Reactive Manifesto. Like every good new concept, a manifesto is created when it is outlined. Reactive applications are responsive. Responsive means they respond to the user in a timely manner, which is different from responsive web design, where the page scales according to the device being used.

No, it means they respond to the user. Responsive applications are resilient, which means they remain responsive to the user in the event of a failure. They are elastic, which was previously referred to as scalable in the Reactive Manifesto. Elasticity means they stay responsive under varying workloads by scaling. Finally, they are message-driven, which means reactive applications use asynchronous message passing to establish boundaries between components in the system. So that's reactive.

Let's start by diving into the first demo. I'll be showing you a few basic features of Vert.x. Let me begin by creating a very simple, minimal Vert.x application. I will start by creating a new Java class. Let's call it "MyFirstVerticle."

So "Vertical" is the unit of work in Vertex, which is somewhat similar to a main method or a main class in Java. I’m going to extend from the abstract class "Vertical." Is this readable in the back? Yeah? All right. It has a start method that is called when the Vertical is started.

Let's override that from the base class. Every vertical has access to the vertex instance variable, which you can use, for example, to create a web server that has a request handler for handling HTTP requests. We can include a lambda function there. When I receive a request, I'll say, "request, get the response," and end it by saying, "Hello, world from Java." All that's left now is to make it listen on a specific HTTP port.

So there we go. Now to fire this up, I'm just going to start Vertex from the command line. I'm going to run it. Note that I'm just running the Java source, so I don't need to compile it first. In this case, you can just run the Java source. I'll be showing that later, too.

Of course, you can run classes, too. In this case, I'm just running a source. Let's see what it does. Here it is: Hello, world from Java. The cool thing about Vert.x is that it's polyglot.

You can run stuff in other languages, too. I have some examples of this. The same thing in Groovy looks pretty much the same. I create an HTTP server, define a request handler, and say "Hello, World" from Groovy.

So let's run that. You can probably expect what we'll see here. There we are. Groovy says hi. And then for JavaScript, we can do the same. I have a JavaScript vertical here, which is fairly similar to the other APIs.

Create an HTTP server that takes a function as an argument. It writes to other APIs. Define a request handler for the HTTP server that takes a function as an argument and writes to the response, "Hello, world from JavaScript." So let's run that too. It takes a bit longer to start this up because it will internally run, I think, Nashorn to execute the JavaScript.

And here we are. These are very basic verticals in three different programming languages. You might be wondering if you need to run source files using the Vert.x command line every time you want to create a Vert.x application.

The answer is, of course, no. You can also run Vertex embedded. When I say "embedded," I don't mean like on Arduino or similar devices. Actually, you can run Vertex on LEGO. There's a specific distribution of Java for the LEGO Mindstorms kit, and you can run Vertex on there.

I did it; I tried it. I was surprised to see that it works. You can run Vertex embedded, which means that in any Java application, Scala application, or whatever, you can get an embedded instance of Vertex and use it there. You could use Vertex in your Java EE application, in your Spring application, or whatever you like. In this case, I just have a basic main method where I'm logging the start of Vertex, then getting the Vertex instance, and basically doing the same as I did before: creating an HTTP server, assigning a request handler, and sending a response whenever a request comes in.

So let's run this. We are there. Whenever a request comes in, it now says, "Hello, World from Java with embedded Vertex."

In this case, this is just a plain Java SE class where you're starting a vertex from launching a web server. Of course, you can also put this in a JAR if you like. I've set up the Maven Shade Plugin, which can create an executable JAR that includes all the dependencies you would like to use for your application. Let's build and package it. By the way, let's change something in the source so you know for sure that this is from the JAR, not the same thing I showed you before. Alright, so there we go.

Let's build it again. So, let's go to the target, and there's a jar here. Just run that. Then we'll see "Hello, World from Java" from inside a big fat jar. These are the options you have: you can run Vert.x alone.

You can run them by embedding them in something else. You can run them as a JAR file too, whatever you prefer. So, let's see. Yes, there are a lot of things to discuss. Let's dive a bit more in-depth about Vertex.

The basic goals are verticals, of course. Verticals are the executable units of a vertex application. These verticals run inside a vertex instance. When I type `vertex run vertical.java`, I’ll be starting up a vertex instance that runs the vertical. A vertex instance runs inside a JVM.

So you fire up a JVM, the first Vert.x instance that runs on a vertical. Of course, a JVM runs on a host, so you get this nice shell of hosts running JVMs that execute verticals. The cool thing is that verticals connect to each other through a distributed event bus. So, when a vertex starts up, it joins the event bus, and all verticals communicate with each other over this event bus. I will explain how this works later on. You can either run one JVM with your verticals inside it.

You can run multiple JVMs on the same machine, and then the verticals in those JVMs can communicate with each other through the Vert.x members. So, let's dive into some of the details and provide some background about Vert.x. It is event-driven, meaning everything in Vert.x is an event. HTTP requests are considered events.

Messages between verticals are events. You can even have file system events. You can have timers. Whatever you like to do, it's probably an event.

To handle these events, Vertex uses an event loop. The event loop is a continuously running loop that checks whether there are more events to process. When an event comes in, it fetches the event and delivers it to a handler. A handler is simply a class that manages a specific type of event. For example, I've created a handler—a request handler—in my example that processes HTTP requests.

So the event loop runs continuously, looking for events to process. When an event comes in, it delegates the event to a handler. The interesting thing is that, compared to a more traditional application, where you typically have a thread-per-socket pattern, the event loop operates quite differently. In a thread-per-socket model, for every connection that comes in, you have a dedicated thread that handles the connection on that socket. This thread will block whenever something is happening in the backend and will continue to block, consuming that thread until the request is completed and a reply is sent back. When you have thousands of open connections being served to users, you are likely utilizing thousands of threads, which can be inefficient.

In the case of Vertex, there is an event loop that uses only one thread, running around to see whether events need to be processed. This pattern, known as the reactor pattern, can handle a large number of events with very few threads. The cool thing is that when an event comes in, it gets delivered to a handler, which then performs whatever actions are necessary. If the handler needs to wait, for instance, for a database operation to complete, the event loop can continue to run and find other events to process. This is very similar to Node.js.

Node.js also uses an event loop to process events, but the difference is that Node.js implements a reactor pattern with one event loop running to handle events. This approach doesn't scale very well on machines with multiple cores. When there is only one event loop on one core and the system has three cores, you need to start additional processes to access those cores efficiently. What Vertex does is utilize a multi-reactor pattern. It typically fires up one event loop per core in your machine.

So that when you have four cores, those four event loops together will enable you to maximize CPU utilization on your machine without the need for firing up extra applications. The cool thing about the reactor pattern is that you don't really need to worry about concurrency or synchronization, because Vert.x will ensure that there is only one thing at a time accessing one handler. Typically, one handler is only served by one and the same event loop. This provides you with actor-like concurrency, where you don't need to worry about locking or synchronization or all that complex stuff. You can just focus on what's similar to single-threaded processing.

So there's a distributed event bus, as I mentioned, which can connect verticals within one JVM, processing. This distributed event bus can connect verticals within one JVM, multiple JVMs, or even across multiple homes. It uses Hazelcast to initialize the cluster and send messages between those Vert.x instances. There are all kinds of cool features, such as built-in management and monitoring. You can use JMX or Dropwizard metrics. Additionally, there’s a whole ecosystem of Vert.x modules that are free to use, built by the community.

But there are also many resources provided by the Vert.x team itself. There's Vert.x Web, which offers features for handling web requests and routing. Additionally, there are modules for Vert.x that facilitate communication with various types of databases. There is a wealth of useful tools available for you to utilize.

Sure! Here’s the text reformatted with correct capitalization and spelling: So, about the event bus. It's just a message bus, and you can use it with either a request-response model or a publish-subscribe model. You can either send a message to a single address and take the response, or publish a message to a specific feed, and all the subscribers will receive that message. All these vertical instances have access to the event bus, and verticals interact with each other by using messages. These messages are received by handlers.

Take the HTTP example. There is an event coming in which the HTTP request is handled by the request handler. If that request handler were to call some other service, it would send a message on the event bus. I'll be downloading that soon. So, when you have an event loop that's constantly running, you only have like four on four cores, and you have 10,000 connections you need to serve.

What do you think happens when you block the event loop? So, you have a request handler, and that request handler thinks it's a good idea to read a file of about 10 gigabytes from disk. What will happen? Any ideas? What happens if you block the event loop?

Yes, basically, if you block the event loop, the world will stop. The event loop is responsible for running and serving all the incoming events and their handlers. When you block it, it can no longer perform these tasks. So, when one handler blocks the event loop, it won't be able to serve any other handlers or deliver any additional messages until that blocking handler completes its execution. Therefore, never, ever, ever block the event loop.

I have done it a few times myself. These problems tend to be fairly difficult to debug. However, in Vertex 3, which was released about six months ago, you get notified when you block. The system will start generating error messages, indicating that you've blocked the event loop for 2-3 seconds, so you receive a notification. You might wonder, what should you do when you want to perform tasks that block?

There's a concept in there called a worker. A worker is a vertical that functions as a traditional thread-based system, equipped with a thread pool for handling blocking tasks. You have your event loop handler, which sends a message to the worker, allowing the event loop handler to stop doing work while it waits. The worker can then perform its synchronous blocking operations. Once the worker is finished, it sends a reply over the event bus, enabling the non-blocking handler to continue its work and be served by the event loop. So, if you put all of this together, this is actually a slide from the Vert.x team.

I asked them if I could use this slide, and they said, of course, it's open source. So, in the top left, you can see that's Polyglot, which allows you to build applications using either JavaScript, Java, Scala, Groovy, Ruby, and I think even PHP, along with some other languages. The unit of execution is a vertical, and events are delivered to verticals and distributed over the event bus. One vertical can communicate with another over the event bus, and these events are handled by handlers, using one or more event loops. The whole system is distributed by nature. You can either run it on a single machine or on multiple machines. Any questions so far?

Yes, sorry. You talked about the actual programming on the JVM. What are the languages you’re referring to? Are there non-JVM languages? Yes, so the question is, I talked about the JVM.

A few of the languages mentioned aren't JVM languages. I'm not sure about PAP, but I'm pretty sure it must run, too. However, all the other languages can run on the JVM.

Groovy and Scala, of course, JavaScript runs using Nashorn, and Ruby runs using JRuby. Now I'm doubting PHP, but maybe there will be something like JPHP or something. I believe it is on the Vert.x side, but if I’m mistaken, don’t hold it against me. So these languages are all able to run on the JVM. That's why you can easily run code in those different languages.

And actually, the APIs for these different languages are all being generated. Before, the Vertex team had to type APIs in those five or six languages. Now they're just generating them. So the maintenance is a lot easier for them. Alright, enough talking.

Let's show some more code. I'll start with a basic example of how the FMBus works. So, let's see. I have a starter vertical here, which has a main method that will fire up two other verticals. I'm calling the Vertex API to deploy new verticals here.

I'm deploying the Echo Service vertical and a Web vertical. These are just names that I made up; you can name them however you like. The Echo Service will not do too many interesting things. It will simply log that it has started.

Then it will register itself at the vertex event as a consumer, meaning a receiver of events. It registers itself at this address, which is just a string. Event bus addresses are simply plain strings. It indicates that whatever events are sent to the echo service address, it will consume them. Then, you pass in a lambda here.

Whenever a message comes in, do this: get the message body. Messages sent over the vertex event bus are typically either plain strings or, for more complex data, JSON objects—a representation of a JSON string. Take the body of this message, log whatever you received, modify the body to include something like "the echo service was here," and then reply with the changed message body to whoever called the service. Additionally, there’s the web vertical that will start an HTTP server just like we did before.

Whenever a request comes in, it will create a message, which is a JSON object containing two keys. It will include some text as well as the query string from the HTTP request. This is included to demonstrate that something is actually happening with the input I am providing. Then, it will send a message using the Vertis API to get the event bus and send a message to the echo service. It will include the message I just created. Whenever a reply comes in, it will take the reply, extract the body from the response, and return that body in the HTTP response.

So, talking in terms of event loop events, whenever there's an HTTP request coming in, the event loop will deliver a message here. Then, this vertical will perform a few steps and send a message to the echo service. After that, this vertical stops doing anything. The event loop won't deliver anything to it until the echo service replies. Once it receives a reply, there's a new event that this vertical will process. Subsequently, we will send it back to the ACP response, and then it’s done. There will actually be multiple passes over this vertical to complete the process.

Let's see what happens if we fire it up. It will say that the address is already in use because there's something else running on port 8080, of course. Let's try that again. It's running now.

Let me clear out the logs so we can see the logging later on. We'll now set the query string to nil and pass through the Echo service with the text "Hello, World." Let's see what happened. The web service sent a message: "Hello, World," with the query string set to nil. Then, the Echo service received the message and sent a reply: "Pass through Echo service." Finally, the web service received the reply.

It sends a reply. We put it into their pass-through echo service. Then, the web vertical has received a reply, and we send it back in the HTTP response. To prove that we are actually processing the input, let's see "key is value," which will also be included. This is taken from the request, placed in the message, sent to the echo service, and then sent back in the HTTP response.

All right. So it was this demo. Let's see what's next on the schedule. Let's dive into a bit more advanced examples. This is still very simple and nice to show, but not really useful yet. So let's dive into a more complex example where you can see one of the drawbacks of using an asynchronous architecture.

Here I have a vertical starter that will deploy three services and then a web vertical. These three services are verticals in themselves. Let's take a look at what's in this service. It will register itself at the event bus address of Service 1. Whenever it receives a reply, it will respond with a reply from Service 1.

Nothing too difficult yet. Let's take a look at Service 2. It will do pretty much the same. It will reply with a response from Service 2 whenever it receives an event. Now, let's look at Service 3.

You might be able to guess what this is going to do. But no, gotcha; there's something else. Whenever it receives the message, it will take the body of the message and then append it, passing it through the service tree to the body. This actually changes the message that it will receive and send back. So what's the use case? I hope I can clarify that for you. In this example, the use case can be compared to a real-world scenario where you have one vertical running, which is your HTTP server, as depicted here. Whenever a request comes in, you have a business case that requires you to call Service 1 and then call Service 2, waiting until both calls have completed.

Get the results together, and then send a call to Service 3. That's a fairly typical scenario when you're calling multiple services. So, how do you do this in classic vertex style? Every reply from a service is a callback.

You could either tackle the challenging task of sending requests out in parallel, waiting for both to complete, and then combining the results, or you could opt for the easier approach of calling Service One. In this case, whenever you receive a reply from Service One, take that reply and then send the message to Service Two. Once you get the reply from Service Two, combine the results by concatenating the two strings and send that combined result to Service Three. After receiving a reply from Service Three, return it in the HTTP response.

So, let's see if this works. It looks like it works. We will say "response from Service 3," "reply from Service 1," "reply from Service 2," and "pass through Service 3." It has now passed through three services and sent a reply back to the HTTP response. Who among you enjoys looking at this beautiful piece of code? Please raise your hands.

Only a few. I do not really enjoy it myself. This is where you can see a basic example of something that's often referred to as "callback hell." Because of the asynchronous nature, you make a call, then you get a callback, and then you get another callback. This is just a fairly simple example, pushing strings around to a few services. When you need to call about eight services, combine the first two, then call service three, and in parallel do service four, it quickly becomes very messy.

So, do we just need to live with this? Well, that's one option. I like to explore alternatives, and one of those alternatives is... So, do we just need to live with this? Well, that's one option. I like to explore alternatives.

And one of those alternatives is RxJava. RxJava is the Java implementation of Reactive Extensions, which was, I think, originally created by Microsoft. Who has ever heard of RxJava here? Okay, so that's about half of you. So, RxJava works with Observables.

Observables are kind of like futures, with the exception that futures operate on single objects. You create a future and then you receive one single object back. Observables can also work with streams of data. In this case, I'm just using them with single objects. However, let's see how this can be replaced with some RxJava code.

I still have the same starter. It will deploy Service 1, Service 2, and Service 3, and then we'll deploy what I call the RxJava web vertical. This will then send a request to Service 1 and send a request to Service 2. These are fairly similar calls to those in the callback scenario, with the exception that I'm now using `sendObservable` instead of `send`. The Vertex team has created an Rx-enabled version of the entire Vertex API, which allows communication through Rx observables. So in this case, I'm just saying to fire calls to those two services.

Here's the reformatted text with correct capitalization and spelling: Take the observable that will hold the reply from those services whenever it completes. Combine those two observables using the `zip` operator, which means they are combined to continue whenever both are completed. You can also chain actions on those two observables. In this case, once the observables complete, I'll take the body from response one and the body from response two, which is similar to concatenating strings in the callback example. Then, subscribe to it. Whenever the observable completes, take the combined result and send it to service three, and then reply to the response with the combined result. This should function similarly to the callback example. Let's see if it works. Yes, it replies the same way: it says "Service One," "Service Two," and "Service Three." I personally think that this is much more readable than the callback spaghetti. If you prefer creating one-liners, you could also condense this into a single line of code. In this case, you would simply send an observable and then zip it with the call to service two. Whenever that completes, send it to service three and do something with the response.

If it has started, it will do pretty much the same. But now we'll refer to RCA for a one-liner. So, is this better than the other scenario? I think that's debatable. I prefer the simplicity of just creating two observables, as you can see I'm sending out two service calls and then combining the results. Personally, I don't believe that this is more readable than the scenario above, but that's something you need to decide for yourself.

So I think there's one demo left. Yes, there is a cool thing about Vert.x, and especially about the Vert.x event bus. You can also extend the Vert.x event bus all the way to the browser. This means that in your JavaScript running in the browser, you have access to the Vert.x event bus. That is actually a pretty cool feature if you want to create real-time applications because you would just be able to send a message to a feed or an address from some service in the back end, and then in the browser, you would receive that message and can do whatever you like with it. So how does this work? I have a basic example that again has a starter class, and the starter class will start Vert.x in clustered mode. I'll explain why this is necessary later. I want to deploy it; we will deploy three verticles. So we will deploy a SockJS event bus bridge.

It will deploy a simple vertical in Java and a simple vertical in JavaScript. So, what does this simple vertical in Java do? It starts a timer. It uses `vertex.setPeriodic()` to execute every thousand milliseconds, which is roughly every second. It will publish a message to the events feed.

So, everyone listening to the events feed will receive this message. What this does is send a message to the events feed every second, indicating that it is a server event from Java. Now, let's take a look at the other one we're deploying, which is called simple vertical.js. This performs basically the same function: it sends a message to the events feed every second, stating that it is a server event from JavaScript. So, how does this work in the browser? We use the Vert.x eventBus.js, which is the Vert.x implementation of the event bus provided by the Vert.x team, along with a basic index.

EventBus.js is the Vertex implementation of the EventBus provided by the Vertex team. It also includes a basic index.html file that will fetch SockJS from a CDN located somewhere on the internet. This will include the Vertex EventBus. In this small piece of script, it will connect to the Vertex EventBus. We will create a new EventBus and access it at localhost:8080. Whenever the EventBus opens, it will perform the specified actions.

Register a handler that will respond to events sent to the events feed. Whenever you receive an event, find the element in this HTML document with the ID "events," which would be this element here. Then, take the inner text of this element, apply a new line, and include the date along with the body of whatever you received. This will simply add to the HTML page whatever event is received. There is just one more thing left to show.

How does the back end work in this case? Here's the SockJS event bus bridge. There's one thing left to show. The back end operates in a straightforward manner, if I may say so. We will be setting up a Vert.x router, which is part of the Vert.x web project.

You can use it to route API endpoints. In this case, it will route everything being sent to the slash event bus to a SockJS handler. So, we'll be creating a SockJS handler, passing the vertex instance into it, and then setting up a SockJS bridge defined by a few options, which are specified here. This acts as a kind of security or access control on the event bus. You can envision a scenario where there is an event bus connecting all your services together—services connected to your database, your session store, and your user management systems. You might not want to expose all that sensitive information to everyone who has a browser.

I discourage you from doing that. You set up some bridge options, and this is similar to whitelisting. In this case, I'm saying that all outbound events to the events feed are permitted. This means that all backend services can publish events to the events feed, which allows outbound communication from the backend to the browser.

Then I'll explain how to set up a handler that will serve static resources from the web folder, which includes the index.html file you just saw. After that, we'll start an HTTP server. Whenever a request comes in, it will be redirected to the router, and we'll listen on port 8080. I'm curious to see what happens when we start this up. It may take a bit longer to initialize because I'm starting in clustered mode. We will also perform some cluster detection. If any of you are running a Vert.x instance on the same network as I am, you might be able to join my cluster.

So it has started. Let's see what happens when I go to low-close 8080. We're seeing events being sent here from Java and from JavaScript. However, I could have programmed this as a simple piece of JavaScript that would echo this. Let's prove that this is actually doing something with WebSockets. I'm using Chrome because it has an easy-to-use WebSocket debugging tool.

Let's reconnect to set up the WebSocket. Then you will see the WebSocket being established here. Over here, we can see the events flying over the WebSocket. Essentially, it's just sending JSON messages over the event bus. Sometimes there's a ping in there, which I think is sent either by `soc.js` or Vertex to ensure that the connection stays alive from the Java vertical and JavaScript vertical over the VAMs to the browser.

Here's a reformatted version with correct capitalization and spelling: "With everything together, just like 20 lines of code, I think that's pretty useful if you want to create fast-updating or very dynamic apps. But that's not all. Let's simulate that this simple JavaScript application is doing such heavy lifting that I need to run it on a different machine. I need another machine to run it because it's using all my resources on my primary machine. So, let's stop it here."

Start it again so it's running. If I now go to the site, I will probably only see events from Java. Now, let's go to the example. There's the JavaScript vertical here. What would happen if I were to fire this up?

Let's see what happens. Actually, nothing happens. No events are being sent from the JavaScript vertical. How? Why?

Well, because I need to tell it to run in clustered mode. I set up Vertex by running it on the backend to operate in clustered mode. This means that it will connect to the network to detect other Vertex nodes that we want to communicate with. I didn't inform the JavaScript vertical about this, so let's go ahead and do that.

You can't see it because it's blocking the view. There we go. So, you can see this example as a back end running on one machine, with the JavaScript vertical running on the same machine, talking to each other and publishing to the event feed, which is running in my browser. It's directly processing the events being sent by the back end, all in just about 20 lines of code or so. Who thinks that's useful for building real-time applications? Okay.

Luckily, almost everyone. So let's see if that was all I wanted to demo. Yes. So let's continue. We've got about 10 minutes left, so that will be all right.

I promised to talk about building microservices with Vertex. I haven't said a word about microservices yet, so it's time I start doing that. The Anatomy of a Microservice: What does a typical microservice look like? It's typically small in size, has a single responsibility, and does one thing well.

It runs in its own process. It has its own data store and accesses a database or whatever it needs by itself. Microservices are distributed by default. If they weren't distributed, there wouldn't be much to service by them. You can independently develop microservices, deploy them independently, and scale them independently. They can potentially be polyglot.

When you're running multiple processes, you can run them in different languages if you like. Microservices typically feature lightweight communication to interact with each other. So, what happens if we plot a vertex module on this? Take a look at the very dynamic activity happening at the top there. The slide basically stays the same. Let's see if we can plot the vertex characteristics against microservice characteristics.

Is it small in size? Does it have a single responsibility? Yes, it is small. The single responsibility depends on how you develop it, but yes, it can definitely fit.

Does it run in its own process? Yes, you have a choice. You can either put several verticals inside one JVM or put every vertical in its own JVM, but it definitely can run in its own process. Does it have its own data store? You can use whatever you like for your verticals, whether that's Microsoft SQL Server, Oracle, MongoDB, or anything else you prefer.

Is it distributed by default? Yes, definitely. DFM is distributed by default. Can you independently develop, deploy, upgrade, and scale them? Yes.

I'll be sharing how we handle deployments in our team. But you can definitely do that. Are there potentially polyglots? Yes. JRuby, Nashorn, Scala, Groovy, whatever you like.

Do they feature lightweight communication? Yes, I would say they do because you can just throw strings over the members or JSON objects, which are still fairly lightweight. So, how are we really using Vertex? A bit more background on the situation at Momburg: there are three types of teams within the organizational structure.

There is one core platform team, so the IT organization consists of around 50 to 60 people. The core platform team provides the infrastructure that our applications run on. They ensure that there are generic provisioning scripts that can spin up a node with Java and Vert.x, as well as MongoDB clusters and similar components. They handle the generic provisioning tasks, while all the product teams manage their environments independently.

So, their DevOps teams are responsible for their applications from design to production. They are using the generic provisioning scripts provided by the platform team. Then there's a core modules team, which consists of three developers who are creating reusable version modules. These modules are designed for profile management, session management, fetching content from the database, and handling student answers. They are also creating front-end components used by students to answer questions. These developers provide reusable modules that are utilized by the product teams.

The product teams are somewhat like eight or ten DevOps teams that use the generic provisioning scripts from the infrastructure team and utilize the generic modules. They combine these elements with a few project-specific vertex modules and include a project-specific front end, along with logic, business components, and content. This integrated approach results in one educational application. These modules are utilized across all teams. We deploy everything on AWS, using Nginx as a web server and proxy, and MongoDB in the backend. Typically, one product consists of one or two project-specific services and around eight or ten generic services. However, these are not designed as microservices; rather, they are reusable services that are hosted centrally. We deviate from the microservices approach in that there is no shared infrastructure between the products. We have shared infrastructure running Jenkins and other tools, but each project has its own independent environment, pulling in the generic modules through Maven. We also have NEX running.

Whenever the Core Modules team releases a new version, they upload it to Nexus. Then, all the teams retrieve those artifacts and deploy them to their servers for use. There is no direct operational relationship between the teams, and different versions of those artifacts may be in use depending on when a team upgrades to the new version, which typically happens at the start of every new sprint. This is how deployments are managed.

When we started with Vertex, there wasn't really good deployment tooling specifically for Vertex. So, we decided to try creating our own solution, which became fairly complete for our use case. These are deployed from Jenkins. We have a plugin in Jenkins, or a Maven plugin, that Vertex's deployment will use to send a call to an agent running on all the application nodes with a deployment descriptor, such as installing these versions of these modules.

The deployment agent will then fetch those artifacts from Maven. It will unzip the web components, the configuration files, and the Vertex modules, and then install them by calling the Vertex Container API, just as I showed you before. "Container" here does not refer to token containers, but to the Vertex container. There’s some logic in place that will compare the running services, their versions, and their names with whatever is being deployed. Typically, teams create new versions of their product-specific artifacts with every commit and only upgrade the core modules once every sprint. Therefore, during a deployment, it is common for eight of the running services to remain unchanged.

So then the deployment will decide I only need to upgrade those two, which will really speed up deployments a lot. Communicating with the Amazon API to deploy node by node and putting stuff in standby so we can do Siemens deployments. I think it's pretty cool. You can look it up on GitHub. It's all open there, along with our experiences.

We love Vert.x. It's also very suitable for test-driven development. We've set up lots of unit tests and integration tests that will spin up Vert.x and an embedded MongoDB. We put test data in there and just fire calls to API endpoints. Since you can run it embedded so easily, it's also very easy to incorporate it into a JUnit test, for example. The Vert.x team has been really helpful to us.

They've been reaching out and asking us about our use cases and things we'd like to change. They're very quick to accept pull requests and similar contributions, so overall, it's been a good experience. However, of course, there are no good experiences without challenges. At the beginning, the callback hell was truly a nightmare—nested callbacks in class after class after class.

The example I showed you was actually all right because of the use of lambdas in Java 8. Before, we had to write inner classes repeatedly, which was really terrible. In Java 8, lambdas helped a lot in terms of readability. And Reactive Streams in Java fixed the remaining issues for us. So right now, we are fairly happy having a synchronous message-driven system without many of the drawbacks, because we can write code that feels almost synchronous using the ArcSava API. Blocking the event loop has cost us in production a few times; we learned the hard way.

Scaling JVM overhead: When you're running a monolith, with one application server and one JVM started, you only incur the JVM overhead once. However, when you're running 10 JVMs on the machine, the JVM overhead multiplies by ten. While I'm not sure of the exact amount, JVM overhead can be estimated to be around tens of megabytes—let's say approximately 30 megabytes. Therefore, when you're running 10 services, you're already consuming 300 megabytes just from JVM overhead. We used to run them on very small instances at AWS, around 2 gigabytes of RAM, I believe.

We had to upgrade a few services because of the JVM overhead. We're now looking to consolidate our services into fewer JVMs. Typically, in some verticals, we run one JVM per vertical, but it is also perfectly fine to run multiple verticals in one JVM. The drawback of this approach is that you cannot scale those JVMs independently. We are setting JVM options and memory settings per JVM, which can vary, especially with event loops and very long, complicated stack traces. Static code analysis tools often struggle to follow event bus calls, so when you remove security tools that are effective at tracing code paths from request to response and determining whether specific data is tainted by user input, they can fail. These tools tend to stop whenever you send a message to the event bus because they do not know where that message is going or which vertical will receive it; this information is only available at runtime.

The upgrade from Vertex 2 to Vertex 3 was, for some projects, quite challenging because it involved a lot of work. While it brings many features that can be very helpful, the transition was still quite demanding. We're glad to have that behind us. If you are starting now, I would advise you to begin with Vertex 3 rather than going back to Vertex 2. We're almost there!

Time-wise, we're also almost there. So to summarize, Vertex is a toolkit for building reactive applications on the JVM. It's polyglot, event-driven, and very suitable for building microservices. It's also very fun to use. These are the resources; some of them I showed you. The examples I demonstrated are from my GitHub.

The deployment tooling is on GitHub. The vertex.io site is quite good, and there are some examples available as well as very good documentation. I will tweet a link to the slide deck later.

So, just follow my Twitter account, and you will be set up with the slides in half an hour or so from now. Let's skip the queue until we're finished; then you can just find me here and ask some questions because my time is already up, and I don't want to hold up the next speaker. However, in good style, there is one more thing I'd like to show you, which is my next project with Vertex. I've stopped at Maanburg, and I am where we will start working for another organization in the Netherlands. Just yesterday at JPoint, we started with a challenge, and this challenge involves this small car. We had the challenge of building an autonomous driving car, for which we've purchased four of these RC car kits without the RC parts.

There was an engine in there, along with servos to control it. Just yesterday, we started building it. We set it up, connected everything, put a Raspberry Pi on there, and connected the servo and the motor to the GPIO pins. We were working on this with three Java developers and two front-end developers. We were deciding whether to run it on the Pi or possibly on a brain or machine that is operating alongside it.

This is a very good use case for Vertex since JavaScript developers can write JavaScript modules, and we can write Java modules. We can decide on running services on the Pi or on the site. This is the result after a day of hacking. It's not too fancy yet, but it's still fun to watch. The Pi is controlling it now. I'm SSHing in from my laptop and sending it to my own.

We still have some trouble controlling it, but we hope that it will be drivable and even autonomously drivable in the future. We’re looking to achieve that with Vertex. Typically, you’ll see it in more enterprise-like applications. If you have a thumbs up, please rate my sessions in the DevOps app; it helps in building even better conferences. If you have any feedback, want to learn more, or would like to talk to me, please find me after the talk.

I'll be around here somewhere. You can reach me on Twitter. I'll be here for the next three days or so. Thank you for your time, and see you around.