java - Vert.x:最简单的 1000 rps 服务器

标签 java vert.x reactor high-load

假设您需要编写一个 1000 rps 的服务器。将来负载可能会增加。服务器仅服务于一种请求 - getGender(name),它接受一个名称,并返回 Male/Female。确定性别是最简单的操作,需要单索引查找,其中索引是内存中的数据结构。

如果理解正确 - 您创建单个 ServerVerticle,并运行 Runtime.getRuntime().availableProcessors() worker verticles 委托(delegate)作业(见下面的代码) .

问题:

  1. 对于1000rps的任务,这是不是最好的方案?
  2. 当 15 个工作人员不足时,请求高峰期会发生什么情况? 假设一个工作人员可以处理 100 rps。你有 15 个 worker 。但是在高峰时间你有 3000 rps。
    • 假设 NetServer 可以处理 3000 rps,但工作人员坚持处理它们。 Vert.x 是否有任何队列来保持等待请求?怎么做?如果有 - worker 失败会发生什么?
    • 假设 NetServer 无法处理 3000 rps - 只需运行服务器的几个实例。 没有陷阱,对吧?
  3. TCP 是这项任务的更好选择吗?
  4. Vert.x 是多 react 器,就像 Node 一样运行它的事件循环。 ServerVerticle 与事件循环在同一个线程中运行,对吗?
  5. 如果您有 16 个核心,其中 1 个核心专用于事件循环,那么 Vert.x 将运行 15 个 GenderVerticles,对吗?没有更多的阅读?

ServerVerticle.java

public class ServerVerticle extends AbstractVerticle {

    public static void main(String[] args) {
        Consumer<Vertx> runner = vertx -> vertx.deployVerticle("ServerVerticle", new DeploymentOptions());
        Vertx vertx = Vertx.vertx();
        runner.accept(vertx);
    }

    @Override
    public void start() throws Exception {
        NetServerOptions options = new NetServerOptions();
        NetServer server = vertx.createNetServer(options);
        server.connectHandler(socket -> {
            socket.handler(buffer -> {
                vertx.eventBus.send("get.gender", buffer, res -> socket.write(res.toString()));
            });
        });
        server.listen(1234, "localhost");

        //Deploy worker verticles
        DeploymentOptions deploymentOptions = new DeploymentOptions()
            .setInstances(Runtime.getRuntime().availableProcessors())
            .setWorker(true);
       vertx.deployVerticle("GenderServiceVerticle", deploymentOptions);
    } 
}

GenderVerticle.java

public class GenderVerticle extends AbstractVerticle {

    @Override
    public void start() throws Exception {
        vertx.eventBus().consumer("get.gender", message -> {
            String gender = singleIndexLookup(message);
            message.reply(gender);
        });
    }

    singleIndexLookup() { ... }
}

最佳答案

这里有几个问题和一些关于 vert.x 的误解。一旦你使用 Verticle 实现你的代码,你就不需要实现你自己的 main 方法,因为在木头下,内部 main 方法将这样做是为了确保您可以充分发挥 CPU 的能力,并且不需要自己扩展它:

//Deploy worker verticles
DeploymentOptions deploymentOptions = new DeploymentOptions()
  .setInstances(Runtime.getRuntime().availableProcessors())

您应该阅读 documentation 的以下部分.

其次,您将 GenderVerticle 称为 worker,因为它会为您执行一些操作。请注意,在 vertx 中,worker 意味着它应该在专用线程池上执行,因为该 Verticle 中的代码可能会执行一些阻塞 IO。

使用worker 模式会带来性能损失,因为您失去了异步 IO 的优势,并且您的请求需要排队等待池中的线程。

由于您的示例说明您的所有代码所做的都是内存查找,我假设它受 CPU 限制而不是 IO 限制,这意味着您应该避免将其部署为 worker 。

回到您的示例,您有 1 个处理所有 HTTP 流量的 Verticle 和另一个处理它的 Verticle。为了获得最佳性能,您可能希望只有 1 个 Verticle,因为跳数较少,但此解决方案无法水平扩展(您提出问题的原因)假设一个节点只能执行 1000rps,我如何处理 3000rps。

现在您已经走上了正确的道路,您将 http 处理与业务处理分开,它有一点损失,但是如果您知道 1 个节点可以处理 1000rps 并且您必须至少处理 3000rps,那么您需要做的就是在 3 台额外的机器上部署 GenderVerticle

执行此操作并启用集群后,您可以通过添加依赖项(例如:hazelcast)来执行此操作:

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-hazelcast</artifactId>
  <version>3.3.3</version>
</dependency> 

然后使用标志 --cluster 启动您的应用程序。您将拥有一个由 4 台机器组成的集群,其中请求将以循环方式负载均衡到每个 GenderVerticles

由于 HTTP 代码由 netty 高度优化,您可能不需要超过一台服务器,如果不是这种情况,您可以选择在服务器前面添加一个流量负载均衡器,然后再次部署另一个ServerVerticle 在集群中的另一台机器上,现在流量负载均衡器将对 2 个服务器之间的 HTTP 流量进行负载均衡,这两个服务器将轮询到 GenderVerticles

所以我猜你开始看到这样一种模式,即一旦你的监控告诉你你的 CPU/NetworkIO 已达到极限,你就会向集群添加更多机器。

关于java - Vert.x:最简单的 1000 rps 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40150925/

相关文章:

java - 在 vertx 中创建 cookie

java - Vertx 上的并发

Java CompletableFuture.complete() block

spring-boot - Reactor 3 - 如何在 Mono 错误时返回 Flux?

javassist :javassist vs org. javassist:javassist

java - Hadoop 资源管理器未启动

java - 从 JOptionPane 下拉列表框中选择后无法刷新 jtextarea

javascript - 安装vertx时出错(vertx运行server.js)

java - 有没有办法让两个类使用相同的泛型?

python - Twisted:WAITING延迟到 'finish'