Сравнение встроенных контейнеров сервлетов в Spring Boot

Сравнение встроенных контейнеров сервлетов в Spring Boot

1. Вступление

Растущая популярность облачных приложений и микросервисов порождает повышенный спрос на встроенные контейнеры сервлетов. Spring Boot позволяет разработчикам легко создавать приложения или сервисы, используя 3 наиболее доступных контейнера: Tomcat, Undertow и Jetty.

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

2. зависимости

Наша настройка для каждой доступной реализации контейнера всегда требует, чтобы мы объявляли зависимость отspring-boot-starter-web в нашемpom.xml.

В общем, мы хотим указать нашего родителя какspring-boot-starter-parent, а затем включить нужные нам стартеры:


    org.springframework.boot
    spring-boot-starter-parent
    2.0.3.RELEASE
    



    
        org.springframework.boot
        spring-boot-starter
    

    
        org.springframework.boot
        spring-boot-starter-web
    

2.1. Кот

Никаких дополнительных зависимостей при использовании Tomcat не требуется, поскольку он включен по умолчанию при использованииspring-boot-starter-web.

2.2. пристань

Чтобы использовать Jetty, нам сначала нужно исключитьspring-boot-starter-tomcat изspring-boot-starter-web.

Затем мы просто объявляем зависимость отspring-boot-starter-jetty:


    org.springframework.boot
    spring-boot-starter-web
    
        
            org.springframework.boot
            spring-boot-starter-tomcat
        
    


    org.springframework.boot
    spring-boot-starter-jetty

2.3. отлив прибоя

Настройка Undertow идентична Jetty, за исключением того, что мы используемspring-boot-starter-undertow в качестве нашей зависимости:


    org.springframework.boot
    spring-boot-starter-web
    
        
            org.springframework.boot
            spring-boot-starter-tomcat
        
    


    org.springframework.boot
    spring-boot-starter-undertow

2.4. Привод

Мы будем использовать Spring Boot’s Actuator как удобный способ как нагрузить систему, так и запросить показатели.

См.this article для получения подробной информации о приводе. Мы просто добавляем зависимость в нашpom, чтобы сделать его доступным:


    org.springframework.boot
    spring-boot-starter-actuator

 2.5. Apache Bench

Apache Bench - это утилита для нагрузочного тестирования с открытым исходным кодом, которая поставляется в комплекте с веб-сервером Apache.

Пользователи Windows могут загрузить Apache от одного из сторонних поставщиков, связанных сhere. Если Apache уже установлен на вашем компьютере с Windows, вы сможете найтиab.exe в каталогеapache/bin.

Если вы работаете на машине Linux,ab можно установить с помощьюapt-get с помощью:

$ apt-get install apache2-utils

3. Метрики запуска

3.1. Коллекция

Чтобы собрать показатели запуска, мы зарегистрируем обработчик событий для запуска Spring BootApplicationReadyEvent.

Мы программно извлечем интересующие нас показатели, напрямую работая сMeterRegistry, используемыми компонентом Actuator:

@Component
public class StartupEventHandler {

    // logger, constructor

    private String[] METRICS = {
      "jvm.memory.used",
      "jvm.classes.loaded",
      "jvm.threads.live"};
    private String METRIC_MSG_FORMAT = "Startup Metric >> {}={}";

    private MeterRegistry meterRegistry;

    @EventListener
    public void getAndLogStartupMetrics(
      ApplicationReadyEvent event) {
        Arrays.asList(METRICS)
          .forEach(this::getAndLogActuatorMetric);
    }

    private void processMetric(String metric) {
        Meter meter = meterRegistry.find(metric).meter();
        Map stats = getSamples(meter);

        logger.info(METRIC_MSG_FORMAT, metric, stats.get(Statistic.VALUE).longValue());
    }

    // other methods
}

Мы избегаем необходимости вручную запрашивать конечные точки Actuator REST или запускать отдельную консоль JMX, регистрируя интересные метрики при запуске в нашем обработчике событий.

3.2. выбор

Существует большое количество метрик, которые Actuator предоставляет из коробки. Мы выбрали 3 метрики, которые помогают получить общий обзор ключевых характеристик времени выполнения после запуска сервера:

  • jvm.memory.used - общая память, используемая JVM с момента запуска

  • jvm.classes.loaded - общее количество загруженных классов

  • jvm.threads.live - общее количество активных потоков. В нашем тесте это значение можно рассматривать как количество потоков «в состоянии покоя».

4. Метрики времени выполнения

4.1. Коллекция

В дополнение к предоставлению показателей запуска мы будем использовать точку отправки/metrics , предоставляемую Actuator, в качестве целевого URL-адреса при запуске Apache Bench, чтобы загрузить приложение.

Чтобы протестировать реальное приложение под нагрузкой, мы могли бы вместо этого использовать конечные точки, предоставленные нашим приложением.

После запуска сервера мы получим командную строку и выполнимab:

ab -n 10000 -c 10 http://localhost:8080/actuator/metrics

В приведенной выше команде мы указали в общей сложности 10 000 запросов с использованием 10 параллельных потоков.

4.2. выбор

Apache Bench может очень быстро предоставить нам некоторую полезную информацию, включая время соединения и процент запросов, которые были обработаны в течение определенного времени.

Для наших целейwe focused on requests-per-second and time-per-request (mean).

5. Результаты

При запуске мы обнаружили, чтоthe memory footprint of Tomcat, Jetty, and Undertow was comparable с Undertow требует немного больше памяти, чем два других, и Jetty требует наименьшего количества.

Для нашего теста мы обнаружили, чтоthe performance of Tomcat, Jetty, and Undertow was comparable, но чтоUndertow was clearly the fastest and Jetty only slightly less fast. 

метрический

Кот

пристань

отлив прибоя

jvm.memory.used (MB)

168

155

164

jvm.classes.loaded

9869

9784

9787

jvm.threads.live

25

17

19

Запросов в секунду

1542

1627

1650

Среднее время на запрос (мс)

6.483

6.148

6.059

Обратите внимание, что метрики, естественно, являются репрезентативными для проекта «голыми руками»; показатели вашего собственного приложения наверняка будут другими.

6. Обсуждение контрольных показателей

Разработка соответствующих тестов производительности для тщательного сравнения серверных реализаций может оказаться сложной. Чтобы извлечь наиболее актуальную информацию,it’s critical to have a clear understanding of what’s important for the use case in question.

Важно отметить, что контрольные измерения, собранные в этом примере, были выполнены с использованием очень специфической рабочей нагрузки, состоящей из HTTP-запросов GET к конечной точке Actuator.

It’s expected that different workloads would likely result in different relative measurements across container implementations. Если бы потребовались более надежные или точные измерения, было бы очень неплохо создать план испытаний, который бы более точно соответствовал производственному сценарию использования.

Кроме того, более сложное решение для сравнительного анализа, такое какJMeter илиGatling, вероятно, даст более ценную информацию.

7. Выбор контейнера

Selecting the right container implementation should likely be based on many factors that can’t be neatly summarized with a handful of metrics alone. Уровень комфорта, функции, доступные параметры конфигурации и политика часто одинаково важны, если не более того.

8. Заключение

В этой статье мы рассмотрели реализации встроенных контейнеров сервлетов Tomcat, Jetty и Undertow. Мы изучили характеристики времени исполнения каждого контейнера при запуске с конфигурациями по умолчанию, посмотрев на показатели, предоставляемые компонентом Actuator.

Мы выполнили искусственную нагрузку на работающую систему, а затем измерили производительность с помощью Apache Bench.

Наконец, мы обсудили достоинства этой стратегии и упомянули несколько вещей, которые следует иметь в виду при сравнении показателей реализации. Как всегда, весь исходный код можно найтиover on GitHub.