Написание инструмента нагрузочного тестирования на Go

Мотивация:

В одной из моих предыдущих организаций у нас было требование нагрузочного тестирования микросервисов на основе Python и Scala, которые взаимодействовали через RabbitMQ (используя протокол AMQP 0.9, который сильно отличается от AMQP 1.0).

Мы уже использовали Jmeter в качестве предпочтительного инструмента нагрузочного тестирования для Rest API. Так что у меня было мало вариантов для работы

  1. Jmeter на основе AMQP плагин
  2. Сам RabbitMQ предоставляет грубый способ загрузки очередей через свой Тест производительности инструмент
  3. Последним вариантом было построить что-то свое

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

Теперь вопрос о том, было ли использование RPC поверх очередей сообщений правильным конструктивным решением или нет, мы обсудим в другой раз. 😃

Вывод состоял в том, чтобы не использовать плагин Jmeter или инструмент RabbitMQ Perf Test, а создать что-то свое.

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

Кстати, есть хороший инструмент генератора нагрузки, написанный на Go, который называется Vegeta, но он в основном для HTTP.

Прежде чем приступить к созданию инструмента, я хотел уточнить несколько вещей.

  1. В Go была доступна клиентская библиотека RabbitMQ, потому что RabbitMQ не предоставляет ее, к счастью, был один клиент с открытым исходным кодом. библиотека
  2. Мониторинг RabbitMQ с точки зрения ЦП, памяти, дискового ввода-вывода хоста, на котором работает узел RabbitMQ, а затем показателей отдельных очередей, таких как общее количество подключений, общее количество потребителей, общее количество сообщений и т. д. в данный момент времени. Есть несколько способов сделать это, как задокументировано здесь

Дизайн:

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

  1. Количество потоков/пользователей
  2. Время нарастания для этих пользователей
  3. Время выполнения теста
  4. Способ определения проб/тестов

Вот и все. Если бы я мог справиться с этими 4 вещами, мой инструмент был бы готов к использованию.

Код:

Первым делом нужно было принять пользовательский ввод для No of User, Ramp Up time и Execution time. Это было довольно просто, я мог установить это с помощью флагов командной строки.

1*icrb5c1Yu9ceOfl7dHvbww.png

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

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

1*jHzQ-ozIzGNGDIjHfNPKdA.png

Так, например, если бы мое время нарастания составляло 30 секунд, и у меня было всего 10 пользователей, я бы запускал новый пользовательский поток каждые 3 секунды.

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

Горутина это облегченный поток, созданный средой выполнения Go, когда любая именованная или анонимная функция вызывается с префиксом ключевого слова go

Ниже горутина подталкивает счетчик пользователей в канал каждый раз, когда он увеличивается, но не инициирует фактический пользовательский поток.

Канал объект в Go — это средство связи для горутин, которые взаимодействуют друг с другом путем отправки и получения сообщений и определяется ключевым словом chan

1*myPJnH_m2eJ-_94HP5NITg.png

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

1*Cbvpdo3dU0xyHUfOK4OdyA.png

После этого последним битом было использование двух каналов, определенных в приведенном выше коде, для управления потоком и выполнения необходимых тестов.
Этот фрагмент кода объединяет все основные функции Go, что делает параллелизм таким простым.

select это специальный оператор в Go, который блокирует выполнение до тех пор, пока какой-либо из каналов в операторах case не будет готов к операции отправки/получения.

1*-trWwnQgyC0HTKDNryDGEQ.png

И это все, что мне было нужно!! Я только что добавил все необходимые тестовые вызовы в приведенном выше for loop и смог бомбардировать очереди сообщений RabbitMQ сотнями пользователей, что потребовало чрезвычайно малого объема памяти на моем генераторе нагрузки!

Для мониторинга и отчетности я переместил все показатели в InfluxDB и использовал Grafana для визуализации в реальном времени.

Go — чрезвычайно мощный язык, когда дело доходит до параллелизма. Я бы порекомендовал каждому энтузиасту Go прочитать книгу Параллелизм в Go написано Кэтрин Кокс-Будей

Вы можете найти полную суть приведенного выше кода здесь

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *