Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vertx web-server uses only one event-loop thread while 16 are available

I use Vert.x v3.5.1. There is the simplest sample of code:

vertx.createHttpServer()
                    .requestHandler(anyRouter::accept)
                    .listen(8080);

In my case the event loop group size is 16 so I expect that my requests will affect 16 threads. Server is started succesfully but it works only in one thread. (I sent request using different tcp-connections so keep-alive is not a reason here.)
Class HttpServerImpl contains httpHandlerMgr and this manager handles a pool of event loops (named availableWorkers). And during debug I saw that this pool contains only one worker.

Using of Verticle model doesn't resolve the issue, still not all of threads are used.

If I create server many times in loop, it helps. As a result I have many affected threads and one shared server. But it looks like workaround.

The question is how to create web server that uses all available event-loop threads?

Implementation with Verticle below

As a result this implementation uses half of available threads (8 threads). But I want it to use 16 :)

public static void main(String[] args) throws Exception {
        int eventLoopSize = 16;
        Vertx vertx = new VertxOptions().setEventLoopPoolSize(eventLoopSize);
       for (int i=0;i<eventLoopSize; i++) {
           vertx.deployVerticle(new MyServer(vertx), deploymentOptions);
       }
    }

public class MyServer implements Verticle {
final Vertx vertx;
public MyServer(Vertx vertx) {
   this.vertx = vertx;
}

@Override
void init(Vertx vertx, Context context) {
vertx.createHttpServer()
                    .requestHandler(anyRouter::accept)
                    .listen(8080);
}
}
like image 363
katrin Avatar asked Apr 11 '18 12:04

katrin


2 Answers

There's a single thread involved, that's precisely the event loop model. I recommend watching Philip Roberts: What the heck is the event loop anyway? | JSConf EU 2014. Examples are for the browser but the concepts are the same for server-side event loop systems like Vert.x or Node.

However, with Vert.x you usually organize your code in verticles (think small services). Each verticle is assigned an event loop but you can deploy multiple instances. This is how you get to use all the cores of your CPUs. If you're a Java programmer and writing a Vert.x application for the first time I recommend reading this guide.

As for scaling your verticle to all the cores, the problem is that when you instantiate the verticle yourself you actually create separate deployments and have no guarantee with respect to using different event loops.

As explained in Specifying number of verticle instances, you must use the verticle name:

When deploying a verticle using a verticle name, you can specify the number of verticle instances that you want to deploy:

DeploymentOptions options = new DeploymentOptions().setInstances(16);
vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options);

This is useful for scaling easily across multiple cores. For example you might have a web-server verticle to deploy and multiple cores on your machine, so you want to deploy multiple instances to utilise all the cores.

like image 110
tsegismont Avatar answered Oct 07 '22 08:10

tsegismont


According to this: https://vertx.io/docs/vertx-core/java/#_reactor_and_multi_reactor

Even though a Vertx instance maintains multiple event loops, any particular handler will never be executed concurrently, and in most cases (with the exception of worker verticles) will always be called using the exact same event loop.

So If you want to use other threads, you could:

  • Use multiple instances of your verticle in seperate pids (using multivalued instance of systemd services for example, or docker containers or whatever that allow you to run multiple java process of a microservice and making the monitoring and the failures recovery easier).

  • Deploy your verticle as a worker verticle multiple times: https://vertx.io/docs/vertx-core/java/#worker_verticles

  • Use the executeBlocking method: https://vertx.io/docs/vertx-core/java/#blocking_code but I'd not recommand you to use that.

If your verticle expose an http restfull API, I'd recommand you to use a classic http reverse proxy and manage multiple instances inside containers or using different hosts if you can't or ports. And delegate the operations to others verticles via the eventbus (or other message queues based system). Here's an example of design.

like image 39
Idriss Neumann Avatar answered Oct 07 '22 09:10

Idriss Neumann