Привет, Хабр! Вы когда-нибудь задумывались, насколько ваш веб-сервис способен выдержать шквал запросов? Что произойдёт, если ваши пользователи, словно зомби, хлынут на сервер тысячами? Вот тут-то и начинается история про нагрузочное тестирование, которое помогает понять, где у вашего приложения «узкие места». А инструмент, о котором мы сегодня поговорим, — Gatling. Это мощная, элегантная и, честно говоря, недооценённая альтернатива монстрам вроде JMeter, LoadRunner и k6. Но давайте разбираться по порядку.

Что такое Gatling? И зачем он нужен?

Представьте, что ваш сервер — это кафе. Клиенты приходят, заказывают капучино, занимают столики и ожидают обслуживания. Всё идёт гладко, пока посетителей немного. Но вот, внезапно, толпа людей устремляется в ваше уютное кафе. Могут ли ваши бариста справиться? Хватит ли столиков? Не придётся ли кому-то пить кофе на улице? Вот именно эти вопросы Gatling помогает решить для вашего веб-приложения. Он проверяет, как сервер поведёт себя при нагрузке, начиная с нескольких пользователей и заканчивая тысячами.

Gatling — это современный инструмент для нагрузочного тестирования. Он написан на Scala, но не пугайтесь — сценарии можно писать и на Java или Kotlin, что особенно удобно для пользователей, привыкших к этому языку. Благодаря совместимости с Maven или Gradle, интеграция Gatling в ваш проект становится лёгкой и удобной.
Поскольку Gatling использует архитектуру Akka, управляемую сообщениями, он может запускать тысячи виртуальных пользователей на одной машине. Это связано с тем, что Akka отменяет ограничение JVM на обработку большого количества потоков. Виртуальные пользователи в Gatling — это сообщения, а не потоки.

Почему Gatling? А что с другими?

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

1. Gatling против JMeter


JMeter — один из самых популярных инструментов, но он далеко не идеален:

  • Тяжелый GUI: Для создания тестов приходится использовать графический интерфейс, что неудобно для версионирования и автоматизации.

  • Высокое потребление ресурсов: JMeter создаёт отдельный поток для каждого виртуального пользователя, что значительно нагружает систему.

  • Сложность работы с параметризацией: Работа с внешними данными требует дополнительных настроек и не всегда интуитивно понятна.

Преимущества Gatling:

  • Лёгкие и читаемые сценарии на Java или Scala.

  • Низкое потребление ресурсов благодаря асинхронной архитектуре.

  • Простая параметризация через CSV, JSON или другие источники данных.

2. Gatling против LoadRunner

LoadRunner — корпоративный гигант с мощным функционалом, но:

  • Высокая стоимость: Это коммерческий инструмент с дорогими лицензиями.

  • Сложность настройки: Для начальной настройки LoadRunner требуется больше времени.

  • Устаревший подход: Скрипты LoadRunner выглядят громоздко и требуют специфических знаний.

Преимущества Gatling:

  • Открытый исходный код и бесплатность.

  • Интеграция в CI/CD: запуск тестов легко автоматизировать.

  • Современные отчёты с подробной аналитикой.

3. Gatling против k6

k6 — ещё один популярный инструмент, который часто сравнивают с Gatling. Основные минусы k6:

  • Язык сценариев: k6 использует JavaScript, который не всем удобен для сложных тестов.

  • Ограниченный функционал для отчётов: Отчёты менее детализированы по сравнению с Gatling.

  • Проблемы с параметризацией: Работа с большими данными требует дополнительных усилий.

Преимущества Gatling:

  • Гибкий DSL для описания сценариев.

  • Более мощные и информативные отчёты.

  • Возможность интеграции с Java-проектами через Maven или Gradle.

Как это работает? Быстрое погружение в сценарии

Для работы с Gatling с использованием языка программирования Java необходимо выбрать одну из IDEA и сборщик Maven или Gardle. Я в качестве примера буду использовать IntellijIDEA и Maven.

Для начала необходимо создать новый проект с произвольным названием.

Если сразу создавать Maven Archetype и выбрать Catalog -> Maven Central то Gatling будет сразу доступен в качестве Archetype с установленными для работы нужными зависимости.
Если сразу создавать Maven Archetype и выбрать Catalog -> Maven Central то Gatling будет сразу доступен в качестве Archetype с установленными для работы нужными зависимости.

Если же вы создали обычный проект Maven с выбором стандартного Archetype то дополнительно можно подтянуть нужные зависимости и плагин в pom.xml

<dependencies>
    <dependency>
      <groupId>io.gatling.highcharts</groupId>
      <artifactId>gatling-charts-highcharts</artifactId>
      <version>${gatling.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven-compiler-plugin.version}</version>
      </plugin>
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>${maven-resources-plugin.version}</version>
      </plugin>
      <plugin>
        <groupId>io.gatling</groupId>
        <artifactId>gatling-maven-plugin</artifactId>
        <version>${gatling-maven-plugin.version}</version>
      </plugin>
    </plugins>
  </build>

Теперь давайте посмотрим на простой сценарий в Gatling, чтобы понять, как он работает.

Настройка протокола

Для начала нужно настроить протокол — это как задать маршрут для бариста, чтобы они знали, куда подавать кофе.

HttpProtocolBuilder httpProtocol = http
    .baseUrl("https://example.com") // Ваш сервер
    .acceptHeader("application/json");

Создание сценария

Сценарий — это план действий виртуального пользователя. Например:

ScenarioBuilder scn = scenario("Basic Scenario")
    .exec(http("Get Home Page")
        .get("/")
        .check(status().is(200)))
    .pause(5) // пауза 5 секунд
    .exec(http("Search Query")
        .get("/search?q=gatling")
        .check(status().is(200)));

Каждый .exec() — это шаг. Здесь мы:

  1. Делаем запрос на главную страницу.

  2. Ждём 5 секунд (имитация реального поведения).

  3. Выполняем поиск.

Методы Gatling: детально о каждом шаге

Теперь рассмотрим ключевые методы Gatling, которые используются в скриптах:

  1. exec(): Выполняет действия. Это основной метод для отправки запросов или выполнения пользовательских действий.

exec(http("Get Home Page").get("/").check(status().is(200)));

Внутри exec можно передавать запросы или проверки, которые сервер должен пройти.

  1. pause(): Добавляет паузу между действиями. Полезно для имитации реального поведения пользователей.

pause(2); // Пауза 2 секунды
pause(1, 5); // Пауза от 1 до 5 секунд
  1. repeat(): Повторяет определённое действие несколько раз.

repeat(10).on(
    exec(http("Repeated Request").get("/repeat"))
);
  1. feed(): Используется для подачи данных из внешнего источника, например CSV или JSON.

Iterator<Map<String, Object>> feeder = csv("users.csv").readRecords();
scn.feed(feeder);
  1. group(): Группирует действия для отображения в отчёте.

group("User Actions").on(
    exec(http("Login").post("/login")),
    exec(http("Get Data").get("/data"))
);

Настройка нагрузки

Когда сценарий готов, вы задаёте нагрузку. Например:

setUp(
    scn.injectOpen(rampUsers(50).during(30)) // Постепенно добавляем 50 пользователей за 30 секунд
).protocols(httpProtocol);

Дополнительные методы

doIf() и doIfOrElse()Позволяют выполнять действия на основе условий.

scn.exec(session -> session.set("flag", true)) // Устанавливаем флаг
   .doIf(session -> session.getBoolean("flag")).then(
       exec(http("Condition Met").get("/condition"))
   );
  • doIf(): Выполняет блок кода, если условие истинно.

  • doIfOrElse(): Позволяет задать альтернативный блок действий.

tryMax() Позволяет повторить шаг определённое количество раз при неудаче (например, если HTTP-запрос возвращает ошибку).

tryMax(3).on(
    exec(http("Retry Request").get("/unstable-endpoint"))
);

В этом примере запрос будет повторён максимум 3 раза, если произойдёт ошибка.

foreach() Циклически обрабатывает элементы коллекции.

List<String> items = Arrays.asList("item1", "item2", "item3");

scn.foreach(items, "item").on(
    exec(http("Get Item").get("/items/${item}"))
);
  • items: Коллекция, элементы которой будут обрабатываться.

  • ${item}: Переменная для текущего элемента в цикле.

exitHereIf() Позволяет завершить сценарий для конкретного пользователя, если выполняется определённое условие.

scn.exec(http("Check Status")
    .get("/status")
    .check(status().is(500)))
    .exitHereIf(session -> session.contains("error"));

Если сессия содержит ошибку, выполнение сценария для пользователя будет прервано.

rendezVous() Используется для синхронизации пользователей в сценарии. Например, вы можете заставить группу пользователей начать следующий шаг одновременно.

scn.rendezVous(10) // Ждёт, пока 10 пользователей достигнут этой точки
    .exec(http("Sync Step").get("/sync"));

during() Позволяет выполнять блок действий в течение заданного периода времени.

scn.during(30).on( // Выполняет в течение 30 секунд
    exec(http("Ping Server").get("/ping"))
);

randomSwitch() Позволяет случайным образом выбирать блоки действий с определённой вероятностью.

scn.randomSwitch()
    .on(
        70.0, exec(http("70% Path").get("/path1")),
        30.0, exec(http("30% Path").get("/path2"))
    );
  • 70.0 и 30.0: Процент вероятности выполнения блока.

Далее из консоли вводим стандартную команду mvn clean install для сборки проекта и далее mvn gatling:test для запуска Gatling сценария.

И всё! Вы запускаете тест и смотрите, как сервер справляется.
Всю представленную информацию так же можно найти на официальном сайте
Документация Gatling

Комментарии (2)


  1. strelkove
    16.12.2024 14:45

    Сравнения с Locust нет, потому что Locust лучше)))


    1. RomanPers Автор
      16.12.2024 14:45

      Вполне возможно, его еще не пробовал. Спасибо за комментарий))