Vertx 网络服务器仅使用一个事件循环线程,而有 16 个可用
Vertx web-server uses only one event-loop thread while 16 are available
我使用 Vert.x v3.5.1。
有最简单的示例代码:
vertx.createHttpServer()
.requestHandler(anyRouter::accept)
.listen(8080);
在我的例子中,事件循环组大小为 16,所以我预计我的请求将影响 16 个线程。服务器已成功启动,但它仅在 一个线程 中工作。 (我使用不同的 tcp 连接发送请求,所以保持活动不是这里的原因。)
Class HttpServerImpl
包含 httpHandlerMgr
并且此管理器处理事件循环池(名为 availableWorkers
)。在调试过程中,我看到这个池只包含 一个 工作人员。
使用 Verticle 模型并不能解决问题,仍然没有使用所有线程。
如果我在循环中多次创建服务器,它会有所帮助。结果,我有许多受影响的线程和一个共享服务器。但它看起来像解决方法。
问题是如何创建使用所有可用事件循环线程的 Web 服务器?
下面用 Verticle 实现
因此,此实现使用了一半的可用线程(8 个线程)。但我希望它使用 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);
}
}
这里涉及到一个线程,这就是事件循环模型。我推荐观看Philip Roberts: What the heck is the event loop anyway? | JSConf EU 2014。示例适用于浏览器,但概念对于 server-side 事件循环系统(如 Vert.x 或 Node.
)是相同的
但是,对于 Vert.x,您通常会在 Verticle 中组织代码(想想小型服务)。每个 Verticle 都分配有一个事件循环,但您可以部署多个实例。这就是您如何使用 CPU 的所有核心。如果您是 Java 程序员并且是第一次编写 Vert.x 应用程序,我建议您阅读这篇 guide。
至于将 Verticle 扩展到所有核心,问题是当您自己实例化 Verticle 时,您实际上创建了单独的部署并且无法保证使用不同的事件循环。
如 Specifying number of verticle instances 中所述,您必须使用 Verticle 名称:
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.
据此: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.
所以如果你想使用其他线程,你可以:
在单独的 pid 中使用您的 Verticle 的多个实例(例如,使用 systemd 服务的多值实例,或 docker 容器或任何允许您 运行 多个 java 微服务的进程,使监控和故障恢复更容易)。
多次将您的 Verticle 部署为 Worker Verticle:https://vertx.io/docs/vertx-core/java/#worker_verticles
使用 executeBlocking
方法:https://vertx.io/docs/vertx-core/java/#blocking_code 但我不建议您使用它。
如果您的 Verticle 公开了一个 http restfull API,我建议您使用经典的 http 反向代理并管理容器内的多个实例,或者如果不能的话使用不同的主机或端口。并通过事件总线(或其他基于消息队列的系统)将操作委托给其他 Verticles。这是 .
的示例
据我所知,经过一些尝试和讨论(感谢 tsegismont),处理池中所有线程的唯一正确方法是:
DeploymentOptions deploymentOptions = new DeploymentOptions()
.setInstances(vertxOptions.getEventLoopPoolSize());
vertx.deployVerticle(() -> new MyServerVerticle(), deploymentOptions);
下面的实现有意外行为:
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);
}
}
并且没有正确的方法来创建 web-server 不使用具有多个 event-loops 的 Verticle 模型。在这种情况下,我们只能循环创建服务器,但我不确定它是否总是正确的:
class MyServerNotVerticle {
public void start() {
for (int i=0;i<vertxOptions.getEventLoopPoolSize();++i) {
vertx.createHttpServer()
.requestHandler(anyRouter::accept)
.listen(8080);
}
}
}
我使用 Vert.x v3.5.1。 有最简单的示例代码:
vertx.createHttpServer()
.requestHandler(anyRouter::accept)
.listen(8080);
在我的例子中,事件循环组大小为 16,所以我预计我的请求将影响 16 个线程。服务器已成功启动,但它仅在 一个线程 中工作。 (我使用不同的 tcp 连接发送请求,所以保持活动不是这里的原因。)
Class HttpServerImpl
包含 httpHandlerMgr
并且此管理器处理事件循环池(名为 availableWorkers
)。在调试过程中,我看到这个池只包含 一个 工作人员。
使用 Verticle 模型并不能解决问题,仍然没有使用所有线程。
如果我在循环中多次创建服务器,它会有所帮助。结果,我有许多受影响的线程和一个共享服务器。但它看起来像解决方法。
问题是如何创建使用所有可用事件循环线程的 Web 服务器?
下面用 Verticle 实现
因此,此实现使用了一半的可用线程(8 个线程)。但我希望它使用 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);
}
}
这里涉及到一个线程,这就是事件循环模型。我推荐观看Philip Roberts: What the heck is the event loop anyway? | JSConf EU 2014。示例适用于浏览器,但概念对于 server-side 事件循环系统(如 Vert.x 或 Node.
)是相同的但是,对于 Vert.x,您通常会在 Verticle 中组织代码(想想小型服务)。每个 Verticle 都分配有一个事件循环,但您可以部署多个实例。这就是您如何使用 CPU 的所有核心。如果您是 Java 程序员并且是第一次编写 Vert.x 应用程序,我建议您阅读这篇 guide。
至于将 Verticle 扩展到所有核心,问题是当您自己实例化 Verticle 时,您实际上创建了单独的部署并且无法保证使用不同的事件循环。
如 Specifying number of verticle instances 中所述,您必须使用 Verticle 名称:
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.
据此: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.
所以如果你想使用其他线程,你可以:
在单独的 pid 中使用您的 Verticle 的多个实例(例如,使用 systemd 服务的多值实例,或 docker 容器或任何允许您 运行 多个 java 微服务的进程,使监控和故障恢复更容易)。
多次将您的 Verticle 部署为 Worker Verticle:https://vertx.io/docs/vertx-core/java/#worker_verticles
使用
executeBlocking
方法:https://vertx.io/docs/vertx-core/java/#blocking_code 但我不建议您使用它。
如果您的 Verticle 公开了一个 http restfull API,我建议您使用经典的 http 反向代理并管理容器内的多个实例,或者如果不能的话使用不同的主机或端口。并通过事件总线(或其他基于消息队列的系统)将操作委托给其他 Verticles。这是
据我所知,经过一些尝试和讨论(感谢 tsegismont),处理池中所有线程的唯一正确方法是:
DeploymentOptions deploymentOptions = new DeploymentOptions()
.setInstances(vertxOptions.getEventLoopPoolSize());
vertx.deployVerticle(() -> new MyServerVerticle(), deploymentOptions);
下面的实现有意外行为:
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);
}
}
并且没有正确的方法来创建 web-server 不使用具有多个 event-loops 的 Verticle 模型。在这种情况下,我们只能循环创建服务器,但我不确定它是否总是正确的:
class MyServerNotVerticle {
public void start() {
for (int i=0;i<vertxOptions.getEventLoopPoolSize();++i) {
vertx.createHttpServer()
.requestHandler(anyRouter::accept)
.listen(8080);
}
}
}