问题
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);
}
}
回答1:
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.
回答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:
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.
回答3:
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);
}
}
}
来源:https://stackoverflow.com/questions/49775238/vertx-web-server-uses-only-one-event-loop-thread-while-16-are-available