Нагрузочное тестирование http-сервера (nginx), 205k+ RPS

k0st1an
5 min readJan 21, 2019

--

В этой заметке речь пойдет о yandex-tank. Стоит помнить о ab, wrk. Но они для простых задачь. Танк же поддерживает различные сценарии. Можно использовать танк для обрестрела нескольких целей. И что важно у танка есть различные модулю, что позволит легко автоматизировать процесс.

Для обстрела цели нужна сама цель и танк:

  • цель — 2 x Intel Xeon E5–2630 v3, 2 x 16GB DDR4, 10Gbps
  • танк — 2 x Intel Xeon E5–2630 v4, 4 x 16GB DDR4, 2 x 2 TB SATA 3.5", 10Gbps

Диски указаны не просто так — танк заранее заготавливает патроны и после серии обстрелов место на диске будет съедено.

В этой заметке не будет детально описано как настроить танк чтоб что-то сделать. Так как тема эта обширна. Так же не будет описания настройки Nginx. Но ответы можно поискать в ссылках ниже.

Некторые параметры интересны для описания, так как не очевидны с ходу. Планирую попробовать различные генераторы нагрузки (пока только phantom). Ворояно по ним будут мысли…

Стоит упомянуть, что на Nginx при обстреле всегда использовался HTTPS и был всего один эндпоинт всегда возвращающий http-код 200. При тестиронвании полноценного API вопросов становится еще больше :)

Как видите условия довольны просты: надо просто достигнуть предельных RPS при тестировании, без какой либо логики в тестировании, без нагрузки и разобраться с работой yandex-tank.

ВАЖНО: создайте отдельный каталог под конфиги и именно из этого каталога будем запускать танк.

Yandex-Tank

Установка очень проста. Один из самых удобных способов запуска танка является Docker.

Пример конфига танка, load.yml:

phantom:
address: remote.host.com:443
ssl: true
load_profile:
load_type: rps
schedule: line(1000, 205000, 5m) const(205000, 5m)
ammofile: ammo.txt
instances: 2500
autostop:
autostop:
- time(50, 30s)
- net(110, 5%, 10s)
telegraf:
enabled: true
config: monitoring.xml
kill_old: false
overload:
enabled: true
job_name: POST requests
job_dsc: line(1000, 205000, 5m) const(205000, 5m) | 2.5k instances | 32 cores
token_file: token.txt

Запуск:

$ yandex-tanl -c load.yml

Модуль: phantom

Написанная на C++ пушка. Очень эффектианая. В доке к танку есть и другие орудия. Описание параметров можно посмотреть в документации. Обычно нужно менять два параметра:

  • phantom.load_profile.schedule — задаем схему обстрела, допускается указывать несколько параметров.
  • phantom.instances — количество инстанцев (тредов), которые нам нужны для обстрела цели с достижением нужного RPS.

С инстанцами все довольно сложно. Значение по-умолчанию 1k, но этого явно мало чтоб достичь 205k+ RPS (overload/154642). С большим количеством можно упереться в долгий ответ прокси, с малым количеством не достигнуть предельных RPS и упереться в полную утилизацию инстанцев, что опять же плохо. Если указать большое количество инстанцев, то очень вероятно тест завалится в самом начале. Инстанцы “ломануться” на цель и автостоп завершит тест, так как появятся ошибки 110 Connection timed out (если автостоп настроен на подобное поведение).

У меня получилось упереться в производительность сервера с которого я вел обстрел. После 200k+ RPS сервер загружен почти на 100% по CPU.

За время теста столкнулся с неадекватным поведением инстанцев неоднакратно. Например после нагрузки 60k rps количество инстанцев падает и все хорошо работает до 100k rps. При следующей стрельбе подобного поведения не наблюдалось. Бывало до конца теста оставалось две-три минуты инстанцы успешно справлялись с нагрузкаой и вдруг утилизация инстанцев 100%, тест завален. Помогает только снизить количество инстанцев. Но как это объяснить не знаю.

Нужно учитывать какой paylaod подается через танк на цель. Например POST-запрос с JSON’ом 7kB это один случай, а 1kB совсем другой. А если вообще пустой запрос — нагрузка минимальна, выдерживать надо только RPS.

Очень важный момент: для достижения предельных RPS использовать Connection: keep-alive. То есть за одно подключение передается множество запросов. Если за одно подключение делется один запрос, а после связь разрывается с сервером — это Connection: close и HTTP-сервер будет очень много времени тратить на handshaking. Количество RPS значительно снижается (overload/155001). Немного вики.

Опять же надо учитывать то, как настроен Nginx. Переменных много. Потому выбор количества инстанцев задача не тривиальная. Потому приходится проводить несколько тестов.

Еще можно поиграться schedule: можно повышать, понижать и подавать экстремальные нагрузки за один тест, тем самым позволяя проверить настройку ОС и Nginx. То есть тут попытка протестировать различные очереди, буферы и вообще выносливость сервера, если для него нагрузка действительно высокая.

Стоит отдельно обратить внимание на следующие параметры:

  • phantom.threads
  • phantom.affinity

Модуль: autostop

Модуль позволяющий остановить работу танка когда все плохо. У модуля довольно богатые возможности (о некоторых я узнал когда сел писать заметку). Чаще всего используют time, http, net.

Модуль: telegraf

Очень классная штука: позволяет мониторить удаленный сервер и позволяет не только показывать данные в консоле во время тестирования, но и отправлять на https://overload.yandex.net. Это очень удобно для последующего анализа запросов.

Работает через SSH. Обычным образом устанавливаем ключи у себя и на удаленной машине. Конфиг, monitoring.xml:

<Monitoring>
<Host address="HOST" interval="1" username="USER">
<CPU/> <Kernel/> <Net/> <System/> <Memory/> <Disk/> <Netstat /> <Nstat/>
</Host>
</Monitoring>

Следует заменить HOST и USER на свои значения.

Модуль: overload

Модуль для отправки метрик на https://overload.yandex.net для последующего анализа. Создайте файл token.txt и положите туда токен, который можно получить на этом же сайте после регистрации.

По желаюнию можно использовать параметры job_name / job_dsc чтоб потом не заполнять описание ручками на сайте.

Сервис еще в бете, но особых проблем не наблюдается.

Другие модули

Очень интереснынй модуль rcheck. Так как ресурсов танк съедает прилично, то этим модулем можно недопустить работу танка в холостую.

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

И очень важный модуль core. Настройки самого танка.

Патроны

Это то, что полетит в цель, как бы банально это не звучало. То есть возможность подготивить серию патронов и обстреливать цель, а не дергать за один тест только один URL. Для довольно сложных сценариев правильней использовать JMeter. Я же использовал Phantom.

Есть два варианта где держать патроны: в конфиге yandex-tank или в отдельном файле. Мне кажется в отдельном файле куда удобнее. Можно использовать скрипт для генерации патронов.

Пример генерации патрона для GET-запроса:

$ echo "GET||/url||case||" | ./make_ammo.py > ammo.txt

/url — какой URI опрашивать, case — тег удобно использовать для статистики. То есть можно тегировать патроны с разными задачами, а потом в консоле и интерфейсе https://overload.yandex.net/ наблюдать статистику по каждому тегу. Скорее всего это будет полезной фичей при тестировании API. Теги опциональны:

$ echo "POST||/url||||" | ./make_ammo.py > ammo.txt

В скрипт я добавил поддержку keep-alive и application/json (использовал для POST-запросов с payload) заменив на 51 сточке Connection: close\r\n на след.:

"Content-Type: application/json\r\n" + \
"Connection: keep-alive"

Content-Type не нужен если вы используете GET-запросы с keep-alive. Если нужно набить максильное значение RPS, просто измените Connection. POST/GET-запрос не имеет значение.

Конечно вы вольны добавлять любые заголовки, особенно это будет полезно при тестировании API.

Думаю эти скрипты хороший пример для написания своих хелперов для патронов.

Заключение

Сценариев использования танка множество. А отдельный сервис overload позволяет легко проводить анализ тестирования. Это супер удобно! Для простых задачь всегда можно использовать ab или wrk.

Полезные ссылки:

--

--