Vertx Web 服务器仅使用一个事件循环线程,而有 16 个可用线程



我使用 Vert.x v3.5.1。 有最简单的代码示例:

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

在我的情况下,事件循环组大小为 16,因此我希望我的请求将影响 16 个线程。服务器已成功启动,但它仅在一个线程中工作。(我使用不同的 tcp 连接发送了请求,所以保持活动状态不是这里的原因。
HttpServerImpl包含httpHandlerMgr,此管理器处理事件循环池(名为availableWorkers)。在调试期间,我看到这个池包含一个工作线程。

使用Verticle 模型并不能解决问题,仍然没有使用所有线程。

如果我在循环中多次创建服务器,它会有所帮助。结果,我有许多受影响的线程和一个共享服务器。但它看起来像解决方法。

问题是如何创建使用所有可用事件循环线程的 Web 服务器?

下面使用顶点实现

因此,此实现使用一半的可用线程(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);
}
}

涉及单个线程,这正是事件循环模型。我建议看菲利普·罗伯茨:事件循环到底是什么? |JSConf EU 2014.示例适用于浏览器,但对于服务器端事件循环系统(如 Vert.x 或 Node),概念是相同的。

但是,使用 Vert.x,您通常以垂直点(考虑小型服务)组织代码。每个顶点都分配有一个事件循环,但您可以部署多个实例。这就是您使用CPU的所有内核的方式。如果您是 Java 程序员并且是第一次编写 Vert.x 应用程序,我建议您阅读本指南。

至于将顶点扩展到所有内核,问题是,当您自己实例化顶点时,您实际上创建了单独的部署,并且无法保证使用不同的事件循环。

如指定顶点实例数中所述,必须使用顶点名称:

使用垂直点名称部署顶点时,可以指定 要部署的顶点实例数:

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

这对于跨多个内核轻松扩展非常有用。例如 您可能有一个要部署的 Web 服务器顶点和多个内核 您的计算机,因此您希望部署多个实例以利用所有 核心。

根据这个: https://vertx.io/docs/vertx-core/java/#_reactor_and_multi_reactor

即使 Vertx 实例维护多个事件循环,任何特定的处理程序也永远不会并发执行,并且在大多数情况下(工作线程除外)将始终使用完全相同的事件循环进行调用。

因此,如果您想使用其他线程,您可以:

  • 在单独的 pid 中使用顶点的多个实例(例如,使用 systemd 服务的多值实例,或 docker 容器或任何允许您运行微服务的多个 Java 进程并使监视和故障恢复更容易的实例)。

  • 多次将顶点部署为辅助角色顶点:https://vertx.io/docs/vertx-core/java/#worker_verticles

  • 使用executeBlocking方法:https://vertx.io/docs/vertx-core/java/#blocking_code 但我不会命令你使用它。

如果您的顶点公开了 http restfull API,我会重新命令您使用经典的 http 反向代理并管理容器内的多个实例,或者如果您不能使用不同的主机或端口,则使用不同的主机。并通过事件总线(或其他基于消息队列的系统)将操作委托给其他顶点。下面是一个设计示例。

经过一些尝试和讨论后我所理解的(感谢您的 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);
}
}

并且没有正确的方法可以在不使用具有多个事件循环的 Verticle 模型的情况下创建 Web 服务器。在这种情况下,我们只能循环创建服务器,但我不确定它是否总是正确的:

class MyServerNotVerticle {
public void start() {
for (int i=0;i<vertxOptions.getEventLoopPoolSize();++i) {
vertx.createHttpServer()
.requestHandler(anyRouter::accept)
.listen(8080);
}
}
}

相关内容

  • 没有找到相关文章

最新更新