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

VB_*_*VB_ 4 java high-load reactor vert.x

假设你需要写一个1000 rps的服务器.未来的负荷可能会增长.服务器只提供一种请求 - getGender(name)接受名称,并返回Male/ Female.性别的确定是最简单的操作,需要单个索引查找,其中索引是内存中的数据结构.

如果理解正确 - 您创建单个ServerVerticle,并运行Runtime.getRuntime().availableProcessors()委托作业的工作者Verticle(请参阅下面的代码).

问题:

  1. 这是1000 rps任务的最佳方案吗?
  2. 当15名工人效率低下时,请求峰值会发生什么?假设一个工人可以处理100 rps.你有15名工人.但在高峰时你有3000转.
    • 假设NetServer可以处理3000 rps,但工人坚持处理它们.让Vert.x有任何队列来保持等待请求吗?怎么做?如果有 - 工人失败会发生什么?
    • 假设NetServer无法处理3000 rps - 只运行服务器的几个实例.没有陷阱,对吧?
  3. TCP是这项任务的更好选择吗?
  4. Vert.x是多反应堆,它像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);
    } 
}
Run Code Online (Sandbox Code Playgroud)

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() { ... }
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*pes 6

这里有几个问题,对vert.x有一些误解.使用Verticles 实现代码后,您不需要实现自己的main方法,因为在木材下,内部main方法将使用什么来确保您可以拥有CPU能力的全部容量,而您不需要自己扩展它有:

//Deploy worker verticles
DeploymentOptions deploymentOptions = new DeploymentOptions()
  .setInstances(Runtime.getRuntime().availableProcessors())
Run Code Online (Sandbox Code Playgroud)

您应该阅读文档的以下部分.

其次,你指的是你GenderVerticle作为一名工人,因为它会为你做一些操作.请注意vertx,工作者意味着它应该在专用线程池上执行,因为可能发生该Verticle中的代码将执行某些阻塞IO.

使用工作模式将导致性能损失,因为您失去了异步IO的好处,并且您的请求需要为池中的线程排队.

由于您的示例解释了您的所有代码都在内存中查找,我认为它是CPU限制而不是IO绑定,这意味着您应该避免将其部署为工作者.

回到你的例子,你有1个Verticle处理所有HTTP流量,第二个处理它.为了获得最佳性能,您可能只需要1个Verticle,因为跳数较少,但此解决方案不会水平扩展(问题的原因)如何处理3000rps,假设一个节点只能执行1000rps.

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

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

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-hazelcast</artifactId>
  <version>3.3.3</version>
</dependency> 
Run Code Online (Sandbox Code Playgroud)

并通过标志启动您的应用程序--cluster.您将拥有一个由4台计算机组成的集群,其中请求将以循环方式对每个计算机进行负载平衡GenderVerticles.

由于HTTP代码是由netty高度优化的,因此您可能不需要多个服务器,如果不是这样,可以使用一个选项在服务器前添加流量负载均衡器并再次ServerVerticle在另一台机器上部署另一个在您的群集中,现在流量负载均衡器将负载平衡两个服务器之间的HTTP流量,这两个服务器将循环到GenderVerticles.

所以我猜你开始看到一种模式,一旦你的监控告诉你你的CPU/NetworkIO被最大化,你就会向集群添加更多的机器.