Рубрики
Без рубрики

SpringBoot2 Блокирующий Веб против реактивного Веба

Попробуйте Spring Reactive Web style и проверьте производительность. Помеченный как java, spring boot.

Привет, я Миц. Это первый пост на dev.to . Приятно познакомиться:)

Как многие из вас слышали, Микросервисы, блокчейн и т.д., Существует множество технических модных словечек, и они часто приходят и уходят. Поэтому для нас важно не верить им, даже не проверив, а самим увидеть, как они работают, а затем поместить их в наш набор инструментов. Вот почему на этот раз я попробовал использовать часть Реактивного программирования.

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

SpringBoot2, который был выпущен в начале этого месяца, представил функцию “Реактивный веб”. Поэтому я попытался сравнить “Spring Web” и “Spring Reactive Web”. ” Spring Web” основан на обычном стиле блокировки с помощью сервлета, а “Spring Reactive Web” – это новый стиль с реактивным программированием.

(Изображение с сайта (Изображение с сайта

Я нашел отличную статью, в которой сравниваются Spring Boot 1 и SpringBoot2: Необработанные показатели производительности – Spring Boot 2 Webflux vs. Пружинный ботинок 1 . Я сделал почти то же самое, чтобы сравнить SpringBoot2, блокирующий Веб, и Реактивный Веб. Архитектура выглядит следующим образом:

Есть 3 приложения:

  • задержка-сервис
  • блокировка-приложение
  • реактивный подход

Исходный код находится здесь: https://github.com/bufferings/webflux-demo-201803

задержка-сервис

Служба задержки эмулирует внешний API с некоторой задержкой. Мы можем установить задержку с помощью параметра path:

  @GetMapping("/{delayMillis}")
  public Mono get(@PathVariable int delayMillis) {
    return Mono.just("OK")
        .delayElement(Duration.ofMillis(delayMillis));
  }

блокировка-приложение

Блокирующее приложение – это простое веб-приложение Spring, которое вызывает службу задержки блокирующим способом и возвращает ее блокирующим способом:

  private static final String DELAY_SERVICE_URL = "http://localhost:8080";

  private final RestTemplate client;

  public BlockingApp(RestTemplateBuilder builder) {
    client = builder.rootUri(DELAY_SERVICE_URL).build();
  }

  @GetMapping("/{delayMillis}")
  public String get(@PathVariable String delayMillis) {
    String result = client.getForObject("/" + delayMillis, String.class);
    return "Blocking:" + result;
  }

реактивный подход

Реактивное приложение – это реактивное веб-приложение Spring, которое вызывает службу задержки с реактивным клиентом и возвращает Mono :

  private static final String DELAY_SERVICE_URL = "http://localhost:8080";

  private final WebClient client = WebClient.create(DELAY_SERVICE_URL);

  @GetMapping("/{delayMillis}")
  public Mono get(@PathVariable String delayMillis) {
    return client.get()
        .uri("/" + delayMillis)
        .retrieve()
        .bodyToMono(String.class)
        .map(s -> "Reactive:" + s);
  }

Задержка запуска-сервис:

./gradlew -p apps/delay-service clean bootRun

curl -w "\n%{time_total}s\n" localhost:8080/1000
# returns "OK" after 1000ms

curl -w "\n%{time_total}s\n" localhost:8080/2000
# returns "OK" after 2000ms

Начать блокировку-приложение:

./gradlew -p apps/blocking-app clean bootRun

curl -w "\n%{time_total}s\n" localhost:8081/2000
# returns "Blocking:OK" after 2000ms

Запустить реактивное приложение:

./gradlew -p apps/reactive-app clean bootRun

curl -w "\n%{time_total}s\n" localhost:8082/2000
# returns "Reactive:OK" after 2000ms

Теперь все три приложения запущены.

Сценарий нагрузочного тестирования

Я использовал Gatling( https://gatling.io/ ) для нагрузочного теста.

Сценарий выглядит примерно так: “1000 пользователей вызывают API 30 раз с интервалом от 1 до 2 секунд”. Я хотел бы установить задержку delay-service равной 300 мс.

  val myScenario = scenario("Webflux Demo").exec(
    repeat(30) {
      exec(
        http("request_1").get(targetUrl)
      ).pause(1 second, 2 seconds)
    }
  )
  setUp(myScenario.inject(rampUsers(simUsers).over(30 seconds)))

Переход от Гатлинга к блокировке-приложение

./gradlew -p apps/load-test -DTARGET_URL=http://localhost:8081/300 \
    -DSIM_USERS=1000 gatlingRun

С помощью VisualVM мы можем видеть, что количество рабочих потоков увеличивается до 200, что является значением maxthreads по умолчанию для Tomcat.

Гатлинг к реактивному подходу

./gradlew -p apps/load-test -DTARGET_URL=http://localhost:8082/300 \
    -DSIM_USERS=1000 gatlingRun

Он использует только 4 потока для обработки запроса.

Вот результат.

Как вы можете видеть, для 1000 пользователей оба приложения работают нормально со временем отклика около 300 мс, как мы и ожидали. Но для 3000 и 6000 пользователей 95-процентный показатель блокировки приложений становится хуже.

С другой стороны, reactive-app сохраняет хорошую скорость отклика около 400 мс и он показывает около 2000 оборотов в минуту с моим ноутбуком (Core i7-7500U 2,7 ГГц/16 ГБ оперативной памяти).

Интересный результат!

блокировка-приложение

блокировка-приложение

блокировка-приложение

блокировка-приложение

блокировка-приложение

блокировка-приложение

блокировка-приложение

с 6000 пользователями:

с 6000 пользователями:

Поскольку я решил попробовать использовать конфигурацию по умолчанию, количество потоков Tomcat достигло 200, что является значением maxThreads по умолчанию. Вероятно, настройка максимального потока улучшит производительность блокирующего приложения.

Отделение конверта

Поскольку я пробовал эту демонстрацию на своем ноутбуке, все приложения влияли друг на друга в отношении использования ресурсов. Таким образом, разделение каждого приложения на несколько машин может привести к другому результату.

В заключение, мы могли бы узнать, как SpringBoot2 Reactive Web эффективно обрабатывает запросы. Но я рекомендую вам проверить это самостоятельно. Я думаю, что особенно реактивное программирование в веб-стиле требует, чтобы Java-инженер в какой-то степени изменил свое мышление.

В любом случае, это так интересно, и я чувствую, что теперь SpringBoot2 Reactive Web находится в моем наборе инструментов. Спасибо!

Оригинал: “https://dev.to/bufferings/springboot2-blocking-web-vs-reactive-web-46jn”