2016-10-20 5 views
2

Предположим, вам нужно написать сервер с 1000 рпс. Нагрузка может расти в будущем. Сервер обслуживает только один вид запроса - getGender(name), который принимает имя и возвращает Male/Female. Определение пола - это простейшая операция, которая требует поиска по одному индексу, где index - это структура данных в памяти.Vert.x: простой сервер с 1000 р.

Если вы правильно поняли - вы создаете одиночный ServerVerticle и выполняете Runtime.getRuntime().availableProcessors() рабочих вертикалей, на которые делегировать задание (см. Код ниже).

Вопросы:

  1. Это самая лучшая схема для задачи 1000 оборотов в секунду?
  2. Что произойдет по запросу, когда будет 15 рабочих? Предположим, что один рабочий может обрабатывать 100 rps. У вас 15 рабочих. Но в пиковое время у вас есть 3000 рпс.
    • Предположим, что NetServer может обрабатывать 3000 об/мин, но рабочие застревают у них. У Vert.x есть какая-либо очередь для ожидания ожидающих запросов? Как это сделать? Если это так - что происходит на рабочем месте?
    • Предположим, что NetServer не может обрабатывать 3000 rps - просто запустите несколько экземпляров сервера. Нет подводных камней, не так ли?
  3. Является ли TCP лучшим выбором для задачи?
  4. Vert.x - многореактор, который, подобно узлу, запускает цикл событий. ServerVerticle запущен в той же теме, что и event-loop, правильно?
  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() { ... } 
} 

ответ

4

Есть несколько вопросов здесь и некоторые неверные представления о vert.x. После того, как вы реализуете свой код с помощью Verticle, вам не нужно реализовывать свой собственный метод main, так как под деревом, что внутренний метод main сделает это, чтобы убедиться, что вы можете иметь полную мощность вашего процессора, и вам не нужно масштабировать себя:

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

Вы должны прочитать следующий раздел documentation.

Во-вторых, вы имеете в виду ваш GenderVerticle как рабочий , потому что он будет выполнять некоторые операции для вас. Обратите внимание, что в vertx, рабочий означает, что он должен выполняться в выделенном пуле потоков, так как может случиться, что код в этой вершине будет выполнять блокировку ввода-вывода.

Использование рабочий режим вводит штраф за производительность, так как вы теряете преимущества асинхронного ввода-вывода, и ваши запросы должны стоять в очереди за потоком из пула.

Поскольку ваш пример объясняет, что весь ваш код выполняет поиск в памяти, я предполагаю, что он ограничен ЦП и не связан с IO, что означает, что вам следует избегать его развертывания в качестве рабочего.

Возвращаясь к вашему примеру, у вас есть 1 вершина, которая обрабатывает весь трафик HTTP, а второй обрабатывает его. Для максимальной производительности вы можете иметь всего одну вертикаль, так как есть меньше переходов, но это решение не масштабируется горизонтально (причина вашего вопроса), как мне обрабатывать 3000rps, если один узел может принимать только 1000rps.

Теперь вы уже на правильном пути, вы разделить обработку HTTP с обработкой бизнеса, у него есть небольшое наказание, но если вы знаете, что 1 узел может обрабатывать 1000rps, и вы должны хотя бы обрабатывать 3000рп все, что вам нужно сделать развертывает GenderVerticle на 3 дополнительных машинах.

После того, как вы сделаете это и позволит кластеризацию, и это можно сделать, добавив зависимость (например: hazelcast):

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

И, начав свое приложение с флагом --cluster. У вас будет кластер из 4 машин, где запросы будут сбалансированы по нагрузке круговым способом для каждого из GenderVerticles.

Поскольку HTTP-код сильно оптимизирован netty, вам, вероятно, не понадобится больше одного сервера, если это не так, один вариант вы можете сделать это, чтобы добавить балансировку нагрузки на трафик перед вашими серверами и снова развернуть другой ServerVerticle на другом компьютере в вашем кластере, теперь балансировщик нагрузки нагрузки будет балансировать трафик HTTP между двумя серверами, которые будут округлять robin до GenderVerticles.

Итак, я думаю, вы начинаете видеть шаблон, который, как только ваш мониторинг сообщает вам, что ваш CPU/NetworkIO максимизируется, вы добавляете в кластер больше машин.

+0

благодарим вас за полное раскрытие! Но можете ли вы объяснить, как я могу извлечь выгоду из многопоточности/многоядерности, если бы у меня было только одно ServerVerticle/GenderVerticle на машину? Как Vert.x будет распараллеливать обработку запросов на одной машине, если она будет иметь только одну вершину? Извините, не нашли по ссылке http://vertx.io/docs/vertx-core/java/#_the_vert_x_launcher ответ, почему мне не нужен основной метод и совпадение процессора. Этот код 'Runtime.getRuntime(). AvailableProcessors()' также берется из той же документации –

+0

, другими словами, кластеризация - это решение, но как получить выгоду от всех 16 ядер одиночной машины с помощью Vert.x? –

+0

Возможно, документация не ясна, но поведение по умолчанию пусковой установки по умолчанию заключается в том, что она всегда будет порождать один цикл событий для ядра процессора. Таким образом, в вашем случае с 16 ядрами вы будете иметь 16 циклов событий. Это максимально увеличит использование вашего ЦП. Ответ здесь: http://vertx.io/docs/vertx-core/java/#_reactor_and_multi_reactor, но не ясно, что он предоставляется из коробки, если вы используете пусковую установку по умолчанию. –