
Привет, Хабр! Меня зовут Иван Дюков. Последние несколько лет я занимался разработкой и оптимизацией сетевых компонентов для облачной инфраструктуры. Среди моих проектов — участие в разработке сетевого процессора для компании Google в составе российского подразделения Intel, а также оптимизация программных сетевых функций для облака Samsung в команде Samsung R&D Institute Russia. В настоящее время работаю над сетевыми сервисами для платформы Cloud.ru Evolution в R&D-команде Cloud.ru.
Основное направление моей работы — это исследования программных сетей, сетевых сервисов и их производительности. В этой статье хочу рассказать, как я искал точку отказа прокси-балансировщика. Расскажу и про метрики, и про инструменты, и как я автоматизировал измерения. Путь оказался весьма извилист, наполнен граблями и шишками, зато результат был познавательными. Статья будет интересна разработчикам сетевых сервисов, DevOps-инженерам и тестировщикам, исследующим проблемы производительности сети и сетевых сервисов.
Что такое прокси-балансировщик?
Перед тем как мы начнем подбирать метрики и инструменты, познакомимся поближе с прокси‑балансировщиком. Что это такое? Как проверить его производительность, и зачем это делать?

Прокси‑балансировщик — это программный компонент, который распределяет нагрузку между серверами, но при этом сессию с пользователем терминирует на себе и к реальным серверам подсоединяется уже от своего IP. Благодаря этому свойству он может очень сильно менять содержимое пользовательских сетевых пакетов, например, удалять SSL‑шифрование.
На мой взгляд, прокси-балансировщик — один из самых сложных сервисов для тестирования. Он модифицирует src IP и dst IP, плюс для него надо поднимать армию серверов, которые он будет балансировать. Чем больше будет этих серверов, тем лучше. И чтобы загрузить эти серверы, нужно еще большую армию пользователей с уникальными IP.
В качестве прокси балансировщика я использовал Envoy + Kubernetes + мои доработки, которые позволяют изолировать пользовательский трафик. В рамках R&D-проекта эта конструкция была собрана на виртуальном стенде и возник вопрос о том, сколько трафика она сможет обработать и сколько ей для этого нужно ядер CPU.
Чтобы ответить на эти вопросы, сначала нужно определить, какие метрики существуют и какие подойдут для нашего эксперимента. Следующий раздел будет о муках выбора между сетевыми метриками и метриками приложений.
Глаза и уши для нагрузки: какие метрики выдают узкие места
Итак, в лаборатории мы имеем Envoy-балансировщик. Какие ему нужно пройти испытания, чтобы освободиться, пока непонятно. Сколько он обработает пользователей? Сколько ядер для этого надо? И главное — когда он упадет? Эту границу надо найти самому, иначе ее найдут пользователи сервиса и им это не понравится.
Нужно было отобрать метрики из уже известных. А известно мне было про сетевые метрики и метрики приложения. Сетевые метрики приведены ниже в таблице:
Метрики |
Описание |
packet per second (pps) |
Производительность сети, измеряемая в пакетах. Более актуальная метрика для программных сетей, где трафик проходит через CPU |
bit per second (bps) |
Производительность сети в битах. Можно посчитать по формуле pps packet size 8 |
Byte per second (Bps) |
Производительность сети в Байтах. Можно посчитать по формуле pps * packet size |
latency |
Время доставки пакета до сервера |
drop rate |
Количество потерянного трафика в секунду |
Метрики для измерения L2/L3/L4 сетевых устройств: коммутаторов, маршрутизаторов, балансировщиков и stateless firewall.
Они подходят для измерения производительности как виртуальных, так и физических сетевых сущностей: сетевых карт, коммутаторов, маршрутизаторов, балансировщиков и stateless firewall’ов. В виртуальной среде весь набор этого оборудования уже реализован в ядре Linux или с помощью DPDK-библиотеки (Data Plane Development Kit). Иначе говоря, это метрики для тестирования чего-то внутри ядра Linux, DPDK приложений или физического оборудования.
В таблице представлены метрики, которые на первый взгляд могут показаться избыточными — PPS (пакеты в секунду) и bps (биты в секунду). bps можно легко получить из PPS * размер пакета, но области применения этих метрик разные. Везде, где трафик проходит через центральный процессор общего назначения, PPS будет более показательной метрикой. Дело в том, что центральный процессор тратит время на обработку заголовка пакета, а пользовательские данные идут прицепом и процессорное время на них тратится гораздо меньше. Самое сложное, что может произойти с пользовательскими данными, это memcpy и отправка на сетевую карту. Но есть много методик, которые позволяют и этого избежать, например: передача указателя на эти данные или использование общей памяти (shared memory). Особенно ярко это выражается в случае, если трафик путешествует на одно�� гипервизоре между виртуальными машинами и не видит физическую сеть. Совсем другая история с заголовком пакета. Заголовок имеет длину примерно 60 байт, но к нему применяются все те сетевые правила, которые есть в облаке, а их там мегабайты. Это правила фильтрации, маршрутизации, трансформации и так далее. И это все потребляет очень много процессорного времени и очень сильно замедляет трафик.
В таких условиях производительность системы лимитируется именно способностью CPU обрабатывать большое количество заголовков пакета, а не объемом передаваемых данных. Поэтому при тестировании программных решений PPS становится более показательной метрикой.
В дополнение к перечисленным метрикам есть еще метрики приложения.
Метрики |
Описание |
connections per second (cps) |
Показывает сколько новых пользователей сервис выдержит за секунду |
requests per second (rps) |
Количество запросов, которое способно обработать приложение, за секунду. Это более сложная метрика, которая учитывает и время прохождения пакета от клиента к сервису, и время обработки клиентского запроса, и время прохождения трафика от сервиса к клиенту |
Метрики для измерения скорости L7 сервисов (web-сервер, прокси, прокси-балансировщик, statefull firewall и так далее).
На этом уровне трафик выходит из ядра ОС и попадает в само приложение. Тут же появляются уникальные пользователи и их запросы. А выражается это в том, что каждый пользователь имеет свой открытый сокет. В прокси-балансировщике на каждый запрос пользователя создаются два сокета — один к клиенту, другой к бэкенду. При этом сам запрос запускает целую цепочку действий: обращение к файловой системе, выделение памяти, создание новых потоков выполнения. То есть запрос приводит к тому, что приложение опять начинает обращаться к операционной системе для выполнения своих задач, а любой вызов к операционной системе — это затратная операция. По сути, здесь более тяжелые операции и занимают больше времени, чем на уровне сети.
Прокси-балансировщик — это приложение, и поэтому к нему применены все метрики приложения, но также он является и сетевой функцией поэтому к нему применимы и метрики сети.
Для нашего теста балансировщика я отобрал следующие метрики:
pps;
Bps;
cps;
latency;
drops rate.
Метрика потерянных пакетов — это ключевая метрика, по которой мы будем определять, что сервис уже не справляется с нагрузкой и мы нашли точку отказа.
Метрики есть. А нам обязательно их мерить? У нас ведь есть спецификация оборудования и там мы заложили все с запасом! И перед тем, как мы перейдем к выбору инструмента для измерения, я бы хотел рассказать, что меня всегда мотивирует измерять производительность сетевых сервисов и меньше полагаться на спецификацию оборудования. Если у вас нет проблем с мотивацией, то можете смело пропустить следующий раздел и перейти сразу к разделу выбора инструмента. А сейчас давайте быстро пробежимся по инфраструктуре облака и попробуем разобраться, какие компоненты системы вносят энтропию.

Почему спецификация оборудования не спасает
Допустим, у нас есть гипервизор с 25 гигабитной сетевой картой и с центральным процессором в 3 GHz. Давайте посчитаем, сколько тактов он потратит на один пакет длиной 64 байта при условии, что такими пакетами забит весь 25‑гигабитный канал.
Для начала переводим скорость сетевой карты в гигабайты:
25 Gbps* / 8 = 3.125 GBps — скорость сетевой карты в гигабайтах.
Делим скорость карты на размер пакета:
3 125 000 000 / 64 = 48 828 125 pps — это количество пакетов в секунду надо обработать, чтобы забить наш 25 Gb канал пакетами по 64 байта.
Теперь считаем количество тактов, которые нужны для обработки одного пакета. Делим нашу частоту на количество пакетов:
3 GHz / 48 828 125 = 61 такт надо потратить на один пакет, чтобы обработать весь наш трафик.
За 61 такт мы даже в оперативную память залезть не сможем. Вот таблица со стоимостью разных операций в тактах. В реальности эти значения будут зависеть от модели центрального процессора и типа памяти, но, в целом, порядок операций всегда будет примерно одинаковый.
Задача |
Количество тактов |
send syscall, отправка буфера в сокет для отправки по сети |
1 100 |
Доступ в оперативную память |
150 |
Доступ в L3 cache |
36 |
Чтение памяти и кеша я взял из этой статьи. Она старовата, современные процессоры и системы работают побыстрей, но ненамного. Так что она поможет вам составить общее впечатление о стоимости разных операций в тактах. В статье я не нашел стоимость системного вызова по отправке в сеть, поэтому я измерил это сам. Для измерения продолжительности одного системного вызова send, я навайбкодил написал программу. Программа вызывала этот системный вызов в цикле 1 миллион раз и замеряла время всех операций. Эта операция завершилась за несколько секунд. Чтобы понять, сколько это будет в тактах, я умножил полученное время в секундах на частоту процессора и получил суммарное количество тактов, потраченное на выполнение 1 миллиона системных вызовов. И все эти такты осталось только поделить на 1 миллион, чтобы узнать, сколько было потрачено на одну операцию. Получилось 1 100 тактов.
По-моему, мы еще ничего не делали, а уже в кредит по тактам залезли. Можно попробовать остановиться, но зачем? Давайте попробуем оформить ипотеку? Пройдем по всему пути пакета в облаке. Для этого рассмотрим компоненты, которые участвуют в общении двух виртуальных машин в облаке.

Начинается все с пользовательского приложения, например, web-клиента. Он открывает сокет и посылает пакет в ядро Linux. Там пакет пролетает уровень сокетов, таблицы маршрутизации и прилетает в виртуальную сетевую карту virtio. Virtio использует общую память с гипервизором, поэтому пакет прямиков попадает на гипервизор.

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

Пробираясь сквозь openflow правила, пакет попадает в физическую сеть. Тут физические серверы с физическими сетевыми картами, коммутаторы и, если повезет, то и маршрутизатор можно встретить. Пакет попадает на коммутатор и направляется на целевой гипервизор, и потом происходит все то же, что мы описали выше, только в обратном порядке. Если открыть спецификацию коммутаторов и сетевых карт, то в них написано, на каких скоростях они работают. Если копнуть документацию глубже, то там можно найти и на каких пакетах эта скорость достигалась. Обычно железные сетевые карты и коммутаторы выдерживают свою пропускную способность на пакетах равных 64 байта. (см. отчеты о тестировании сетевых карт на сайте DPDK).
Но программный сетевой стек не имеет такой спецификации. И он точно не поместится в 61 такт. Поэтому, если сетевой сервис начинает работать значительно меньше скорости оборудования, то проблемы скорее всего в программном обеспечении, и узкие места нужно искать именно там.

Узким местом может стать любой из этих уровней, но практика показывает, что вероятность падения производительности увеличивается от железного уровня к пользовательской нагрузке.
Чтобы бороться с недостаточной производительностью центрального процессора, используются разные приемы, которые позволяют распределить нагрузку на несколько процессоров и/или сделать эти процессоры выделенными для конкретной задачи. Тема оптимизаций сетевых приложений заслуживает отдельной статьи; мы же в этой главе хотим понять, какую нагрузку выдержит наш сервис. И похоже, что понять не получится – надо мерить! А как мерить и чем мерить, мы рассмотрим дальше.
Ping не работает, netperf молчит, а трафик есть. Кто виноват и что делать?
Первым делом я захотел проверить задержку, так как это показалось простой задачей, и я планировал ее закончить за пару минут. Нужно было просто запустить ping и посмотреть результат. Для тестирования я собрал стенд с несколькими клиентами и серверами обработки.

В первой версии балансировщика мы планировали поддержку только TCP-протокола, поэтому я настроил Envoy на обработку TCP-трафика на 80 порту и приступил к экспериментам.
Зашел на клиента, запустил ping, посмотрел на результат, и прямо в этот момент понял, что ping работает через ICMP-протокол, а наш балансировщик — через TCP. Ping не подошел, нужно было подобрать альтернативу.
Пару часов поиска в сети и был найден netperf. Вот эти команды должны были замерить задержку так же, как ping, только через TCP-протокол.
netperf -H 10.127.10.10 -p 80,32080 -L 10.128.10.2 -l -1000 -t TCP_CRR -w 10ms -b 1 – на стороне клиента.
netserver -D -p 80 – на стороне сервера.
Запустил тест, посмотрел на результат — пинга нет. Идей тоже не было. Может с аргументами намудрил? Несколько раз перечитал справку по netperf. Ничего подозрительного не нашел — достал tcpdump. Снял дамп, а в дампе все хорошо. Трафик по 80 порту ходил и туда, и обратно, и все выглядело как живое. Еще раз перечитал справку на всякий случай. Опять ничего не нашел. Вернулся к дампу трафика. Методом пристального вглядывания через некоторое время заметил, что там, кроме общения по 80 порту, есть еще общение по 45325 порту. Еще раз прошелся по документации и интернетy. Безрезультатно.
Снял дамп еще раз. Опять две TCP сессии: на 80 и 41328. Балансировщик просто удалял пакеты с 41328 порта, и это было ожидаемо, так как он был настроен пропускать только 80 порт. Можно было бы настроить второй порт в балансировщике. Для этого надо было знать, какой порт открывать, а он всегда был разный. Прошло уже три часа как я пытался его запустить, а результата не было, и я решил еще раз поискать альтернативы для netperf в интернете. Поиск ничего не дал, и я решил идти с netperf до конца. Скачал исходники, построил его с отладочной информацией и запустил все это добро под gdb.

Еще пару часов отладки и была найдена причина и решение этой проблемы. Оказалось, netperf использует два порта для запуска тестов: один порт для управления и один порт для данных, при этом порт для данных выбирался случайно из диапазона портов >32K. И в результате отладки была найдена опция: -- -P 81 -O, которая обязывала запускать данные на 81 порт. В итоге у нас на балансировщике появилось два открытых порта, и оба они вели на один сервер обработки запросов.
Финальная команда запуска оказалось такой.
Команда запуска клиента:
netperf -H 10.10.10.10 -p 80,32080 -L 10.10.10.2 -l -1000
-t TCP_CRR -w 10ms -b 1 -- -P 81 -O
Команда запуска сервера:
netserver -D -p 80
После тестирования я все-таки смог найти эту опцию в официальной документации на сайте, но только один раз и случайно. И так обрадовался, что забыл в закладки добавить. Повторные поиски не дали результата. Тестирование показало, что вместо запланированных двух минут я потратил семь часов задержки были в пределах нормы.
Выбор инструмента для измерения пропускной способности
Для тестирования пропускной способности у меня на примете было несколько инструментов. Приложения для измерения производительности web-серверов меня тоже устраивали, так как они работают поверх TCP-протокола. Больше всего меня интересовали инструменты, которые смогут создать максимальное количество параллельных соединений. Для этих целей я установил все эти приложения у себя в лаборатории и проверил их основные параметры. Результат экспериментов приведен в таблице ниже.
Инструменты для измерения производительности и их характеристики.
Самую большую армию клиентов смог создать Trex. Он смог поддержать 32 тысячи соединений. Если я его просил создать больше соединений, он просто не мог увеличить трафик. Остальные приложения при увеличении параллельных соединений, в лучшем случае, выдавали сообщение: Too many open files, в худшем, просто подвешивали систему. Так что победитель тут был очевиден, им оказался Trex.
Trex: первые шаги
Trex — это инструмент разработанный компанией Сisco для генерации трафика. Он может генерировать сеть клиентов и серверов. Он поддерживает работу с DPDK-драйверами и также может работать поверх обычных сетевых устройств Linux. Мне производительности обычных Linux-устройств хватило, поэтому я его использовали в режиме без DPDK. В режиме без DPDK, он так же, как и с DPDK, монопольно захватывает интерфейс, но при этом интерфейс виден в системе. И у других приложений может появиться соблазн что‑нибудь отправить через этот интерфейс, но ничего не выйдет. У меня там был запущен FRR, и он сразу молча разорвал свои сессии с маршрутизаторами. Починил я это отказом от FRR и парой статических маршрутов на маршрутизаторе на время теста.
Trex также накладывает ограничения на топологию сети. Его особенность — это генерация новых логических сетей. И эти сети появляются внутри Trex, а интерфейсы, которые вы ему отдали автоматически, становятся логическими маршрутизаторами. А так как он генерирует и клиентскую сеть, и серверную, ему нужно два интерфейса. Каждый интерфейс будет обслуживать одну сеть. А вы наверняка еще захотите подключиться к машине по ssh, чтобы управлять всем этим добром. Поэтому виртуальная машина с Trex должна иметь три интерфейса:
интерфейс клиентской сети;
интерфейс серверной сети;
интерфейс управления.

Итого мы имеем следующие сети:
10.127.0.0/16 — клиентская сеть. Генерируется Trex.
10.128.0.0/16 — серверная сеть. Генерируется Trex.
192.168.1.0/30 и 192.168.1.4/30 — транспортные сети.
192.168.3.0/24 — сеть, где располагается наш сервис балансировки.
Чтобы эта схема заработала, я добавил маршруты на Default router до клиентской и серверной сети, и в конфигурации Trex указал маршруты по умолчанию до Default router:
/etc/trex_cfg.yaml
- version : 2 # version 2 of the configuration file
low_end : true
interfaces : ["ens9f0np0","ens3f0np0"] # если нужен только пользовательский трафик, а бэки у вас будут настоящие то просто можете второй интерфейс указать как “dummy”
port_limit : 2
port_info:
- ip : 192.168.1.2 # адрес клиентского порта на виртуальной машине
default_gw : 192.168.1.1 # адрес клиентского порта на дефолтном маршрутизаторе
- ip : 192.168.1.6 # адрес бэкэнд порта на виртуальной машине
default_gw : 192.168.1.5 # адрес бэкэнд порта на маршрутизаторе
Я провел несколько тестовых замеров. Результат мне понравился, и я решил еще проверить, как он будет работать с живыми бэкэнд-серверами.
Чтобы выключить один порт в Trex, достаточно в конфиге поставить dummy в имя порта.Я поставил вместо серверного порта dummy и поднял несколько nginx-серверов. В итоге получилась вот такая схема:
Клиентская сеть 10.127.0.0/16 осталась в Trex, а в качестве бэкэнд‑серверов я использовал nginx. Trex выполнял функцию генерации http-запросов, а ответы посылали настоящие http-сервера. У этого подхода сразу обнаружился недостаток: настоящие серверы после закрытия соединения с клиентом держат сокет в состоянии TIME_WAIT еще две минуты. И клиент с таким же src IP и src port уже не может подсоединиться. Генератор исчерпывал весь диапазон 10.127.0.0/16 и начинал генерировать эти же адреса, только уже по второму кругу. И если между первым и вторым кругом прошло меньше, чем две минуты, то появлялись потерянные пакеты.
Диагностировать это было сложно. И поначалу я даже списывал эти проблемы на недостаточную производительность балансировщика. Но потом выяснил причину и настроил nginx, чтобы он не ждал две минуты, а разрешал использовать сокеты повторно.
После того как я победили проблему TIME_WAIT с помощью флага net.ipv4.tcp_tw_reuse, я понял, что наш балансировщик может прокачать гораздо больше трафика, чем у нас есть серверов для тестирования. Поэтому я вернулся к тестированию изначальной схемы, где клиент и сервер генерируются Trex’ом.
Как измерить производительность, если ты сам ее задаешь?
Приложения для измерения производительности сети делятся на два типа: одни запускаются и сразу выдают скорость сети, другим же надо сказать, на какой скорости работать. Trex относится ко второму типу. У него для этого есть флаг -m (множитель). Как же померить скорость, если мы ее сами задаем?
Для начала я решил проверить производительность стенда без балансировщика. Для этого я собрал вот такую сетевую схему:

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

Первые несколько итераций производительность росла пропорционально множителю, а потом рост остановился. Это произошло где-то на границе 32 000. Я эту границу интерпретировал как предел стабильной производительности стенда. И для себя сделал пометку, что балансировщик не выдаст производительность больше, чем стенд. Дальнейший анализ показал, что множитель как раз и задает количество новых TCP-сессий в секунду, т. е. CPS (connection per second). Точнее он множит ваш профиль нагрузки, а у меня был профиль с одной сессией. Как написать профиль на Python и потом заставить Trex генерировать нагрузку по этому профилю я расскажу чуть позже, а сейчас вернемся к тестированию балансировщика.
Конфигурации Envoy
Стенд был готов, осталось только определить:
Сколько отдать CPU в Envoy?
Сколько экземпляров Envoy запустить?
Какие размеры пакетов использовать для теста?
Для Envoy я выбрал 4 конфигурации: 0.1, 1, 2, 4 CPU ядер. Я рассчитывал получить более сложные метрики, которые показывали производительность одного или нескольких CPU:
PPS per CPU.
Bps per CPU.
Cps per CPU.
Размеры пакетов решил проверить вот такие: 64, 256, 768, 1460. При этом все эти пакеты надо было прогнать на всех конфигурациях Envoy. В итоге получается 4х4 = 16 тестов. Хотелось еще проверить, как он горизонтально масштабируется, для этого надо было хотя бы на паре конфигураций запустить два Envoy-экземпляра. При этом надо было еще подобрать множители и найти, где это все упадет. С учетом множителей количество тестов могло легко перешагнуть за сто. Не хотелось, конечно, все это вручную запускать, и я решил автоматизировать перебор множителей. Для этого я воспользовался встроенной в Trex Python-библиотекой.
Как запустить тесты
Я написал тест (test_proxy.py), который может перебирать множители. Для этого у него есть вот такие аргументы:
top-multi — верхняя граница;
bottom-multi — нижняя граница;
step-multi — шаг.
Также я написал профиль (profile_http_proxy.py), который описывает TCP-сессию, для клиентского и серверного интерфейса. Чтобы задать IP сети, нужно воспользоваться вот этими аргументами:
client-ip-net — клиентская сеть. Этот аргумент используется для генерации IP src на клиентском порту.
lb-ip-net — сеть балансировщиков. Этот аргумент используется для генерации IP dst на клиентском порту.
backend-ip-net — серверная сеть. Этот аргумент настраивает серверный порт и обязывает его отвечать только на пакеты, которые направляются в эту сеть.
Тест и профиль нагрузки я выложил в репозиторий. Там же есть README с подробной инструкцией по запуску этих скриптов. Код и конфиги в проекте содержат подробные комментарии, поэтому я не стал дублировать эту информацию здесь. Тестовый скрипт выводит результат измерений в обычном html-формате, чтобы удобно было потом их вставить в Сonfluence. Если у вас есть Grafana, и вы хотите результаты отправлять туда, есть хорошая статья, как это сделать. Также в ней рассматривается пример, как настроить Trex с DPDK.
Как читать результаты Trex
Я начал тест с 1 000 новых пользователей в секунду и потом каждые 15 секунд увеличивал CPS на 1 000. Пропускная способность линейно росла примерно до 13 600 CPS.

При больших значениях множителя пропускная способность резко упала. При этом потерянных пакетов как бы не было, потому что мой тест должен был остановиться, если есть потери. А потери в скрипте я определял по полю rx_drop_bps в структуре статистики Trex. Я проверил всю структуру статистики и не нашел там другие поля, которые бы содержали бы «drop» в названии. То есть, по результатам тестов, потерь нет, но по графику и так понятно, что мы что-то потеряли на больших значениях CPS. И эти потери вносил наш балансировщик, так как без него таких проблем не было.
Я предположил, что rx_drop_bps показывает скорость потерь за секунду, так как тест останавливался, если на последней секунде были потери. А rx_bps показывает среднее значение пропускной способности за весь тест. По-хорошему, тут бы надо более детально разобраться.
Не измерения, а прозрение
Тесты показали не просто цифры — они раскрыли пределы нашего программного решения и помогли оценить эффективность как вертикального, так и горизонтального масштабирования. Теперь мы спокойно можем прогнозировать количество необходимых CPU ядер для заданной нагрузки. Также стала понятна граница производительности одного сервера, и мы можем добавить новый сервер в инфраструктуру прежде, чем сервис начнет отказывать в доступе нашим пользователям.
Чтобы получить этот результат, пришлось разобраться с метриками и очень внимательно проверить результаты замеров. Выяснились следующие характеристики измерительных инструментов:
Netperf использует 2 порта для запуска тестов. Порт с данными и управляющий порт. И это надо учитывать, если у вас в сети запущен firewall, балансировщик или используются группы безопасности с фильтрацией трафика.
Trex очень удобен для автоматизации тестов. Имеет Python-клиента, который можно запускать даже с удаленного сервера. Например, из CI/CD окружения, при этом сам генератор будет работать в тестовом окружении.
Скорость генерации трафика в Trex задается вручную. Поэтому просто померить производительность сервиса с одного запуска не получится. А вот если захочется посмотреть поведение сервиса под разной нагрузкой, то эта задачка для Trex.
В процессе также был разработан тест на Python, который позволил автоматически замерять производительность одной конфигурации. Этот тест также будет полезен в сервисах, которые трансформируют IP-адреса, например, NAT.
Чтобы разобраться с Trex, пришлось прочитать много материалов на Хабре. Мне так понравился этот инструмент, что я решил написать эту статью и посвятить ее нераскрытым темам и повстречавшимся подводным камням. Надеюсь, это сэкономит вам пару дней и несколько десятков нервных клеток.
А у вас бывало так, что планируете две минуты, опираясь на open source-решение, а на Земле за это время проходит семь часов? Делитесь в комментариях — очень интересно узнать. Всем стабильных сетей и точных измерений!