Pull to refresh
50
Вячеслав@polarnik

Performance Engineer

57
Subscribers
Send message
Возможно, я серьёзно недоглядел чего-то в документации, но мне не удалось найти способа, допустим, настроить периодическое событие, запускаемое каждые 30 секунд и выполняющее определённые действия при ответе на сообщение WebSocket, а также производящее действия по HTTP, и всё это в рамках одной HTTP-сессии. Я не нашёл такой возможности ни в одном инструменте нагрузочного тестирования

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


А стремление создать в тесте производительности поведение реального пользователя — чаще всего недостижимо. И сделать профиль нагрузки на бумажке, лишь опираясь на логи — хороший подход. Тут согласен. Пример такой, по логам можно узнать интенсивность входов. А у аналитика узнать, что треть пользователей выполняет операцию Х. И вот теперь, на листочке, можно примерно оценить интенсивность операции Х, как функции от интенсивности входа, даже если по Х не было никакой статистики.

Согласно текущему состоянию матрицы:
https://github.com/open-telemetry/opentelemetry-specification/blob/master/spec-compliance-matrix.md
Для Java нет поддержки Zipkin и Jaeger. Телеметрия в лог не так интересна. А как использовать OLTP/gRPC пока не представляю:


Exporters


Но поддержка Zipkin и Jaeger есть при использовании Python и .NET, именно это и имел в виду.


Если я неверно прочел таблицу. И варианты:


  • Service name mapping
  • SpanKind mapping
  • InstrumentationLibrary mapping

это варианты подключения Zipkin/Jaeger API, то тогда был не прав — поддержка есть везде во всех языках.

Крутейший доклад. Только так, на примере, смог разобраться, что такое OpenTelemetry. Из ограничений — интерфейс OpenTelemetry работает в Python и .NET.

Могу перечислить что нахожу удобным в SJK.


  • Неплохая документация. Нет большого количества примеров, часть примеров использования пришлось в свое время подсматривать в тестах инструмента, но она неплохая.
  • Явное разделение на процесс сбора метрик и процесс формирования отчета по метрикам. Что очень удобно.
  • Работа с Windows и Linux, успешно профилировал службы на JVM 6 для Windows (и они были запущены от SYSTEM, это был отдельный квест), все получилось
  • Удобный вывод в виде CSV и текстовых файлов легко передается в InfluxDB, что позволяет организовать непрерывный мониторинг с отображением результатов в Grafana
  • Механизм фильтров и опция categorize для меня является очень удобной фичей, позволяя превратить результаты профилирования в статистику, но вот как раз по ней лучшей документацией являются тесты, а сама документация пока непонятная
  • Возможность объединить результаты профилирования с нескольких POD-ов/экземпляров приложения в один отчет

За счет фильтров, возможности отдельно собрать sdt-файл статистики и отдельно сформировать отчетность в разной форме от csv до svg и html, возможности работы на Windows/Linux/MacOS сделал удобный способ профилирования:


  1. Подключиться к серверу
  2. Запустить там профилирование
  3. Скачать себе назад результаты профилирования
  4. Превратить результаты в отчеты.

Отчеты формируются сложные и долго, по 15-20 минут: объединение результатов профилирования с разных POD-ов микросервисов, с использованием массы фильтров — по потокам, по методам сервиса, по отдельным узким местам. Поэтому удобно, что это делается не на самой POD-е, а на моей машине.


Сложности SJK — нет пока документации на categorize, кроме самих исходников:



Сложности SJK — не запустить профилирование, если есть только JRE, а нет JDK/JDK-devel


  • К счастью. В базовых образах Docker, используемых разработчиками на текущем проекте, есть jdk-devel, поэтому SJK тут работает без дополнительных yum install или apk…
  • Но если бы в контейнерах был бы только JRE, было бы здорово, чтобы инструмент профилирования мог нести с собой tools.jar или какой-то другой механизм подключаться к JRE-процессам, а не только к JDK/JDK-devel-процессам

Раньше наличие только JRE на станции, где нужно выполнить профилирование, было проблемой. Когда надо было профилировать на продуктиве, а там не было возможности поставить что-то дополнительное — нет прав на это. И приходилось копировать вместе с sjk на станцию и папку с jdk — на Windows способ работает хорошо, а вот на Linux нет одной папки с jdk-devel, там нужны и нативные библиотеки и около 5-6-ти разных пакетов, в общем, не просто

Андрей, приветствую!
Также пользуюсь SJK, также как и коллега выше работаю с Enterprise-приложениями.


А async-profiler может формировать отчетность не на станции, на которой выполняется профилирование, а на машине инженера? Не нашел такой возможности изучив документацию

И дополнительно можно группировать pg_stat_activity по ключу


md5(query)::uuid::varchar(100) as query_md5

А если места не жалко, то можно просто по


left(regexp_replace(query, '\\r|\\n|\\t|\\s+', ' ', 'g'), 1000) query

Тогда для "idle in transaction" накапливается статистика о запросах, после которых транзакция зависла. md5 можно сопоставить с md5 из pg_stat_statements. А query сам по себе интересен. В МакроСервисах кода много и текст query может быстрее привести к месту в коде, где транзакции обрываются.

Алексей, спасибо за полезные запросы к pg_stat_activity.
Добавлю, что при наличии микросервисов удобно группировать метрики из pg_stat_activity по usename. Чтобы сопоставлять "idle in transaction" с конкретным сервисом.

Для контекста. Это текстовая расшифровка доклада "Ускоряем Apache.JMeter", который был на конференции Heisenbug 2019 Piter 17-18 мая 2019.


О конференции были статьи от phillennium:



Ссылки на материалы по докладу:



Готовил его вместе с Владимиром Ситниковым vladimirsitnikov. Использовал профайлер SJK от Алексея Рагозина. И помогали советами коллеги из Райффайзенбанка: Алексей, Дмитрий, Урал.


Тема не была исчерпана полностью. Еще есть много аспектов разработки быстрых тестов. Много подходов.


А краткая суть доклада — глядя на результаты benchmark-ов инструментов нагрузки, где JMeter или другой инструмент проигрывает одному из фаворитов обзора, помните, что не все так просто, и один и тот же инструмент может выдать как 300 RPS, так и 19 000 RPS, используя и 0 МБайт ОЗУ и 4 ГБайта.

И по возможности Apache.JMeter использовать несколько ip-адресов для отправки HTTP-запросов, как следствие, кратно увеличивать максимальное количество исходящих соединений тоже тогда ошибся.


В старом JMeter еще была такая опция, когда мы могли привязать текущий клиент к определенному IP. И мы могли расширять диапазон IP на клиенте. Таким образом не залазить ни в одну настройку, а просто говорить, что тест сейчас запускается с трех-четырех-пяти адресов. В актуальной версии это удалили. Это как-то можно придумать иначе.

В акутальной версии Apache.JMeter эта возможность есть:
https://jmeter.apache.org/usermanual/component_reference.html#HTTP_Request


На момент доклада изменился интерфейс JMeter, и в новом интерфейсе я эту настройку потерял из вида. Но она осталась.


image


Source address type
[Only for HTTP Request with HTTPClient implementation]
To distinguish the source address value, select the type of these:
  • Select IP/Hostname to use a specific IP address or a (local) hostname
  • Select Device to pick the first available address for that interface which this may be either IPv4 or IPv6
  • Select Device IPv4 to select the IPv4 address of the device name (like eth0, lo, em0, etc.)
  • Select Device IPv6 to select the IPv6 address of the device name (like eth0, lo, em0, etc.)

И есть статьи по ее использованию:


Спасибо за труд!
Тут в конце статьи, на секции вопросов и ответов, был задан вопрос:


А в Windows есть что-то подобное?

И я тогда ответил, что нет. Что в Windows нельзя расшить диапазон локальных портов или очередь TCP_TIME_WAIT, настроить переиспользование сокетов. Был тогда не прав. Расширить диапазон портов точно возможно.


Устранение проблем нехватки портов (docs.microsoft.com)


Диапазон динамических портов по умолчанию для TCP/IP

Чтобы соответствовать рекомендациям Service Name and Transport Protocol Port Number Registry, корпорация Майкрософт расширила диапазон портов клиентов для исходящих подключений. Новый диапазон по умолчанию — с 49152 по 65535 (16383 портов). В предыдущих версиях Windows диапазон был с 1025 до 5000 (3975 портов).

В статье по ссылке выше есть команды для задания диапазона портов:


netsh int ipv4 set dynamicport tcp start=10000 num=1000

И инструкции по поиску ошибок в Event log, которые показывают — актуальна ли проблема нехватки портов для станции:


  • Event ID 4227
  • Event ID 4231

Хороший вопрос, спасибо.


Да, $granularity — список констант, с интервалом времени.


Сделан для ускорения отображения большого количества графиков, чтобы показать меньше точек. Чтобы можно было задать группировку по минутам, и получить на графике 100 точек вместо 1900 точек (при ширине монитора 1980 точек).


Также для отладки неудачных запросов. И для возможности предсказания ожидаемого количества точек => для наличия критериев соответствия результата запроса настройкам.


Причина — не самое производительное оборудование для станций мониторинга.


И для обратной ситуации, чтобы иногда показать больше точек, чем поддерживает монитор. Показать на отдельном графике три месяца, но с группировкой по минутам. Это используется, чтобы найти на графике отдельный кратковременный запуск теста. Или метрики по отдельному процессу, который фиксировался однажды в момент тестирования, ссылки на временной интервал не сохранилось, и теперь надо его визуально найти. Представьте, что вы выполняли когда-то в этом году тестирование длительностью 30 минут, и вот сейчас отображаете последние 6 месяцев на графике. В этом случае для разрешения 1900 точек получается, что в каждой точке будет 6×30×24×60÷1900=136,42 минут, примерно с такой группировкой выполнится запрос при настройке auto. А если все метрики собирались всего 30 минут, и на графике отображается одна точка, то точку не видно. Некоторые графики для отображения нуждаются в двух точках, и при группировке превышающей весь набор сбора метрик вообще график не получить. Например, функции NON_NEGATIVE_DERIVATIVE(), DERIVATIVE(), NON_NEGATIVE_DIFFERENCE(), DIFFERENCE(),… в таком случае не вернут числовой результат им нужно две точки минимум.


Причина почему из 6 месяцев сбора метрик бывает нужно найти только интервал в 30 минут — нерегулярные запуски тестов, нерегулярный сбор метрик из-за переключений между проектами. Стенд может собраться, тесты будут выполнены (30 минут). А следующий запуск тестов, через недели три, а может через месяц.


Кстати эту проблему уже решил, на связке Grafana + InfluxDB можно сделать ссылки на конкретные участки временного ряда, и кликом по гиперссылке получить нужный интервал времени. Это интересная и полезная задача. Расскажу скоро и о ней.


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


Если отдавать разработанную доску во внешний мир, то можно в $granularity оставить одно значение = auto, а саму переменную скрыть. Тогда у пользователей всегда будет одно значение, основанное на количестве пикселей в графике. Но пока идёт разработка, параметр $granularity полезен с разными значениями.


The $__interval Variable


Цитата
The $__interval is calculated using the time range and the width of the graph (the number of pixels).

Approximate Calculation: (from - to) / resolution

For example, when the time range is 1 hour and the graph is full screen, then the interval might be calculated to 2m — points are grouped in 2 minute intervals. If the time range is 6 months and the graph is full screen, then the interval might be 1d (1 day) — points are grouped by day.

Вариант 3 (не рабочий)
Посмотрел ещё на постпроцессоры telegraf, среди них не нашел такого, который бы ещё на этапе записи метрик в InfluxDB объединил бы hostname и ip_address в одно поле.


Вот все постпроцессоры:
https://github.com/influxdata/telegraf#processor-plugins


Вариант 4 (рабочий)
Но есть вариант решения, через переменные окружения и небольшое изменение в файле конфигурации telegraf.conf. Решение в обход, ещё один пример ненормального программирования с InfluxDB.


Можно:


  • периодически обновлять переменную окружения hostname_with_ip: export hostname_with_ip="hostname(hostname -I | awk '{print $1}')"
  • в файле telegraf.conf настроить сохранение переменной окружения hostname_with_ip в тег hostname_with_ip:
  • фильтровать метрики по готовому тегу

Можно сделать так:


# Global tags can be specified here in key="value" format.
[global_tags]
  # dc = "us-east-1" # will tag all metrics with dc=us-east-1
  # rack = "1a"
  ## Environment variables can be used as tags, and throughout the config file
  # user = "$USER"
  hostname_with_ip = "$hostname_with_ip"

[[inputs.exec]]
  commands = ["sh /opt/telegraf_update_hostname_with_ip.sh"]
  timeout = "60s"
  data_format = "influx"

Можно выполнение export hostname_with_ip="hostname(hostname -I | awk '{print $1}')" поместить куда-нибудь в /etc/profile.d/telegraf_update_hostname_with_ip.sh
тогда не надо будет делать секцию [[inputs.exec]]


И просто фильтруем по готовой переменной.

В комментарии выше всё же описал Вариант 1. Там предположил, что подобная конструкция будет работать. Позже прочел ваш amarao комментарий, про сложение, и понял, что Вариант 1 не получится реализовать. Строки не комбинируются в InfluxDB 1.7, в InfluxDB 2.0, возможно комбинируются.

Да, подзапросы есть. Да, за счёт подзапросов можно преобразовать теги в поля. Но у hostname и ip тип — String, а операция + не работает для строк в InfluxDB.

Понял — задача со звёздочкой.
Вариант 1
Вывести в выпадающем списке комбинацию hostname (ip), и по выбранным значениям успешно фильтровать метрики по полям hostname или ip.


Можно попробовать решить с помощью магии регулярных выражений. Сформировав задачу так: как сформировать регулярное выражение с опциональной частью?


Чтобы выражение вида


performanceAgent (10.11.100.111)*

применилось к списку серверов:


performanceAgent
databaseServer
applicationServer
moniringServer

И оставался только один результат: performanceAgent


Да, такое можно попробовать сделать. Ещё не пробовал.


Вариант 2
А пробовал вот как: использовать для фильтрации не выпадающий список, а отдельный dashboard с таблицей ссылок на другие доски. Где все ячейки таблицы являются фильтрами. Тут возможности вывода не ограничены ничем. Можно в таблицу вывести хоть пять колонок.


Документация на такой способ есть в самом интерфейсе Grafana:



Specify an URL (relative or absolute)
Use special variables to specify cell values:
${__cell} refers to current cell value
${__cell_n} refers to Nth column value in current row. Column indexes are started from 0. For instance,
${__cell_1} refers to second column's value.
${__cell:raw} syntax. By default values are URI encoded. If the value is a complete URL you can disable all encoding using


Пример такой фильтрации подготовил в докладе для Heisenbug, конференцию пока перенесли. Если достаточно одного слайда, то он такой:

Конкретно для случая server, ip пример можно подготовить, но позже.

Пока не сталкивался. Но если задача — вывод hostname и ip в наименовании серии, то можно сделать группировку метрик по двум тегам сразу:

USE telegraf;
SELECT mean("usage")
FROM "cpu"
WHERE
    hostname =~ /^${hostname:regex}$/ AND
    $timeFilter
GROUP BY
    "hostname", "ip", time($granularity)

А в поле ALIAS BY написать:
$tag_hostname ($tag_ip) mean cpu


Это как в самом первом запросе статьи в разделе «Как всё начиналось», только теги называться будут не Type и name, а hostname и ip.

Чтобы вывести в ALIAS BY переменную, можно использовать $tag_{Имя тега} (только такого тега, по которому есть группировка) или $col — имя поля. И ради вывода значения тега в подписи к серии, просто добавляем группировку значений по этому тегу: hostname, а если по два тега нужно вывести, то группируем по двум тегам: hostname и ip.

Верно понял задачу? Или нужно выводить ip в другом месте: в выпадающем списке, таблице?
Слайды и видео трёх докладов Load Testing MeetUp:

1. Программирование с Grafana и InfluxDB. Смирнов Вячеслав (polarnik), Райффайзенбанк.
Видео.
2. Автоматизация НТ. Дёшево и больно. Юрков Кирилл (login40k), Билайн.
Видео.
3. Case Study дефектов производительности: DeadLock, Race Condition, Memory Leak. Филимонов Сергей, EPAM
Видео.

Если у вас есть тема для выступления, то напишите мне (polarnik) или заполните форму заявки на доклад.
И присоединяйтесь к сообществу QA — Load & Performance
Не замерял никогда ещё.
Изучил вопрос немного.

Получается, что Java по умолчанию хранит кеш успешных адресов с момент старта до момента завершения. А кеш неуспешных хранит 10 сек.
$JAVA_HOME/jre/lib/security/java.security
#
# The Java-level namelookup cache policy for successful lookups:
#
# any negative value: caching forever
# any positive value: the number of seconds to cache an address for
# zero: do not cache
#
# default value is forever (FOREVER). For security reasons, this
# caching is made forever when a security manager is set. When a security
# manager is not set, the default behavior in this implementation
# is to cache for 30 seconds.
#
# NOTE: setting this to anything other than the default value can have
# serious security implications. Do not set it unless
# you are sure you are not exposed to DNS spoofing attack.
#
#networkaddress.cache.ttl=-1

# The Java-level namelookup cache policy for failed lookups:
#
# any negative value: cache forever
# any positive value: the number of seconds to cache negative lookup results
# zero: do not cache
#
# In some Microsoft Windows networking environments that employ
# the WINS name service in addition to DNS, name service lookups
# that fail may take a noticeably long time to return (approx. 5 seconds).
# For this reason the default caching policy is to maintain these
# results for 10 seconds.
#
#

networkaddress.cache.negative.ttl=10



В файле system.properties эти настройки не переопределены.
apache-jmeter-5.1/bin/system.properties
# Java networking-related properties
#
# For details of Oracle Java network properties, see for example:
# http://download.oracle.com/javase/1.5.0/docs/guide/net/properties.html
#
#java.net.preferIPv4Stack=false
#java.net.preferIPv6Addresses=false
#networkaddress.cache.ttl=-1
#networkaddress.cache.negative.ttl=10



Получается, что DNS Cache Manager не нужен для ускорения. А может он понадобиться наоборот, чтобы сбрасывать кеш.



А доля DNS Lookup, если сервер верно настроен, будет небольшой.
Но был случай, он помог. Теперь не могу объяснить почему. Спасибо за вопрос.
Цитата из статьи
Коню ясно, что нельзя при нагрузочном тестировании дергать только одну детальную страницу каталога, поэтому полезно считывать и ротировать их список из CSV-файла:
image

image



Так как domain_name принимает значение от 1 до 250. А domain_l1_name ещё несколько значений, пусть 2. То всего имён серверов будет 250 * 2 = 500.
В статье нагрузка подаётся на 500 серверов. Они принимают нагрузку. Судя по тексту статьи
Кстати да, мы не осветили этот момент. Из банальных причин обычно всплывает отсутствие балансировки между nginx — apache — mysql воркерами.

нагрузку принимают nginx-узлы.

Отвечая на вопрос
уточните, пож-та, какой сервер Вы имели ввиду, если указаны несколько в многозвенной системе: proxy, web, app, db (возможно ещё balancer, а в отказоустойчивой схеме и т.д.)?

имел в виду nginx, предполагая, что нагрузка подаётся на него. Он физически может быть один (один сервер), но обслуживать 250 или 500 доменных имён или даже 1000. Правила перенаправления позволяют написать любую конфигурацию.

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

и какая суть разницы фигачить соответствующей нагрузочной интенсивности поток запросов на 1 (или 1 сбалансированный отказоустойчивый контур многозвенки) или 250+?

Разница в мелких деталях. Так подавая нагрузку на 250, 500, 1000 доменных имён. И не включив кеширование DNS ответов на JMeter. Мы будем активнее опрашивать DNS-сервер, на котором будет немалая таблица адресов. Он будет испытывать нагрузку и может стать узким местом. На что обратил внимание автора.
В случае 1 доменного имени ситуация упрощается, нагрузка на DNS меньшая.

Если за указанными 250, 500, 1000 доменными именами стоит столько же разных ip-адресов, то гораздо меньше шансов достигнуть лимита соединений между клиентом и сервером. Так как серверов много и лимиты на количество подключений не будут достигнуты. Если же сервер соотвествует 1 ip-адресу, и клиент соотвествует тоже только 1 ip-адресу. То при высокой интенсивности узким местом может стать получение подключения от клиента к серверу на генераторе нагрузки. По простому — JMeter, имитирующий интенсивную работу 1000 пользователей, не сможет создать ту же нагрузку, что и 1000 пользователей работающих с разных ip-адресов. Об этом рассказывал на конференции Гейзенбаг.

Ускоряем Apache.JMeter:

Тут детали почему так происходит, и как можно настроить нагрузочную станцию.

Information

Rating
Does not participate
Location
Армения
Registered
Activity

Specialization

Инженер по производительности
Ведущий
PostgreSQL
Java
Высоконагруженные системы
Kubernetes