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

时间:2016-10-20 09:46:10

标签: java vert.x reactor high-load

假设您需要编写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,对吧?不再有?
  6. 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() { ... }
    }
    

1 个答案:

答案 0 :(得分:6)

这里有几个问题,对vert.x有一些误解。使用Verticle实现代码后,您不需要实现自己的main方法,因为在内部main方法下,内部//Deploy worker verticles DeploymentOptions deploymentOptions = new DeploymentOptions() .setInstances(Runtime.getRuntime().availableProcessors()) 方法将确保您拥有完全满足您的CPU功率,您无需自行扩展:

GenderVerticle

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

其次,您指的是vertx作为工作人员,因为它会为您执行某些操作。请注意,在GenderVerticle中, worker 表示它应该在专用线程池上执行,因为可能发生该Verticle中的代码将执行某些阻塞IO。

使用 worker 模式会导致性能下降,因为您失去了异步IO的好处,并且您的请求需要为池中的线程排队。

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

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

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

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

--cluster

使用标记GenderVerticles启动应用程序。您将拥有一台包含4台计算机的集群,其中请求将以循环方式对每个ServerVerticle进行负载平衡。

由于netty对HTTP代码进行了高度优化,因此您可能不需要多个服务器,如果不是这样,可以使用一个选项在服务器前添加流量负载均衡器并再次部署另一个服务器GenderVerticles在群集中的另一台计算机上,现在流量负载均衡器将对2个服务器之间的HTTP流量进行负载均衡,这些服务器将循环到$date = Carbon::now(); // or $date = new Carbon(); $date->setISODate(2016,42); // 2016-10-17 23:59:59.000000 echo $date->startOfWeek(); // 2016-10-17 00:00:00.000000 echo $date->endOfWeek(); // 2016-10-23 23:59:59.000000

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