Генерируем 21k запросов в секунду

Это статья о том, как мы в Cogniance делали нагрузочное тестирование. Она является отчасти продолжением статьи Димы «Держим 11k req/s», поэтому я не буду повторять информацию об архитектуре приложения, вдаваться в детали наших модулей — все это Вы можете найти там.

Единственная часть, на которой я хотел бы остановиться детальнее, прежде чем перейти к сути, — требования. Самое интересное здесь то, что через 6 месяцев после старта проекта ожидаемая нагрузка увеличилась приблизительно в 100+ раз. Требования к нагрузочному тестированию из разряда «дайте нам хоть что-то» перешли в разряд «мы хотим видеть все виды тестирования, о которых читали».

Требования при старте проекта:
— Request rate: 50 req/sec normal rate
— Request rate high: 150 req/sec peaks
— Protocol: http
— Authentication: no
— Response time : average 99% < 200ms.

Требования после 6 месяцев разработки:
— Request rate: 7000 req/sec normal rate
— Request rate high: 21000 req/sec peaks
— Protocol: https
— Authentication: 2WAY(mutual ssl)
— Response time : 99% total < 100ms.

Я не буду останавливаться на том этапе, когда требования позволяли нам хостить приложение на Димином телефоне, а сразу перейду к той части, где нам необходимо было поднапрячься и придумать, как в корне поменять нагрузочное тестирование. Для модуля, который показывает рекламу (Ad Server), клиент попросил сделать тестирование приблительно так, т.е. используя «Performance Testing Guidance for Web Applications» от Microsoft.

В самом начале нам надо было определить и описать, какие тесты мы можем провести в относительно сжатые сроки. Остановились на следующих тестах:

— Performance Testing. Benchmarking (Simple scenario, Average scenario, Complex scenario)
— Stress testing (Complex scenario)
— Scalability testing (Complex scenario)
— Soak testing (Complex scenario)
— Layer testing
— Production environment. Instance identification.

Расскажу немного деталей о каждом типе.

Performance Testing. Benchmarking. Делая так называемый «Benchmarking», мы пробуем определить:

— как ведет себя приложение в условиях нагрузки, близкой к максимальной, используя сценарии нагрузки от простого до сложного;
-сделать заключение, укладываемся мы в SLA или нет;
— собрать «эталонные» метрики;

Переходя к Stress testing, мы старались понять:
— как «чувствует» себя приложение при нагрузке более установленных лимитов;
— определить точку невозврата. Максимальное количество запросов, которое может выдержать наше приложение;
— понять, при какой нагрузке приложение чувствует себя OK;

Scalability testing. Говоря коротко — понять, насколько мы можем «скейлиться», линейно или нелинейно.

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

Во время Layer testing мы хотели выявить «узкие» места и проверить каждый модуль в отдельности.

И как итог нашего нагрузочного тестирования от нас ожидали рекомендации к производственной среде.

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

Jmeter

Начнем с самого популярного, наверное, решения — Jmeter. Официальный сайт говорит нам следюущее:

«Ability to load and performance test many different server/protocol types.»

К сожалению, даже для нашего простейшего сценария он не совсем подходил. Например, POST запрос (mutual ssl), максимально уникальный, с множеством различных параметров ~3kb, ответ ~3kb и еще несколько GET запросов, которые мы создали на основе ответа.

При таком сценарии, генерируя порядка 300 requests/sec с каждой ноды* (всего нод 5), мастер умирал в распределённом режиме через какое-то время, более того, Jmeter требовал огромного количества ресурсов, в частности, памяти, периодически падая по OOM и не производя ожидаемой нагрузки. Ещё Jmeter использует относительно устаревший протокол для общения между мастером и слейвами — RMI, из-за которого они обмениваются большим количеством данных, что, в свою очередь, плохо сказывается на производительности в распределенном режиме.
*CPU Intel® Core™ i7 CPU, 920 @ 2.67GHz, # of CPU's — 1, # of cores — 8, memory — 12 gb.

Load UI

Следующим кандидатом, который мы успешно использовали раньше для генерации не столь существенной нагрузки, был Load UI. У такого решения было много «плюшек»:

— отлично работает в распределенном режиме;
— легко писать/ранить свои скрипты;
— легко запускается в non-gui режиме;
— можно добавлять агенты «на лету»;
— красивые графики;
— и еще много другого.

Но снова — слишком большое потребление ресурсов и слишком маленькая производимая нагрузка (а именно — большое потребление памяти и всего ~300 requests/sec с каждой ноды*). Нужно так же отметить, что loadui не поддерживает больше 5 нод в распределнном режиме работы. Даже если воспользоваться платной версией.
*CPU Intel Xeon E5-2680, 2.80GHz, # of cores — 8, memory — 15 gb.

Load UI подходил нам практически всем: относительно удобный интерфейс позволял делать довольно сложные конфигурации для тестов и изменять их «на лету».

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

Еще одна «плюшка» Load UI — графики, они очень близки к тем, которые хочет в итоге получить большинство клиентов (или продакт оунеров).

Скрипты для собственных сценариев можно было относительно быстро написать на Groovy. Если же возникали сложности, Dev команда всегда могла быстро помочь в тонкостях написания.

Что же заставило нас отказаться от использования Load UI на проекте?

Ответ уже был дан выше — нагрузка слишком мала, да и количество агентов, которые можно подключить к одной мастер-ноде, также невелика — всего 5.

И самая большая проблема Load UI, которую мы, к сожалению, так и не смогли побороть — «умирающие агенты». Мы долго не могли понять, то ли это проблемы с нашим аппликейшном, или же это проблемы агентов, но приблизительно через 20 — 60 минут агенты в хаотичном порядке «отваливались» или «зависали». После перепроверки другими инструментами проблема была локализована, и это послужило дополнительным толчком к тому, чтобы отказаться от Load UI навсегда.

Велосипед

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

Tsung

Нашим спасителем стал Tsung. У этого решения тоже есть свои минусы:
— Нельзя добавлять агенты «на лету»;
— Нет возможности написать тест на java/groovy;
— Нет UI;
— Порог входа" немного выше, по сравнению с описанными выше решениями;
— Нет готовых сценариев.

Но при этом он просто делает свою работу, и справляется с этим на отлично:
— Не требует большого количества ресурсов для генерации нагрузки при сложных сценариях;
— Может сгенерировать просто огромную нагрузку (~11k requests/sec с одной ноды*);
*CPU Intel Xeon E5-2680, 2.80GHz, # of cores — 8, memory — 15 gb.

Создатели описывают цель Tsung'a следующим образом:

«The purpose of Tsung is to simulate users in order to test the scalability and performance of IP based client/server applications. You can use it to do load and stress testing of your servers. Many protocols have been implemented and tested, and it can be easily extended.»

Здесь я попробую немного детальнее остановиться на некоторых ньюансах.

UI Tsung'a выглядит приблизительно так:

Все тесты в Tsung — xml, и выглядят приблизительно так:

<http url="/adserver/ad?uid=200_request_%%_rnduid%%&type=TTTT&cellid=%%_rndcell%%&lat=%%_lat%%&lon=%%_lon%%" version="1.1" method="POST" contents="{"app”:NMN","appver":"2345","channels":[],"blocked":["%%_channel%%"],"device":{"device":"9910","time":%%_time%%,"platform”:"nokia","sd":2,"sw":360,"sh":240, "os":"%%_os%%","mf":"bla"}, "demo":[%%_male%%,"carrier/%%_carrier%%"], "tastes":[%%_taste%%]}">
                   
         <http_header name="Accept" value="text/json"/>
                            <http_header name="Content-type" value="text/json;charset=UTF-8"/>
                            <http_header name="Accept-Charset" value="UTF-8"/>
                            <http_header name="X-Forwarded-For" value="1.1.1.1"/>
                            <http_header name="Accept-Language" value="%%_language%%"/>
                            <http_header name="User-Agent" value="Mozilla/5.0 (Nokia; U; Nokia 3310; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0 Mobile Safari/534.11+"/>
                            <http_header name="Connection" value="keep-alive"/>
                            <http_header name="Cache-Control" value="no-cache"/>
                            <http_header name="Accept-Encoding" value="gzip,deflate"/>

Тем не менее, разобравшись, мы поняли, что не все так страшно, как казалось в начале.

Предположим, что мы уже написали какой-то тест и хотим его запустить при помощи Tsung.

Сделать это просто:

$cd /home/ubuntu/.tsung
$tsung -f script.xml -l /var/www/ start
-l path to logs and results

Узнать текущую генерируемую нагрузку:

$tsung status

Ожидаем увидеть что-то похожее на:

Tsung is running [OK]
Current request rate:    7727.28 req/sec
Current users:           44
Current connected users*: 45
Current phase:           1

*Current connected users: amount of users generating load

Детальные результаты нагрузки (работает только если включить детальное логирование):

$cd /var/www/20140506-1628
$sudo perl /usr/lib/tsung/bin/tsung_percentile.pl --percentiles 99

И как результат мы должны получить:

Read : tsung-fullstats.log
Read : 21245 values for sample,connect
Percentile 99 : 51.39892578125
Read : 3342222 values for sample,request
Percentile 99 : 13284.6879882812
Read : 1764201 values for sample,page
Percentile 99 : 20497.458984375

Tsung также позволит нам сгенерировать графики:

Они не настолько красивы и информативны, как у Load UI, и, скорее всего, их надо будет еще «обработать напильником», прежде чем отдать клиенту или продакт оунеру:

$sudo perl /usr/lib/tsung/bin/tsung_stats.pl --dygraph

Нюансы тестирования с Tsung:

— Если вы хотите, чтобы master node участвовал в нагрузке, ему нужен будет беспарольный ssh доступ на себя, помимо беспарольного ssh на все агенты.
— Закончились локальные порты (детальнее):

echo 5 > /proc/sys/net/ipv4/tcp_fin_timeout
echo 15000 65000 > /proc/sys/net/ipv4/ip_local_port_range

Итог

При приблизительно* одинаковых условиях мы получили следующую нагрузку при помощи вышеописанных средств:
*Незначительные отличия в инстансах и мелкие изменения в теле тестов

JMETER ~ 300 requests/second per node. Total nodes 5. Total load ~ 1,5k req/sec.
LOAD UI ~ 300 requests/second.Total nodes 5. Total load ~ 1,5k req/sec.
TSUNG — 11k requests/second. Total nodes 2. Total load ~ 21k req/sec.
CUSTOM — 1k headaches/second. Total headache.

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

Самому нетребовательному, думаю, будет достаточно графиков, которые вам сгенерирует Tsung. Но так или иначе, чтобы понять, насколько хорошо (или плохо) перформит ваш апликейшн, следующие метрики могут быть полезны:

  • Test resume. I.e.:
    • Time for 99 % of connections, ms
    • Time for 99 % of ad requests, ms
    • Time for 99 % of ad event, ms
  • Test Specification. I.e.:
    • Amount of entities in the system
    • % of served requests
    • % of non-matched
  • Requests stats. I.e.:
    • tomcat localhost_access.log
    • Instance specification. I.e.:
    • Amazon c3.2xlarge, Redis: Amazon ElastiCache m2.xlarge.
  • Result metrics. I.e.:
    • Stats from agent:
    • Name
    • highest 10sec mean
    • lowest 10sec mean
    • Highest Rate
    • Mean
    • Count
    • Common number of requests/ concurrent users from Agent
  • Graphs
  • Conclusion

Какие выводы мы успели сделать во время тестирования:

  • Новое соединение — это очень $$$. Пример:
    • Open/close connection ~ 70 ms;
    • Serve request within open connection ~ 12 ms;
  • RTFM. Без комментариев;
  • Разбивайте систему на части. Иногда сложно «угадать», где проблемы, и можно потратить на это много времени;
  • Тестируйте любой, даже, казалось бы, самый «хорошо описанный в интернете» солюшн. Это позволит вам не переписывать систему потом;
  • 21k req/sec — это далеко не предел.

Я и ребята попробуем ответить на Ваши вопросы, если такие будут.

Все про українське ІТ в телеграмі — підписуйтеся на канал DOU

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn

Схожі статті




83 коментарі

Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.

21К RPS это мало, банальный golang с низкоуровневыми SIMD оптимизациями и epoll’ом может такое обработать. Сразу видно что вы не профилируете существующие решения под нагрузкой: определять пропускную способность и общую стабильность под нагрузкой — это одно, а знать где есть бутылочные горлышки — совсем другое.

До 100К rps лучше использовать яндексовский фантом github.com/...tom/blob/master/README.ru в танке github.com/yandex/yandex-tank Если нужно более 100К rps — тогда уж лучше сразу писать нагрузочные тесты под dpdk с его dts’ом dpdk.org/doc/dts/gsg, там уже и по 2-3миллиона RPS можно выжать без особой нагрузки на процессоры.

Разве что китайские однодолларовые.

Недавно работал с Tsung’ом и хочу сказать что данный тул все-таки очень крут не смотря на то что были проблемы с разворачиванием Tsung cluster на Amazon. Но я не смог на одной машине Tsung’a получить больше 10к concurrent users && 10k mps. Тест заключался в следующем: к серверу коннектятся > 10k users и каждый начинает раз в секунду слать месседжи примерно по 160 Byte. в итоге я получил примерно ваши результаты. Tsung не смог отдавать больше 10к mps от 50k users. Машины использовались разные, был даже 36-ти ядерный монстр с 10ГБит каналом. Получалось ли у вас поднять месседж рейт? Вы правда считаете что 10к mps в современном мире это серьезная нагрузка?

Получалось ли у вас поднять месседж рейт?
Насколько я понял из Вашего описания, у нас был немного другой сценарий генерации нагрузки, мы не держали открытыми 10k соединений. Наш сценарий предполагал поддержание небольшого количества соединений. Нагрузку, существенно большую, чем описано в статье, мы не делали в виду отсутствия необходимости и времени.
Вы правда считаете что 10к mps в современном мире это серьезная нагрузка?
Все зависит от нужд и целей конкретного проекта, сценария нагрузки и возможностей. Если абстрагироваться от этого, то нагрузка не кажется большой.

А неужели не хотелось найти предел сервера?

«Предел сервера» для нашего сценария мы нашли :)

160 Byte
Речь о шттп? или tcp сокетах? слишком уж маленькие месседжи для шттп.

Речь о WebSoсket.
Еще хочу добавить что с одной машины получилось открыть 100к коннекшнов, дальше начиналось безумие. Так же проблема с месседж рейтом была локализирована и это точно tsung потому как Play Server тянул 50к открытых соккетов и 50 к месседжей в секунду.

дальше начиналось безумие
А грязные подробности =)?

260-270к и 20 тысяч коннекшнов отлетает. и.т.д. до нуля

36ти ядерного монстра для 10GbE канала явно многовато, можно и в 4 логических ядра обработать, в зависимости от задачи. В таких условиях принято использовать DPDK — там драйвера выгружаются в userspace и обращения к PCIe тоже выполняются прямо с userspace’a, для этого используется банальное IOMMU и DMA ремаппинг. Правда сейчас ремапит только по схеме «один к одному» без всяких scatter-gather ништяков, и в целом поддержка VFIO/IOMMU плюшек не полная.

p.s. пишу статью o том как прикручивать DPDK к Netty, и о последующих 50ти-кратных приростах производительности.

Получилось протестировать с 100к коннекшнами на машину. Конфигурация была след. 16-ти ядерные slaves и 32-х ядерный мастер. Всего 10 слейвов с протюнингованным линуксом (конфигурация кол-ва открытых файлов, распределение памяти для виртуальных коннекшнов) давали нагрузку в 1 млн. открытых коннекшнов и что-то около 600 тысяч сообщений в секунду (в среднем по 60к с машины).
Итог: Тсунг — хороший инструмент, единственное была проблема с мониторингом этого добра, потому как графики у Tsung’a ну совсем не айс.

Я не говорю что tsung это плохо, я говорю что он не подходит для поставленной задачи: было использовано очень много лишнего железа с ужасным оверхедом.

tsung будет гораздо менее производителен чем решения на основе dpdk, хотя бы потому что tsung — это erlang, со стандартным поллером на epol(), а в dpdk всё прямо в сетевуху пишется с пользовательского процесса через DMA, без задействования процессора и лишних копирований буферов. По этому сравнивать tsung и любой dpdk pktgen совсем некорректно.

Для примера можно глянуть адски устаревший github.com/Pktgen/Pktgen-DPDK или же www.seastar-project.org c бэнчмарками в шесть миллионов конкурентных HTTP/WSock соединений, на двух машинах в 28 ядер и 4ёх 10GbE Intel xl710 интерфейсах, хотя, имхо, могли взять и 40GbE на xl710.

В dpdk 2.2 ситуация на много веселее.

Правда сейчас ремапит только по схеме «один к одному» без всяких scatter-gather ништяков
Имеется ввиду, что в текущей имплементации драйвер не поддерживает возможность сетевой карты передавать данные на фрагментированную физическую память? Тобишь для устройства выделяется лишь один буфер в RAM?
пишу статью o том как прикручивать DPDK к Netty, и о последующих 50ти-кратных приростах производительности
Ради интереса спрошу, результатом статьи будет работающая библиотека на базе DPDK/Netty или только описание того, как скрестить DPDK/Netty для профита?
+ Ну и собственно где можно будет почитать статью? :)

Есть замечательный тул для нагрузочного тестирования — gatling.io
Под капотом scala + Akka. Особенность в том, что создает большое количество реквестов без большой нагрузки по ресурсам клиента. Рекомендую включить в ваш обзор.

После прочтения документации у меня появились небольшие вопросики:

  1. Распределенное тестирование в Tsung осуществляется только путем указания виртуальных IP, по которым уже будут запускаться client инстансы (для каждого client’а — отдельный Erlang VM)? Тоесть распределенное тестирование мы можем выполнять только в пределах одной физической машины?
  2. Касательно статистики, верно ли, как я понимаю, что статистика со всех client инстансов отправляется на controller, который уже по завершению своей работы генерирует отчет?

Ну и относительно Вашего решения мне также интересно:

  1. Как долго у Вас выполнялся нагрузочный тест и могли бы Вы пожалуйста показать summary report, мне кажется, что с него проще начать изучать graphical report? Дело в том, что я не уверена что графики у Вас правильно сгенерились по статистики, потому как они похожи один в один с теми, которые нарисованы в официальной документации по ссылке graphical-overview
  2. Какой тип монитора Вы использовали для сбора статистики с сервера? Рассматривали ли Вы разные варианты мониторов, и если да, то на сколько выбор монитора влияет на тест по Вашим наблюдениям, если влияет вообще?

Заранее благодарна за ответ.

Распределенное тестирование в Tsung осуществляется только путем указания виртуальных IP, по которым уже будут запускаться client инстансы (для каждого client’а — отдельный Erlang VM)? То есть распределенное тестирование мы можем выполнять только в пределах одной физической машины?

Распределенная нагрузка с помощью Tsung осуществляется с нескольких физических машин. Для запуска Tsung в распределенном режиме нужно выполнить несколько условий:
1. На каждой Slave node установить Еrlang и Tsung той же версии что и на Master node
2. Обеспечить беспарольный ssh доступ с Master node на каждую Slave node.
3.Как было написано в статье

Если вы хотите, чтобы master node участвовал в нагрузке, ему нужен будет беспарольный ssh доступ на себя, помимо беспарольного ssh на все агенты.
4. Описать все nodes в xml конфигурации

<clients>
<client host="louxor" weight="1″ maxusers="800"/>
<client host="memphis" weight="3″ maxusers="600″ cpu="2"/>
</clients>

Касательно статистики, верно ли, как я понимаю, что статистика со всех client инстансов отправляется на controller, который уже по завершению своей работы генерирует отчет?

Master node собирает метрики со Slave node каждые 10 секунд. Вы можете генерировать html репорт каждые 10 секунд и тем самым получать относительно динамический репопртинг.
Я предпочитаю устанавливать на Master node Apache HTTP Server и пересылать репорты в корневую папку сервера и запускать генерацию репортов в цикле. Получаем просмотр новых метрик на обновлении страницы браузера.

> tsung -f conf.xml -l /var/www/ start
Переходим в папку с логами текущего запуска и
> while true; do perl /usr/lib/tsung/bin/tsung_stats.pl —dygraph; sleep 10; done

Обратите внимание что perl /usr/lib/tsung/bin/tsung_stats.pl с ключиком —dygraph генерирует репорт с интерактивными графиками на основе javascript.

Какой тип монитора Вы использовали для сбора статистики с сервера? Рассматривали ли Вы разные варианты мониторов, и если да, то на сколько выбор монитора влияет на тест по Вашим наблюдениям, если влияет вообще?
Отказались от Tsung мониторинга, чтобы избежать негативного влияния на производительность нагружаемой системы. Для мониторинга использовались встроенное в нашу систему решение.
Для мониторинга использовались встроенное в нашу систему решение

Приоткрыть карты можете :) ?

Не JMX ли случайно :) ?

Клёвая статья. Про Tsung ранее не слышал — ненагугливался.

Когда есть ссылка в статье и название фреймворка — гуглится. Не гулился раньше по performance testing

Спасибо, статья интересная. Есть практический вопрос:

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

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

Спасибо.

Во время тестов невозможно было понять, где проблема — на стороне приложения или же на стороне генератора нагрузки.
Я не совсем корректно выразился здесь. Под «невозможно» имеется в виду требовалось относительно много времени чтобы понять где на самом деле проблема.
Исходный код был.
Оценивали, копаясь в коде и параллельно сравнивая с результатами других решений. По большей части клиент сам пользовался этим решением, для того чтобы сгенерировать нагрузку параллельно с нами. Поддерживать отдельный «мини» проект для генерации нагрузки оказалось немного нецелесообразным.

Да, всё правильно вы сделали. Мы, в своё время, разработали свой инструмент и набор подходов. Интересно было прочесть ваш опыт и средства, которые вы использовали. Мы тоже, кстати, лет 5 назад склонялись к Erlang как к языку реализации.
К сожалению, мне пока не удалось применить свой опыт нагрузочного тестирования на другом проекте, не считая мелочёвки. С функциональными тестированием проще — до нагрузочного не все проекты доживают. Вам повезло :)

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

Ну ведь результаты тестов могут нам сказать об этом, верно?

JMETER ~ 300 requests/second per node. Total nodes 5. Total load ~ 1,5k req/sec.
LOAD UI ~ 300 requests/second.Total nodes 5. Total load ~ 1,5k req/sec.
TSUNG — 11k requests/second. Total nodes 2. Total load ~ 21k req/sec.
CUSTOM — 1k headaches/second. Total headache.

Всё дело в том, как спроектирован тест. Если достаточно просто устанавливать и разрывать соединения, не важно как события распределены во времени (это делает Linux по своим внутренним алгоритмам и далеко не равномерно), то всё ok. Но если в будующем тесты и требования могут усложняться, лучше инвестировать в доморощенный инструмент, потому как в этом случае больше ценится понимание процесса.

Я уже писал о своём опыте. Реально нагрузочное, стресс и realtime тестирование — очень редко используемая технология для небольших проектов. Потому разумно брать готовые проверенные средства. Хотя я бы всё равно писал своё — мне интересно :)

Я уже писал о своём опыте.
Скиньте пожалуйста ссылочку, Сережа, любопытно почитать :)

Хм. Мы тестировали системы интернет рекламы, в том числе, рекламу распространяемую на facebook. Были заказы на тестирование как сервис, потому продукт не сделали, это ведь дополнительные затраты на раскрутку, можно сказать — инвестиции.
Если по поводу того, что я написал под Linux — то это отдельная тема. Для тестирования некоторых вещей Linux как система, на которой запускаются тесты и производится realtime анализ действительно не подойдёт в силу того, что TCP/IP уровень работает как городская почта — в основном держит пакеты на складе, а не доставляет. Это как вы бы попытались увидеть молекулу в световой микроскоп — есть предел временного разрешения самого ядра.
Года два назад мы прекратили этим заниматься просто потому, что те вещи, которые мы тестировали были написаны таким образом, что проблема, как правило, была видна и без тестов и тратить время стало не интересно. Потому перешли к написанию своих систем.
Если что-то интересует более конкретной — пишите в личку. Я тут бываю в основном, когда долгий тест отрабатывает, когда надо убить пару минут :)

никогда не думал что создние нагрузки в 21k/sec может быть челенджем тянущим на статью.

так может теперь вы напишете как вы собственно держите 21k req/sec? это будет существенно интересней

Это уже было dou.ua/...cles/11k-req-s
Наше приложение хорошо скейлится :)

никогда не думал что создние нагрузки в 21k/sec может быть челенджем тянущим на статью.
А зря, вот еще статья от Яндекса на эту тему — habrahabr.ru/...ex/blog/202020

Спасибо за статью. Подскажите, а чем вам не подошел Яндекс.Танк? Или его даже не рассматривали?

Спасибо за еще одну техническую статью на DOU :)

На будущее, посмотрите также на gatling.io

Возможно я не совсем понял ваш вопрос, однако отвечу так как понял :)
gatling.io/...l?highlight=ssl

Красаучеги =)
Респект!

Сами тесты запускали откуда, из своих ноутов, или из AWS, например?

В какой-то момент показалось, что вот она, статья, которой не хватало когда занимался нагрузочным тестированием... показалось. Яндекс таким макаром свой браузер написал.
Вопросы:
Что использовали при написании своего велосипеда и почему он так и не поехал?
Какая ширина канала у ноды? Скорее всего 1 Гб/с, так как 11к запросов-ответов по 3к каждый — необходимо минимум 11 * 6 * 10^6 * 8, т.е. 528 мб/с. Если так, то подтянуть есть еще куда, хотя tsung очень молодец. Что стало ограничителем?
Первое проводимое тестирование нагрузки должно быть тестирование максимального количества подключаемых пользователей емнип(сколько максимум, а за секунду?). Проводили ли такое и какая корреляция между количеством коннектов и генерируемых запросов?

В какой-то момент показалось, что вот она, статья, которой не хватало когда занимался нагрузочным тестированием... показалось. Яндекс таким макаром свой браузер написал.
Я не совсем понял причем здесь Яндекс. Чего Вам не хватило в статье?
Что использовали при написании своего велосипеда и почему он так и не поехал?
Велосипед был заказчика. Они использовали Java. Слишком «дорого» было его дебажить. У проекта были определенные сроки, которые мы не могли затягивать.
Какая ширина канала у ноды? Скорее всего 1 Гб/с, так как 11к запросов-ответов по 3к каждый — необходимо минимум 11 * 6 * 10^6 * 8, т.е. 528 мб/с. Если так, то подтянуть есть еще куда, хотя tsung очень молодец. Что стало ограничителем?
Про канал — верно. Если мне не изменяет память после того как канал стал 1 Гб/с уперлись в CPU. Для каждого запроса нам надо генерировать много «случайных» значений. Уточню немного, мы не ставили перед собой цель сгенерировать максимум запросов с одной машины.
Первое проводимое тестирование нагрузки должно быть тестирование максимального количества подключаемых пользователей емнип(сколько максимум, а за секунду?).
У нас немного другой сценарий. Такой кейс нам проверять не надо было.

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

Чего Вам не хватило в статье?
После прочтения заголовка и слегка пафосного интро — описания написанного вами фреймворка способного выдать 21к запросов с одной ноды. Оказалось, нода не одна, да и решение чужое. Дальше — вы по всей видимости не смогли утилизировать целиком bottleneck нагрузочного сервера — сеть, уперевшись в CPU. 8×2.8 ГГц — это 22.4 миллиарда(!) операций в секунду. Конечно, использование даже простого RNG типа n = (a * b + C) mod range [+ min] съест много за счет прожорливого mod, но это можно было оптимизировать задавая по возможности диапазоны через 2^(n-1) получая шустрый n = (a * b + C) & range [+ min]. В крайнем случае сделать pre-generated наборы случайных чисел, чтобы не напрягать CPU во время тестирования. Потратить немного времени на оптимизацию пакетов, они ж скорее всего plain text, чтобы уменьшить нагрузку сети. Там глядишь и получили бы заветные 21к. Но...
Уточню немного, мы не ставили перед собой цель сгенерировать максимум запросов с одной машины.
Where is challenge? Where is achievement?

Давайте попробуем разобрать Ваш фибдек по порядку.

После прочтения заголовка и слегка пафосного интро — описания написанного вами фреймворка способного выдать 21к запросов с одной ноды. Оказалось, нода не одна, да и решение чужое.
Покажите где шла речь про одну ноду и «свое решение»? Речь шла о том, что необходимо срочно покрыть «новые» требования заказчика, и что из этого получилось.
Дальше — вы по всей видимости не смогли утилизировать целиком bottleneck нагрузочного сервера — сеть, уперевшись в CPU. 8×2.8 ГГц — это 22.4 миллиарда(!) операций в секунду. Конечно, использование даже простого RNG типа n = (a * b + C) mod range [+ min] съест много за счет прожорливого mod, но это можно было оптимизировать задавая по возможности диапазоны через 2^(n-1) получая шустрый n = (a * b + C) & range [+ min]. В крайнем случае сделать pre-generated наборы случайных чисел, чтобы не напрягать CPU во время тестирования.
Я не спорю, что место для оптимизаций всегда есть. Когда у нас будет время, которое мы можем потратить на оптимизацию, мы обязательно попробуем. Тем временем, если у Вас времени немного больше, Вы можете помочь с оптимизацией open source проэкту — github.com/...rocessone/tsung
Там глядишь и получили бы заветные 21к. Но...
Исходя из Вашей логики, если бы требование стояло «сгенерировать/держать 150k в секунду», мы просто обязаны были бы сделать это используя одну ноду? :)
Where is challenge? Where is achievement?
Здесь мы не последовали принципу «хто вище б’є, той краще грає», но несмотря на столь внезапные изменения в требованиях (challenge), нам все же удалось заделиверить проект в срок и уложиться в бюджет (achievement).

Надесь, что статья кому-то просто упростит жизнь, и поможет избежать «судорожного» поиска решений при похожих требованиях.

Покажите где шла речь про одну ноду и «свое решение»?
У меня создалось такое впечатление от заголовка и интро. Это были воодушевляющие эмоции, а затем разочарование: эх... а я то думал, пацаны сейчас расскажут. Если у вас случались подобные ситации, то поймете мой негатив. Оставим же эмоции в стороне.
Что касается требований и достижений: мы мыслим немного разными категориями. Будь я вашим заказчиком, то сформулировал бы требования так: одна нода должна выдавать бесконечно много запросов в секунду. Вы бы сказали, что я болен, а я бы дал вам срок, деньги, команду «а вы постарайтесь!», и стал бы подталкивать на всё лучший результат. Откуда эта болезнь? От немцев, делающих лучшие в мире автомобили. Почему я вам это рассказываю? Хочу чтобы вы тоже заразились и делали лучший в мире %product_name% и заражали других.
Скорее всего 1 Гб/с, так как 11к запросов-ответов по 3к каждый
Объясните пожалуйста, от куда появилось магическое число 3к?
11 * 6 * 10^6 * 8
Расшифруйте пожалуйста magic numbers из Вашего вычисления

на сколько я понимаю, про размер запроса вот здесь: "

К сожалению, даже для нашего простейшего сценария он не совсем подходил. Например, POST запрос (mutual ssl), максимально уникальный, с множеством различных параметров ~3kb, ответ ~3kb и еще несколько GET запросов, которые мы создали на основе ответа.
"

количество запросов 11000, запрос+ответ = 6 кбайт = 6000 байт = 6000*8 = 48000 бит, 48000 бит*11000 = 528 млн. бит, т.е. 528 Мбит
как-то так?

Range портов можно устанавливать прям в конфиге tsung’a с помощью опции ports_range. tsung будет принудительно биндить их на локальный сокет.
Так же можно использовать IP aliasing и попросить tsung просканить и использовать доступные виртуальные интерфейсы.
Теоретически, может получиться создать более 60к соединений с одной клиентской машины, но я не пробовал.

Range портов можно устанавливать прям в конфиге tsung’a с помощью опции ports_range. tsung будет принудительно биндить их на локальный сокет.
Так и делали потом. Спасибо.

очень отлично, есть только неожиданный нюанс — поскольку dou в списке экстремистских сайтов в РФии, можно где-то поиметь статью еще?

спасибо, я чето сам не допер )

Также набор более универсальных решений: rublacklist.net/bypass

Спасибо, ребята, отличная работа и отличная статья!

Почему не использовались какие то сервисы? Например www.blitz.io или loader.io (последний мы разрабатываем и 10k он позволяет тестировать без траты денег)

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

тоесть вы проводили тест на тех же нодах, что и работал проект?

Не совсем. Ноды находились в той же сети.

Так в этих сервисах можно указать зону тестирования (тоесть если инстансы на AWS, Rackspace, DigitalOcean — то тестирующие демоны будут в этих сетях)

Не успел детально изучить предложения этих сервисов, но пока не нашел у них упоминания про поддержку mutual ssl.

Так в этих сервисах можно указать зону тестирования (тоесть если инстансы на AWS, Rackspace, DigitalOcean — то тестирующие демоны будут в этих сетях)

Согласно FAQ loader.io, это не совсем так.

What testing locations are available?
Currently all tests are run from Amazon’s US-east datacenter. Multi-location testing is currently in private beta, and we are working to make testing locations around the world available to all Pro users.
Не успел детально изучить предложения этих сервисов, но пока не нашел у них упоминания про поддержку mutual ssl.
В loader.io точно нет. Про остальные — не в курсе.
Согласно FAQ loader.io, это не совсем так.
Значит не обновили FAQ. Мультирегионы и провайдеры уже давно крутятся на продакшене (хотя за эту фичу придется платить).

кстати, вот зашел пощупать loader.io, при ране теста словил 500-ку.


We’re sorry, but something went wrong!
We are most likely aware of the problem and already on it.
Come back in a few minutes.

Пичалька. Давно это было? А то вдруг команда уже пофиксила.

А вы не пробовали Яндекс Танк для ваших целей?
Яндекс говорит что генерит до 100к запросов и есть неплохие решения для построения графиков и т. д.

А вы не пробовали Яндекс Танк для ваших целей?
На этапе «прототипа» он перформил хуже Tsung’a. Возможно до конца не разобрались, но дальше оставили Tsung.
Яндекс говорит что генерит до 100к запросов и есть неплохие решения для построения графиков и т. д.
Количество запросов которое можно сделать при помощи того или иного инструмента сильно зависит от требований к самим запросам.

Alexey Vasiliev ниже написал про 50-60 к, а вы добились всего 21к или я чего-то не понимаю?

Могу я ответить. Любое тестирование при повышении количества клиентов ведет к тому, что вы начинаете мерять не свой ресурс, а производительность тестируемого оборудования (tsung, ab, прочее). Ведь с увилечение количества клиентов с тестирующего демона, он начинает упиратся в CPU (частая проблема), память (реже, но зависит от утилиты), сеть (одна из основных проблем) и реализацию логики тестирования (акторы, «зеленые треды», прочее). Тоесть с увиличением набора клиентов у Вас может начинаться проседание в тестах, потому что нода, на которой ведется тестирования не справляется с таким размером теста. 50-60k — это идеальный предел, но до даже с тюнингом такое тяжело достигнуть.

Alexey Vasiliev ниже написал про 50-60 к, а вы добились всего 21к или я чего-то не понимаю?
Мы добились ~11k, с одного инстанса. Чем «выше» требования к запросу, тем меньше запросов вам удастся сгенерировать с одного инстанса, по причинам которые Alexey Vasiliev описал ниже. Простых GET запросов сделать можно было в разы больше, с того же инстанса.

На одном инстансе 50-60К это предел (и для этих целей уже придется не мало ядро тюнить)

Рассматривали ли wrk как вариант?
github.com/wg/wrk

Нет, WRK тогда не попал в наше поле зрения.

Успешно использую wrk/wrk2 + Lua скрипты, классная штука.

После перепроверки другими инструментами проблема была локализована
так в чому ж профіт від Tsung?

Попробую ответить цитатой из статьи:

...он просто делает свою работу, и справляется с этим на отлично:
— Не требует большого количества ресурсов для генерации нагрузки при сложных сценариях;
— Может сгенерировать просто огромную нагрузку (~11k requests/sec с одной ноды*);
Другие средства не позволяли нам сгенерировать необходимую нагрузку учитывая наши требования.

гм. так як він допоміг локалізувати проблему?

Локализировать проблему помогли просто другие «генераторы нагрузки», в том числе и Tsung, которые дали понять, что проблема скорее в Load UI, чем в нашем апликейшне.

Підписатись на коментарі