Настройка связки JMeter+Prometheus+Grafana
Доброго времени суток, дорогой читатель!
В данной статье мы с вами постараемся подробно разобраться в настройке плагина Prometheus listener, джобы Prometheus и дашборда в Grafana.
Приступим.
Настройка JMeter
Чтобы наш JMeter отдавал необходимые метрики нам нужен следующий плагин:
https://jmeter-plugins.org/files/packages/jmeter-prometheus-0.6.0.zip
После скачивания подкладываем jmeter-prometheus-plugin-0.6.0.jar в apache-jmeter/lib/ext
Если jmeter был открыт - перезагружаем его.
Создадим простой проект для проверки работоспособности нашей схемы:
Я использую FFA катушку. Если вам удобно пользоваться другой - пользуйтесь другой.
Итак, создадим запрос на yandex.ru:


Добавим View Result Tree, чтобы проверить работу нашего запроса:

Попробуем запустить тест:

Отлично! Наш запрос работает.
Теперь добавим Prometheus listener:

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

Name | Help | Labels | Type | Buckets or Quantiles | Listen to | Measuring |
jmeter_rt_summary | response time summary | category,label,code | SUMMARY | 0.75,0.5|0.95,0.1|0.99,0.01 | samples | ResponseTime |
jmeter_count_total | all code and count | label,code | COUNTER |
| samples | CountTotal |
jmeter_success_total | success total | label,code | COUNTER |
| samples | SuccessTotal |
jmeter_success_ratio | success ratio | label,code | SUCCESS_RATIO |
| samples | SuccessRatio |
jmeter_idle_time | idle time |
| SUMMARY | 0.75,0.5|0.95,0.1|0.99,0.01 | samples | IdleTime |
jmeter_failure_total | failure total | label | COUNTER |
| samples | FailureTotal |
jmeter_rt_counter | response time counter |
| SUMMARY | 0.75,0.5|0.95,0.1|0.99,0.01 | samples | ResponseTime |
jmeter_latency_summary | latency summary |
| SUMMARY | 0.75,0.5|0.95,0.1|0.99,0.01 | samples | Latency |
jmeter_connect_time | connect time |
| SUMMARY | 0.75,0.5|0.95,0.1|0.99,0.01 | samples | ConnectTime |
Итак, листенер настроен. Сохраняем наш тест-план и закрываем jmeter.
Теперь нам нужно отредактировать следующий файл: apache-jmeter/bin/jmeter.properties
Добавить в конец файла строчки:
prometheus.port = 9270
prometheus.ip = 0.0.0.0
#prometheus.delay = 0
prometheus.save.threads = true
prometheus.save.threads.name = jmeter_threads
prometheus.save.jvm = true
Должно получиться следующее:

Перезагружаем jmeter. Открываем план, который мы сделали до этого. Запускаем тест.
Теперь по ссылке <jmeter_ip>:9270/metrics (в моем случае это http://localhost:9270/metrics) jmeter отдает нам наши метрики. Для проверки проходим по этом адресу и нажимаем Ctrl+f. В поиске вставляем название метрики:

It's alive! Alive! Поздравляю, у нас получилось!
Настройка Prometheus
Далее нам нужно создать в Prometheus джобу, которая будет следить за нашим эндпоинтом.
Открываем prometheus.yml и прописываем нашу джобу:
scrape_configs:
- job_name: 'jmeter'
scrape_interval: 5s
static_configs:
- targets: ['<jmeter_ip>:9270']
Сохраняем файл, перезапускаем Prometheus.
После запуска идем на графический интерфейс прометея:
<prometheus_ip>:9090/targets?search=
И видим следующую картину:

State = DOWN. Отставить панику! Все в порядке, он и должен быть не активным. Вспоминаем - jmeter отдает метрики только во время проведения теста =)
А что это значит? Правильно! Самое время запустить тест и обновить страницу. И, вауля:

По техническим причинам я этого продемонстрировать не могу, но если перейти по Endpoint'у - мы увидим наши метрики =) Мы на верном пути.
Дело за малым - настроить дашборд в Grafana.
Что ж, приступим.
Настройка Grafana
Идем по <grafana_ip>:3000 и логинимся в ней. Где взять логин и пароль от нее с нужными правами - это отдельная тема, покрытая вуалью неизвестности. Поэтому оставим ее за скобками.
Итак, мы вошли. Первым делом нам нужно подключить наш прометей к графане. Идем на вкладку Data sources(1) и нажимаем Add data source(2).

У меня уже подключен прометей, поэтому мы сделаем вид, что мы его не видим =)
Мы нажали на кнопку и получили результат:

Что нам нужно? Правильно, Prometheus. Его и выбираем.
В самом простом варианте мы заполняем только адрес нашего прометея. В рамках крупных проектов - эти настройки лежат на плечах специалистов, у которых есть все "явки и пароли", и, собственно, доступ к настройке всего "вот этого".
Вы спросите зачем тогда тут об этом писать? Хмм... Затем. Можно протестировать все это на локальном компьютере. На русскоязычных ресурсах в просторах ворлд-вайд-веба такой подробной инструкции нету и я подумал, что пускай будет хотя бы тут.
Лирическое отступление закончено, продолжим. Заполняем поле URL: <prometheus_ip>:9090

Листаем вниз и нажимаем кнопку Save & Test и радуемся следующей картине:

Датасорс успешно добавлен. Мы красавчики!
Теперь нам нужно создать новый дашбоард:

Далее мы попадаем в этот дашборд и выбираем создание новой панели:

В этой статье я не буду расписывать создание каждой панели в отдельности, настроим одну, а остальные можно будет настроить по аналогии.
Итак, после нажатия на Add a new panel мы видим:

Минимальное, что нам нужно сделать :
Заполнить название панели.
Переключиться на Code
Если нужно выводить не запрос, а несколько - добавить, использую кнопку + Query.
Итак, заполняем:

Названия дашборда и панелей - на вашей совести. Желательно с цензурой и информативно.
Так же если прокрутить настройки чуть ниже - можно поиграть с визуализацией метрик. На любой вкус и цвет. Почти.
Нажимаем кнопочку Apply. Поздравляю! Вы создали панель. Примерно через час копи-паста и размышлений у вас должно получиться что-то подобное:

Вернемся чуточку назад: я не просто так рекомендовал настраивать прометеус листенер как в этом примере. У меня есть небольшой бонус. Настройки каждой панели =)
Вжух:
*******************************************************************************************************************************************************************Name: Jmeter threadssum(jmeter_threads{state="active"})
Name: Success ratiosum(irate(jmeter_success_ratio_total[$__interval]))
Name: Avg successavg((rate(jmeter_rt_summary_sum{code="200"}[$__interval])/(rate(jmeter_rt_summary_count{code="200"}[$__interval])>0)))
Name: Avg fail(avg(rate(jmeter_success_ratio_failure[$__interval]))/avg(rate(jmeter_success_ratio_total[$__interval])))
Name: Virtual Users vs OK/KOA: sum(rate(jmeter_success_ratio_success[$__interval]))B: sum(jmeter_threads{state="active"})C: sum(rate(jmeter_success_ratio_failure[$__interval]))
Name: Total Requests vs OK/KOA: (sum(rate(jmeter_success_ratio_success[$__interval]))/sum(rate(jmeter_success_ratio_total[$__interval])))B: (sum(rate(jmeter_success_ratio_failure[$__interval]))/sum(rate(jmeter_success_ratio_total[$__interval])))C: sum(rate(jmeter_success_ratio_total[$__interval]))
Name: Avg. Response Time vs Virtual UsersA: sum(jmeter_threads{state="active"})B: avg((rate(jmeter_rt_summary_sum{code="200"}[$__interval])/(rate(jmeter_rt_summary_count{code="200"}[$__interval])>0)))
Name: Avg. Response Time vs OK/KOA: sum(rate(jmeter_success_ratio_success[$__interval]))B: avg((rate(jmeter_rt_summary_sum{code="200"}[$__interval])/(rate(jmeter_rt_summary_count{code="200"}[$__interval])>0)))C: sum(rate(jmeter_success_ratio_failure[$__interval]))
Name: OKsum(jmeter_success_ratio_success) by (label)
Name: KOsum(jmeter_success_ratio_failure) by (label)
Name: Avg. response timeavg (rate(jmeter_rt_summary_sum{code=~"1.*|2.*|3.*|4.*|5.*"}[$__interval]) / (rate(jmeter_rt_summary_count{code=~"1.*|2.*|3.*|4.*|5.*"}[$__interval])>0)) by (label)
Name: Pct response timesavg(jmeter_rt_summary{code="200"}) by (quantile)
Name: Request per second totalA: sum(rate(jmeter_success_ratio_success[$__interval]))B: sum(rate(jmeter_success_ratio_failure[$__interval]))
Name: Request per second by labelsum(rate(jmeter_success_ratio_total[$__interval])) by (label)
Name: Request per second by HTTPCodesum by (code) (rate(jmeter_success_ratio_total[$__interval]))
Name: Errors by HTTPCodesum by(code) (rate(jmeter_success_ratio_failure[$__interval]))
Name: Errors by labelsum by (label) (rate(jmeter_success_ratio_failure[$__interval]))
Name: GC % timeA: rate(jvm_gc_collection_seconds_sum{job=~"jmeter"}[1m])B: rate(jvm_gc_collection_seconds_sum{job=~"jmeter"}[$__interval]) / ignoring(gc) group_left rate(process_cpu_seconds_total{job=~"jmeter"}[$__interval])C: rate(jvm_gc_collection_seconds_sum{job=~"jmeter"}[1m]) / rate(jvm_gc_collection_seconds_count{job=~"jmeter"}[1m])
Name: JVM heap - free memory by pool(jvm_memory_pool_bytes_committed {job=~"jmeter"}) - (jvm_memory_pool_bytes_used{job=~"jmeter"})
Name: JVM heap - used memory by pool(jvm_memory_pool_bytes_used{job="jmeter"})
Name: JVM free memory(jvm_memory_bytes_max {job="jmeter"}) - (jvm_memory_bytes_used{job="jmeter"})
*******************************************************************************************************************************************************************
Ну что же, дорогой читатель. Вот и подошло к концу наше веселое путешествие через настройку связки JMeter+Prometheus+Grafana.
Прошу прощения за количество "буковок" и картинок - я старался сделать инструкцию максимально подробной.
Понимаю, что тут есть еще очень много нюансов, но я очень надеюсь, что этот материал кому-то окажется полезным!
Пишу на Хабре впервые, прошу не судить строго.
Если найдете неточность или какие-то ошибки - милости прошу в комментарии.
Удачи! =)