6

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);
}
}
katrin
  • 1,146
  • 1
  • 13
  • 24
  • A more up to date answer is available [here]( https://stackoverflow.com/questions/62558613/in-vert-x-does-it-make-sense-to-create-multiple-httpserver-instances-in-a-runti) – MuJosh Sep 14 '22 at 07:15

3 Answers3

7

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.

tsegismont
  • 8,591
  • 1
  • 17
  • 27
  • Thank you for response! I want my server to use all available cores, i.e. all event loops threads. It seems so called "multi-reactor pattern" as described in Vertx manual: "Instead of a single event loop, each Vertx instance maintains several event loops." I also tried deploying of verticles but it doesn't work as expected too - not all threads involved due to the fact the corresponding chooser of event-loop relies on internal index that is not incremented as expected, as a result I got only a half of expected threads. – katrin Apr 11 '18 at 13:22
  • Can you update your question with snippets for 1/ the code deploy the verticle with multiple instances 2/ the verticle itself. I'll take a look – tsegismont Apr 11 '18 at 15:15
  • Sure. I updated the question. But actually it's another story for Verticle model. My original question was - why does web server use only one event-loop thread but not all available? – katrin Apr 11 '18 at 15:26
  • 1
    No it's not another story. An `HttpServer` events are always handled by a single event loop. But when you deploy multiple verticle instances (hence create multiple `HttpServer`), Vert.x load-balances requests among the different servers. – tsegismont Apr 11 '18 at 16:22
  • In case of Verticles I have the following situation: - I create Vertx instance with event loop pool size = 16 - I deploy 16 Verticles but they affect only half of available threads - the reason of it is that balancing relies on internal index and this index incremented twice for each iteration. As a result - just 8 affected thread. In case of simple web server without Verticles I want just scale it on event loop threads. I can do it just creating servers N times in loop. Thats seems strange. – katrin Apr 11 '18 at 16:24
  • The question is: Why having 16 netty event loops under the hood we just use one by default? Why dont we scale netty client channels to all 16 threads by default? Why do I need invent workarounds to reach this simple behaviour? – katrin Apr 11 '18 at 16:28
  • I got the part of answer: one Verticle can be executed only in one event loop - so we can create only one-threaded server inside Verticle. (Issue with half-loaded balancing still exists). But what if I don't use Verticles at all? What is the best practice in this case to create scaled web-server? Thank you! – katrin Apr 11 '18 at 16:46
  • If you don't use Verticle at all, it depends. When `vertx.createHttpServer` is invoked, Vert.x picks the execution context by calling `vertx.getOrCreateContext()`. In a verticle this return the event-loop execution context. Out of a Vert.x thread this will pick a new context every time. But the recommended way is really to create a verticle. – tsegismont Apr 12 '18 at 08:08
  • Thank you, tsegismont! Your answers were very helpful! Now my application looks pretty good :) – katrin Apr 12 '18 at 09:20
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/168834/discussion-between-katrin-and-tsegismont). – katrin Apr 12 '18 at 12:20
2

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:

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.

Idriss Neumann
  • 3,760
  • 2
  • 23
  • 32
  • I just deploy several "normal" (not worker) verticles and they use several event-loops. But not all. But I dont understand why "multi-reactive pattern" is not applicable for simple web-server. Why not using of all netty event loops by default? – katrin Apr 11 '18 at 13:52
0

As I understood after some tries and discussions (thanks for tsegismont) the only right way to work with all threads in pool is:

DeploymentOptions deploymentOptions = new DeploymentOptions()
        .setInstances(vertxOptions.getEventLoopPoolSize());

vertx.deployVerticle(() -> new MyServerVerticle(), deploymentOptions);

The implementation below has unexpected behaviour:

for (int i=0;i<vertxOptions.getEventLoopPoolSize();++i) {
   vertx.deployVerticle(new MyServerVerticle());
}

class MyServerVerticle implements Verticle {
 @Override
public void init(Vertx vertx, Context context) {
    this.vertx=vertx;
}

 @Override
 public void start(Future<Void> startFuture) throws Exception {
vertx.createHttpServer()
            .requestHandler(anyRouter::accept)
            .listen(8080);
}
}

And there is no proper way to create web-server not using Verticle model with multiple event-loops. In this case we can only create servers in loop, but I'm not sure that it's always correct:

class MyServerNotVerticle {
  public void start() {
   for (int i=0;i<vertxOptions.getEventLoopPoolSize();++i) {
       vertx.createHttpServer()
                .requestHandler(anyRouter::accept)
                .listen(8080);
    }
  }
}
katrin
  • 1,146
  • 1
  • 13
  • 24
  • In your 3rd example (calling `createHttpServer()` directly), be careful *not* to call from an existing vertx thread. – The Scrum Meister Apr 13 '18 at 21:32
  • The Scrum Meister, could you please explain your comment? I don't see any reasons to prevent several servers launched in one thread. – katrin Apr 16 '18 at 12:26
  • You can launch them all on one thread, but if you launch them (by calling `listen()`) on a vertx thread they will all share the same `Context` and thus use the same cpu thread. (look at the source for `httpServer.listen()` and `getOrCreateContext()`). Your 3rd example will work as long as it is called from a non vertx thread (such as `main()`) – The Scrum Meister Apr 16 '18 at 18:50