我使用 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);
}
}
}