【问题标题】:Vert.x: simplest server with 1000 rpsVert.x:最简单的服务器,1000 rps
【发布时间】:2016-10-20 09:46:10
【问题描述】:

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

如果理解正确 - 您创建单个 ServerVerticle,然后运行 ​​Runtime.getRuntime().availableProcessors() 工作节点,将作业委托给它(参见下面的代码)。

问题:

  1. 这是 1000 rps 任务的最佳方案吗?
  2. 当 15 个工作人员不足时,在请求高峰时会发生什么?假设一个工作人员可以处理 100 rps。你有 15 名工人。但是在高峰时间你有 3000 rps。
    • 假设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);
    } 
}

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() { ... }
}

【问题讨论】:

    标签: java vert.x reactor high-load


    【解决方案1】:

    这里有几个问题以及对 vert.x 的一些误解。一旦你使用Verticles 实现了你的代码,你就不需要实现你自己的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 限制,这意味着您应该避免将其部署为工作人员。

    回到您的示例,您有 1 个处理所有 HTTP 流量的 Verticle 和第二个处理它的 Verticle。为了获得最佳性能,您可能希望只有 1 个垂直,因为跳数较少,但此解决方案不能水平扩展(您的问题的原因)假设一个节点只能执行 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

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

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

    【讨论】:

    • 感谢您如此全面的披露!但是,如果每台机器只有一个 ServerVerticle/GenderVerticle,你能解释一下我将如何从多线程/多核中受益吗?如果 Vert.x 只有一个 Verticle,它将如何在单台机器上并行处理请求?抱歉,没有通过链接vertx.io/docs/vertx-core/java/#_the_vert_x_launcher 找到答案为什么我不需要 main 方法和手动 CPU 匹配。此代码Runtime.getRuntime().availableProcessors() 也取自同一文档
    • 换句话说集群是一种解决方案,但是如何利用 Vert.x 的单机 16 核全部受益?
    • 也许文档不清楚,但默认启动器的默认行为是它总是会为每个 CPU 内核生成一个事件循环。因此,在您有 16 个内核的情况下,您将有 16 个事件循环。这将使您的 CPU 使用率最大化。答案就在这里:vertx.io/docs/vertx-core/java/#_reactor_and_multi_reactor,但不清楚如果您使用默认启动器,它是否是开箱即用的。
    • 我的错,这在文档中说得很清楚。请再问一个问题 - 如果我有 ServerVerticleGenderVerticle 作为标准工作人员,Vert.x 默认情况下会将它们部署在单个实例中。所以会有一个GenderVerticle 的实例和16 个事件循环,对吧?并发将如何完成??
    • 假设您的实例确实施加了某种锁定(例如某处有一个同步块),那么您可能无法使用事件循环的全部容量,在这种情况下您可能会调整您的使用命令行参数--instances N 的性能将产生N Verticles 实例
    猜你喜欢
    • 2011-12-17
    • 2019-05-24
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 2013-12-24
    • 1970-01-01
    • 2012-02-26
    相关资源
    最近更新 更多