Search code examples
javavert.xevent-loopvertx-verticle

How to vertically scale Vert.x without Verticals?


According the the Vert.x docs - deploying using Verticles is optional. If this is the case - how can I deploy say an HTTP server onto multiple event loops? Here's what I tried - also read the api docs and couldn't find anything:

Vertx vertx = Vertx.vertx(new VertxOptions().setEventLoopPoolSize(10));

HttpServerOptions options = new HttpServerOptions().setLogActivity(true);

for (int i = 0; i < 10; i++) {
  vertx.createHttpServer(options).requestHandler(request -> {
    request.response().end("Hello world");
  }).listen(8081);
}

This appears to create 10 HTTP servers on the first event loop but I'm hoping for 1 server per event loop.

Here's what I see in my logs - all eventloop-thread-0:

08:42:46.667 [vert.x-eventloop-thread-0] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0x0c651def, L:/0:0:0:0:0:0:0:1:8081 - R:/0:0:0:0:0:0:0:1:50978] READ: 78B

08:42:46.805 [vert.x-eventloop-thread-0] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0xe050d078, L:/0:0:0:0:0:0:0:1:8081 - R:/0:0:0:0:0:0:0:1:51000] READ: 78B

08:42:47.400 [vert.x-eventloop-thread-0] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0x22b626b8, L:/0:0:0:0:0:0:0:1:8081 - R:/0:0:0:0:0:0:0:1:51002] READ: 78B


Solution

  • "Optional" doesn't mean "you can, getting the same benefits". "Optional" simply means "you can".

    Vert.x has the notion of thread affinity. HTTP Server created from the same thread will always be assigned to the same event loop. Otherwise you'll get nasty thread-safety problems.

    You can compare the example code from above with the following code:

            Vertx vertx = Vertx.vertx();
    
            HttpServerOptions options = new HttpServerOptions().setLogActivity(true);
    
            // Spawn multiple threads, so EventLoops won't be bound to main
            ExecutorService tp = Executors.newWorkStealingPool(10);
            CountDownLatch l = new CountDownLatch(1);
            for (int i = 0; i < 10; i++) {
                tp.execute(() -> {
                    vertx.createHttpServer(options).requestHandler(request -> {
                        System.out.println(Thread.currentThread().getName());
                        // Slow the response somewhat
                        vertx.setTimer(1000, (h) -> {
                            request.response().end("Hello world");
                        });
                    }).listen(8081);
                });
            }
            // Just wait here
            l.await();
    

    Output is something like:

    vert.x-eventloop-thread-0
    vert.x-eventloop-thread-1
    vert.x-eventloop-thread-2
    vert.x-eventloop-thread-0
    

    That's because each event loop thread now is bound to a separate executing thread.