Yandex.Tank: нагрузочное тестирование

Автор: | 02/09/2021
 

Кроме горячо любимых Apache Bench и JMeter имеется интересная утилита Yandex Tank.

Ей давно пользуются наши QA, пришло время и мне его потрогать для проверки одной проблемы с Kubernetes, о которой поговорим в следующем посте.

В этом — посмотрим на базовые возможности Yandex.Tank.

Из особенно приятного — в отличии от Apache Bench выводит статистику по кодам ответов, и проще в настройке и запуске, чем JMeter, плюс гибкая настройка автостопа на случай, если «Что-то пошло не так» (с)

Компоненты

См. Modules.

Сам Yandex Tank написан Python.

Для выполнения тестов имеется несколько модулей Load generators, по-умолчанию используется Phantom на С++.

Telegraf — для мониторинга тестируемого хоста — подключается по SSH, запускает свой агент и снимает метрики CPU/mem/etc.

Overloader — используется для загрузки полученных данных в Yandex Overloader или InfluxDB, но мы им не воспользуемся. См. Artifact uploaders.

Кроме того, в примерах ниже не рассматривается создание отдельных «патронов» (ammo), т.к. мы не QA, и мне пока достаточно будет простых GET на какие-нибудь URI. Still, см. документацию по ним в Preparing requests.

Запуск

Создадим минимальный конфиг для запуска Phantom:

phantom:
  address: rtfm.co.ua:443
  header_http: "1.1"
  headers:
    - "[Host: rtfm.co.ua]"
  uris:
    - /
  load_profile:
    load_type: rps
    schedule: const(1,30s)
  ssl: true
console:
  enabled: true
telegraf:
  enabled: false

Тут:

  • phantom:
    • address: адрес и порт тестируемого хоста
    • header_http: версия HTTP для тестов, зададим 1.1, что бы использовать одно соединение на запросы, а не открывать новое каждый раз (см. HTTP persistent connection)
    • headers: заголовки, передаваемые на тестируемый сервер
    • uris: список URI, к которым выполняем запросы
    • load_profile:
      • load_type: может быть rps или instances:
        • rps: requests per second — указываем желаемое количество запросов в секунду
        • instances: указываем желаемое количество активных тредов, которые будут генерировать столько rps, сколько смогут, см. Dynamic thread limit
      • schedule: может быть const, line или step (или все три вместе) — определяет характер генерируемой нагрузки, см. Tutorials:
        • const: указывается в виде (load,dur), где load — кол-во rps, dur — время для выполнение тестирования, в примере выше — выполняем 1 запрос в секундв течении 30 секунд
        • line: указывается в виде (a,b,dur), где a — начальное кол-во rps, b — конечное, dur — время для выполнение тестирования, в кечении котрого значение будет линейно увеличиваться от a до b
        • step: указывается в виде (a,b,step,dur), где a — начальное кол-во rps, b — конечное, step — на сколько rps увеличивать, dur — время между каждым step
    • ssl: включаем поддержку запросов по HTTPS (не забываем указать 443 в address)
  • console: включаем вывод результатов в консоль
  • telegraf: агент мониторинга для сбора метрик с тестируемого хоста, рассмотрим в Monitoring (Telegraf)

И запускаем Танк из Docker-образа:

docker run --rm -v $(pwd):/var/loadtest -it direvius/yandex-tank

Результат:

Monitoring (Telegraf)

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

Включаем его в load.yaml:

...
telegraf:
  enabled: true
  package: yandextank.plugins.Telegraf

Настройки метрик описываются в отдельном файле, создаём monitoring.xml, см. Configuration file format:

<Monitoring>
  <Host address="rtfm.co.ua" interval="1" username="root">
    <CPU />
    <Kernel />
    <Net />
    <System />
    <Memory />
    <Disk />
    <Netstat/>
  </Host>
</Monitoring>

Тут в address — сервер, с которого будем собирать метрики, interval — интервал сбора метрик, username — пользователь, под которым Telegraf будет подключаться на сервер.

При этом у этого пользователя на тестируемом хосте в ~/.ssh/authorized_keys должна быть записана публичная часть SSH-ключа для аутентификации (см. SSH: авторизация по ключам).

Приватную часть передадим в контейнер  исмонтируем в контейнер в файл /root/.ssh/id_rsa, т.к. процессы в контейнере запускаются под рутом:

docker run --rm -v $(pwd):/var/loadtest -v /home/setevoy/.ssh/setevoy-do-nextcloud-production-d10-03-11:/root/.ssh/id_rsa -it direvius/yandex-tank

Paramiko: SSHException: not a valid RSA private key file

При первом запуске Telegraf выдал ошибку:

16:32:54 [ERROR] Failed to install monitoring agent to rtfm.co.ua
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/yandextank/plugins/Telegraf/client.py", line 209, in install
out, errors, err_code = self.ssh.execute(cmd)
File "/usr/local/lib/python2.7/dist-packages/yandextank/common/util.py", line 72, in execute
with self.connect() as client:
File "/usr/local/lib/python2.7/dist-packages/yandextank/common/util.py", line 42, in connect
timeout=self.timeout, )
File "/usr/local/lib/python2.7/dist-packages/paramiko/client.py", line 437, in connect
passphrase,
File "/usr/local/lib/python2.7/dist-packages/paramiko/client.py", line 749, in _auth
raise saved_exception
SSHException: not a valid RSA private key file

Возникает она из-за формата ключа — на DigitalOcean он по-умолчанию в PEM/OpenSSH.

Проверяем:

file /home/setevoy/.ssh/setevoy-do-nextcloud-production-d10-03-11
/home/setevoy/.ssh/setevoy-do-nextcloud-production-d10-03-11: OpenSSH private key

Конвертируем его в RSA:

ssh-keygen -p -m PEM -f /home/setevoy/.ssh/setevoy-do-nextcloud-production-d10-03-11

Проверяем снова:

file /home/setevoy/.ssh/setevoy-do-nextcloud-production-d10-03-11
/home/setevoy/.ssh/setevoy-do-nextcloud-production-d10-03-11: PEM RSA private key

Запускаем тесты повторно — Telegraf выведет собираемые и игнорируемые метрики и вообще свою конфигурацию:

docker run --rm -v $(pwd):/var/loadtest -v /home/setevoy/.ssh/setevoy-do-nextcloud-production-d10-03-11:/root/.ssh/id_rsa -it direvius/yandex-tank
...
16:36:38 [INFO] Detected monitoring configuration: telegraf
16:36:38 [INFO] Preparing test...
16:36:38 [INFO] Telegraf Result config {'username': 'root', 'comment': '', 'telegraf': '/usr/bin/telegraf', 'python': '/usr/bin/env python2', 'host_config': {'Kernel': {'fielddrop': '["boot_time"]', 'name': '[inputs.kernel]'}, 'Netstat': {'name': '[inputs.netstat]'}, 'System': {'fielddrop': '["n_users", "n_cpus", "uptime*"]', 'name': '[inputs.system]'}, 'Memory': {'fielddrop': '["active", "inactive", "total", "used_per*", "avail*"]', 'name': '[inputs.mem]'}, 'Net': {'interfaces': '["eth0","eth1","eth2","eth3","eth4","eth5"]', 'fielddrop': '["icmp*", "ip*", "udplite*", "tcp*", "udp*", "drop*", "err*"]', 'name': '[inputs.net]'}, 'Disk': {'name': '[inputs.diskio]', 'devices': '["vda0","sda0","vda1","sda1","vda2","sda2","vda3","sda3","vda4","sda4","vda5","sda5"]'}, 'CPU': {'fielddrop': '["time_*", "usage_guest_nice"]', 'name': '[inputs.cpu]', 'percpu': 'false'}}, 'startup': [], 'host': 'rtfm.co.ua', 'telegrafraw': [], 'shutdown': [], 'port': 22, 'interval': '1', 'custom': [], 'source': []}
16:36:38 [INFO] Installing monitoring agent at root@rtfm.co.ua...
16:36:38 [INFO] Creating temp dir on rtfm.co.ua
16:36:38 [INFO] Execute on rtfm.co.ua: /usr/bin/env python2 -c "import tempfile; print tempfile.mkdtemp();"
...

После чего запустит нагрузочное, а в правой панели будет выведить статистику ресурсов сервера:

И работа агента на тестируемом сервере:

root@rtfm-do-production-d10:~# ps aux | grep tele
root      4580  0.5  0.4 309992  9436 pts/1    Ssl+ 15:38   0:00 python2 /tmp/tmpZez6yJ/agent.py --telegraf /tmp/telegraf --host rtfm.co.ua
root      4582  7.1  1.5 851256 31896 ?        Ssl  15:38   0:01 /tmp/telegraf -config /tmp/tmpZez6yJ/agent.cfg

Autostop

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

Например, можно настроить остановку тестирования, если количество 5хх ошибок будет больше 10%, или время ответа превысит некое пороговое значение.

Добавляем:

...
autostop:
  autostop:
    - http(2xx,100%,1s)

Тут для примера — остановить выполнение, если в течении 1 секунды 100% ответов будут с кодом 2хх.

Запускаем, и:

docker run --rm -v $(pwd):/var/loadtest -v /home/setevoy/.ssh/setevoy-do-nextcloud-production-d10-03-11:/root/.ssh/id_rsa -it direvius/yandex-tank
...
16:56:24 [INFO] Monitoring received first data.
16:56:24 [WARNING] Autostop criterion requested test stop: http(2xx,100%,1s)
16:56:24 [WARNING] Autostop criterion requested test stop: 2xx codes count higher than 100.0% for 1s, since 1612889780
16:56:24 [INFO] Finishing test...
16:56:24 [INFO] Stopping load generator and aggregator
...

Тест сразу остановился.

Больше примеров — в документации тут>>>.

Полность файл load.yaml получился таким:

phantom:
  address: rtfm.co.ua:443
  header_http: "1.1"
  headers:
    - "[Host: rtfm.co.ua]"
  uris:
    - /
  load_profile:
    load_type: rps
    schedule: const(1,30s)
  ssl: true
console:
  enabled: true
telegraf:
  enabled: true
  package: yandextank.plugins.Telegraf
  config: monitoring.xml
autostop:
  autostop:
    - http(2xx,100%,1s)

В целом, на этом всё.

Возможностями порадовал, можно придумывать запуск автоматических load-тестов для приложений в Kubernetes-кластере.

Ссылки по теме