Важно отслеживать показатели и работоспособность приложения, что помогает нам повышать производительность, лучше управлять приложением и замечать неоптимизированное поведение. Мониторинг каждой службы важен для поддержания системы, состоящей из множества микросервисов.
В этом сообщении в блоге я продемонстрирую, как веб-приложение Spring Boot можно отслеживать с помощью Micrometer , который предоставляет метрики из нашего приложения, Prometheus который хранит метрические данные, и Графана для визуализации данных в графиках.
Внедрение этих инструментов может быть сделано довольно легко, добавив всего несколько конфигураций. В дополнение к метрикам JVM по умолчанию я покажу, как вы можете предоставлять пользовательские метрики, такие как счетчик пользователей.
Как всегда, код для демо-версии, используемой в этой статье, можно найти на GitHub .
Пружинный ботинок
Основой для нашей демонстрации является приложение Spring Boot, которое мы инициализируем с помощью Spring Initializr :
Мы инициализировали проект с помощью spring-boot-starter-actuator , который уже предоставляет готовые к производству конечные точки .
Если мы запустим наше приложение, мы увидим, что некоторые конечные точки, такие как health и info уже доступны для конечной точки /actuator по умолчанию.
Запуск конечной точки /actuator/health дает нам показатель, запущена ли служба и работает ли она:
▶ http GET "http://localhost:8080/actuator/health"
HTTP/1.1 200
Connection: keep-alive
Content-Type: application/vnd.spring-boot.actuator.v3+json
Date: Wed, 21 Oct 2020 18:11:35 GMT
Keep-Alive: timeout=60
Transfer-Encoding: chunked
{
"status": "UP"
}
Привод Spring Boot может быть интегрирован в Spring Boot Admin , который предоставляет визуальный интерфейс администратора для вашего приложения. Но этот подход не очень популярен и имеет некоторые ограничения. Поэтому мы используем Прометей вместо привода пружинного башмака и Grafana вместо Spring Boot Admin, чтобы иметь более популярное и независимое от фреймворка/языка решение.
Этот подход к решению требует метрик, не зависящих от поставщика, и Micrometer является популярным инструментом для этого варианта использования.
Микрометр
Micrometer обеспечивает простой интерфейс по сравнению с клиентами instrumentation для наиболее популярных систем мониторинга, позволяя вам настраивать код приложения на основе JVM без привязки к поставщику. Подумайте о SLF4J, но для метрик.
Micrometer является проектом с открытым исходным кодом и предоставляет метрический фасад, который предоставляет метрические данные в независимом от поставщика формате, понятном системе мониторинга. Эти системы мониторинга поддерживаются:
- Приложение “Оптика”
- Монитор Azure
- Атлас Netflix
- Облачный дозор
- Журнал данных
- Динатрасса
- Эластичный
- Узлы
- Графит
- Гумио
- Приток/Телеграф
- JMX
- KairosDB
- Новая Реликвия
- Прометей
- SignalFx
- Google Stackdriver
- СтатсД
- Волновой фронт
Микрометр не является частью экосистемы Spring и должен быть добавлен как зависимость. В нашем демонстрационном приложении это уже было сделано в конфигурации Spring Initializr .
Следующий шаг – предоставить метрики Prometheus в application.properties :
management.endpoints.web.exposure.include=prometheus,health,info,metric
Теперь мы можем запустить эту конечную точку и увидеть показатели Prometheus:
▶ http GET "http://localhost:8080/actuator/prometheus"
HTTP/1.1 200
Connection: keep-alive
Content-Length: 8187
Content-Type: text/plain; version=0.0.4;charset=utf-8
Date: Thu, 22 Oct 2020 09:19:36 GMT
Keep-Alive: timeout=60
# HELP tomcat_sessions_rejected_sessions_total
# TYPE tomcat_sessions_rejected_sessions_total counter
tomcat_sessions_rejected_sessions_total 0.0
# HELP system_cpu_usage The "recent cpu usage" for the whole system
# TYPE system_cpu_usage gauge
system_cpu_usage 0.0
# HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool
# TYPE jvm_buffer_count_buffers gauge
jvm_buffer_count_buffers{id="mapped",} 0.0
jvm_buffer_count_buffers{id="direct",} 3.0
# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="G1 Survivor Space",} 1.048576E7
jvm_memory_used_bytes{area="heap",id="G1 Old Gen",} 3099824.0
jvm_memory_used_bytes{area="nonheap",id="Metaspace",} 3.9556144E7
jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 1206016.0
jvm_memory_used_bytes{area="heap",id="G1 Eden Space",} 3.3554432E7
jvm_memory_used_bytes{area="nonheap",id="Compressed Class Space",} 5010096.0
jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 6964992.0
# HELP jvm_gc_pause_seconds Time spent in GC pause
# TYPE jvm_gc_pause_seconds summary
jvm_gc_pause_seconds_count{action="end of minor GC",cause="Metadata GC Threshold",} 1.0
jvm_gc_pause_seconds_sum{action="end of minor GC",cause="Metadata GC Threshold",} 0.009
# HELP jvm_gc_pause_seconds_max Time spent in GC pause
# TYPE jvm_gc_pause_seconds_max gauge
jvm_gc_pause_seconds_max{action="end of minor GC",cause="Metadata GC Threshold",} 0.009
# HELP jvm_gc_live_data_size_bytes Size of old generation memory pool after a full GC
# TYPE jvm_gc_live_data_size_bytes gauge
jvm_gc_live_data_size_bytes 4148400.0
# HELP jvm_gc_max_data_size_bytes Max size of old generation memory pool
# TYPE jvm_gc_max_data_size_bytes gauge
jvm_gc_max_data_size_bytes 4.294967296E9
# HELP tomcat_sessions_active_current_sessions
# TYPE tomcat_sessions_active_current_sessions gauge
tomcat_sessions_active_current_sessions 0.0
# HELP process_files_open_files The open file descriptor count
# TYPE process_files_open_files gauge
process_files_open_files 69.0
# HELP http_server_requests_seconds
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/actuator/health",} 1.0
http_server_requests_seconds_sum{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/actuator/health",} 0.041047824
# HELP http_server_requests_seconds_max
# TYPE http_server_requests_seconds_max gauge
http_server_requests_seconds_max{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/actuator/health",} 0.041047824
# HELP jvm_threads_peak_threads The peak live thread count since the Java virtual machine started or peak was reset
# TYPE jvm_threads_peak_threads gauge
jvm_threads_peak_threads 32.0
# HELP process_uptime_seconds The uptime of the Java virtual machine
# TYPE process_uptime_seconds gauge
process_uptime_seconds 13.385
# HELP process_cpu_usage The "recent cpu usage" for the Java Virtual Machine process
# TYPE process_cpu_usage gauge
process_cpu_usage 0.0
# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management
# TYPE jvm_memory_max_bytes gauge
jvm_memory_max_bytes{area="heap",id="G1 Survivor Space",} -1.0
jvm_memory_max_bytes{area="heap",id="G1 Old Gen",} 4.294967296E9
jvm_memory_max_bytes{area="nonheap",id="Metaspace",} -1.0
jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 7553024.0
jvm_memory_max_bytes{area="heap",id="G1 Eden Space",} -1.0
jvm_memory_max_bytes{area="nonheap",id="Compressed Class Space",} 1.073741824E9
jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 2.44105216E8
# HELP logback_events_total Number of error level events that made it to the logs
# TYPE logback_events_total counter
logback_events_total{level="warn",} 0.0
logback_events_total{level="debug",} 0.0
logback_events_total{level="error",} 0.0
logback_events_total{level="trace",} 0.0
logback_events_total{level="info",} 8.0
# HELP system_load_average_1m The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time
# TYPE system_load_average_1m gauge
system_load_average_1m 3.18994140625
# HELP jvm_gc_memory_promoted_bytes_total Count of positive increases in the size of the old generation memory pool before GC to after GC
# TYPE jvm_gc_memory_promoted_bytes_total counter
jvm_gc_memory_promoted_bytes_total 0.0
# HELP jvm_threads_states_threads The current number of threads having NEW state
# TYPE jvm_threads_states_threads gauge
jvm_threads_states_threads{state="runnable",} 14.0
jvm_threads_states_threads{state="blocked",} 0.0
jvm_threads_states_threads{state="waiting",} 11.0
jvm_threads_states_threads{state="timed-waiting",} 5.0
jvm_threads_states_threads{state="new",} 0.0
jvm_threads_states_threads{state="terminated",} 0.0
# HELP jvm_memory_committed_bytes The amount of memory in bytes that is committed for the Java virtual machine to use
# TYPE jvm_memory_committed_bytes gauge
jvm_memory_committed_bytes{area="heap",id="G1 Survivor Space",} 1.048576E7
jvm_memory_committed_bytes{area="heap",id="G1 Old Gen",} 1.31072E8
jvm_memory_committed_bytes{area="nonheap",id="Metaspace",} 4.1336832E7
jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 2949120.0
jvm_memory_committed_bytes{area="heap",id="G1 Eden Space",} 1.26877696E8
jvm_memory_committed_bytes{area="nonheap",id="Compressed Class Space",} 5767168.0
jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 7012352.0
# HELP tomcat_sessions_active_max_sessions
# TYPE tomcat_sessions_active_max_sessions gauge
tomcat_sessions_active_max_sessions 0.0
# HELP jvm_buffer_memory_used_bytes An estimate of the memory that the Java virtual machine is using for this buffer pool
# TYPE jvm_buffer_memory_used_bytes gauge
jvm_buffer_memory_used_bytes{id="mapped",} 0.0
jvm_buffer_memory_used_bytes{id="direct",} 24576.0
# HELP jvm_gc_memory_allocated_bytes_total Incremented for an increase in the size of the young generation memory pool after one GC to before the next
# TYPE jvm_gc_memory_allocated_bytes_total counter
jvm_gc_memory_allocated_bytes_total 2.7262976E7
# HELP jvm_classes_loaded_classes The number of classes that are currently loaded in the Java virtual machine
# TYPE jvm_classes_loaded_classes gauge
jvm_classes_loaded_classes 7336.0
# HELP jvm_classes_unloaded_classes_total The total number of classes unloaded since the Java virtual machine has started execution
# TYPE jvm_classes_unloaded_classes_total counter
jvm_classes_unloaded_classes_total 0.0
# HELP tomcat_sessions_created_sessions_total
# TYPE tomcat_sessions_created_sessions_total counter
tomcat_sessions_created_sessions_total 0.0
# HELP process_files_max_files The maximum file descriptor count
# TYPE process_files_max_files gauge
process_files_max_files 10240.0
# HELP tomcat_sessions_alive_max_seconds
# TYPE tomcat_sessions_alive_max_seconds gauge
tomcat_sessions_alive_max_seconds 0.0
# HELP jvm_buffer_total_capacity_bytes An estimate of the total capacity of the buffers in this pool
# TYPE jvm_buffer_total_capacity_bytes gauge
jvm_buffer_total_capacity_bytes{id="mapped",} 0.0
jvm_buffer_total_capacity_bytes{id="direct",} 24576.0
# HELP system_cpu_count The number of processors available to the Java virtual machine
# TYPE system_cpu_count gauge
system_cpu_count 12.0
# HELP jvm_threads_live_threads The current number of live threads including both daemon and non-daemon threads
# TYPE jvm_threads_live_threads gauge
jvm_threads_live_threads 30.0
# HELP process_start_time_seconds Start time of the process since unix epoch.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.603358363515E9
# HELP tomcat_sessions_expired_sessions_total
# TYPE tomcat_sessions_expired_sessions_total counter
tomcat_sessions_expired_sessions_total 0.0
# HELP jvm_threads_daemon_threads The current number of live daemon threads
# TYPE jvm_threads_daemon_threads gauge
jvm_threads_daemon_threads 26.0
Пользовательские показатели
Мы также можем определить некоторые пользовательские показатели, которые я продемонстрирую в этом разделе. Демонстрация содержит класс Scheduler , который периодически запускает включенный метод scheduling Task .
Чтобы иметь возможность отправлять пользовательские показатели, нам необходимо импортировать Meter Registry из библиотеки Micrometer и вводим его в наш класс. Для получения более подробной информации, пожалуйста, ознакомьтесь с официальной документацией .
Можно создать экземпляры этих типов счетчиков из Реестра счетчиков :
- Счетчик : сообщает просто о количестве по указанному свойству приложения
- Датчик : показывает текущее значение счетчика
- Таймеры : измеряет задержки или частоту событий
- Сводка распределения : обеспечивает распределение событий и простое резюме
Я внедрил счетчик и датчик для демонстрационных целей:
@Component
public class Scheduler {
private final AtomicInteger testGauge;
private final Counter testCounter;
public Scheduler(MeterRegistry meterRegistry) {
// Counter vs. gauge, summary vs. histogram
// https://prometheus.io/docs/practices/instrumentation/#counter-vs-gauge-summary-vs-histogram
testGauge = meterRegistry.gauge("custom_gauge", new AtomicInteger(0));
testCounter = meterRegistry.counter("custom_counter");
}
@Scheduled(fixedRateString = "1000", initialDelayString = "0")
public void schedulingTask() {
testGauge.set(Scheduler.getRandomNumberInRange(0, 100));
testCounter.increment();
}
private static int getRandomNumberInRange(int min, int max) {
if (min >= max) {
throw new IllegalArgumentException("max must be greater than min");
}
Random r = new Random();
return r.nextInt((max - min) + 1) + min;
}
}
Если мы запустим приложение, мы увидим, что наши пользовательские показатели отображаются через actuatuor/prometheus конечная точка:
▶ http GET "http://localhost:8080/actuator/prometheus" | grep custom # HELP custom_gauge # TYPE custom_gauge gauge custom_gauge 29.0 # HELP custom_counter_total # TYPE custom_counter_total counter custom_counter_total 722.0
Поскольку теперь у нас есть метрики, доступные в формате, понятном Prometheus, мы рассмотрим, как настроить Prometheus.
Прометей
Prometheus хранит наши метрические данные во временных рядах в памяти, периодически извлекая их через HTTP. Данные могут быть визуализированы с помощью языка шаблонов консоли, встроенного браузера выражений или путем интеграции Графана (что мы сделаем после настройки Prometheus).
В этой демонстрации мы будем запускать Prometheus локально в контейнере Docker, и поэтому нам понадобятся некоторые конфигурации в prometheus.yml файл, который вы можете разместить в любом месте вашего жесткого диска:
global:
scrape_interval: 10s # How frequently to scrape targets by default
scrape_configs:
- job_name: 'spring_micrometer' # The job name is assigned to scraped metrics by default.
metrics_path: '/actuator/prometheus' # The HTTP resource path on which to fetch metrics from targets.
scrape_interval: 5s # How frequently to scrape targets from this job.
static_configs: # A static_config allows specifying a list of targets and a common label set for them
- targets: ['192.168.178.22:8080']
Все доступные параметры конфигурации можно увидеть в официальной документации .
Поскольку мы хотим запустить Prometheus в контейнере Docker, нам нужно сообщить Prometheus наш IP-адрес вместо localhost в static_configs -> targets . Вместо localhost:8080 мы используем 192.168.178.22:8080 где 192.168.178.22 это мой IP-адрес на данный момент. Чтобы получить IP-адрес вашей системы, вы можете использовать ifconfig или ipconfig в вашем терминале в зависимости от вашей операционной системы.
Теперь мы готовы запустить “Прометей”:
docker run -d -p 9090:9090 -v:/etc/prometheus/prometheus.yml prom/prometheus
<путь к вашему prometheus.yml> должен быть путем, по которому вы разместили prometheus.файл конфигурации yml , описанный выше.
Наконец, мы можем открыть “Прометей” на http://localhost:9090 в веб-браузере и найдите свою пользовательскую метрику с именем custom_gauge настройка :
Чтобы проверить, правильно ли Prometheus прослушивает наше локально запущенное приложение Spring Boot, мы можем перейти к Status -> Targets в верхней главной панели навигации:
Prometheus предоставляет язык запросов PromQL, проверьте официальную документацию для получения более подробной информации.
Графана
Включенный график браузера Prometheus хорош для базовой визуализации наших показателей, но мы будем использовать Графана вместо этого. Grafana предоставляет богатый пользовательский интерфейс, в котором вы создаете, исследуете и делитесь информационными панелями, содержащими несколько графиков.
Grafana может извлекать данные из различных источников данных, таких как Prometheus, Elasticsearch, InfluxDB и т.д. Он также позволяет вам устанавливать оповещения на основе правил, которые затем могут уведомлять вас через Slack, электронную почту, Hipchat и тому подобное.
Мы запускаем Grafana также локально в контейнере Docker:
docker run -d -p 3000:3000 grafana/grafana
Открытие http://localhost:3000 в браузере теперь должна отображаться следующая страница входа в систему:
Вы можете войти в систему, используя имя пользователя по умолчанию администратор и пароль по умолчанию администратор . После входа в систему вы должны изменить эти пароли по умолчанию, посетив http://localhost:3000/profile/password .
Первый шаг – добавить наш локальный Prometheus в качестве источника данных:
Панель мониторинга сообщества
Первая панель мониторинга, которую мы хотим добавить, – это панель мониторинга сообщества . Поскольку мы используем приложение Spring Boot, мы выбираем популярную панель управления JVM :
После загрузки URL-адреса мы можем увидеть импортированную панель мониторинга:
Настраиваемая панель управления метриками
Наконец, мы хотим создать новую панель мониторинга, где мы показываем наши пользовательские показатели. Первый шаг – создать новую панель мониторинга:
Теперь мы видим новую панель мониторинга, где мы можем создать новую панель:
На первой панели мы добавляем визуализацию для нашей метрики custom_gauge . Я использую визуализацию Stat , поскольку она показывает текущее значение и простой график:
Кроме того, на нашу панель мониторинга добавлена новая панель для метрики custom_counter :
В итоге приборная панель выглядит так:
Вывод
Важно отслеживать показатели и работоспособность приложения, что помогает нам повысить производительность, лучше управлять приложением и замечать неоптимизированное поведение. Мониторинг каждой службы важен для поддержания системы, состоящей из множества микросервисов.
В этой статье я показал, как веб-приложение Spring Boot можно отслеживать с помощью Micrometer , который предоставляет метрики из нашего приложения, Prometheus который хранит метрические данные и Графана для визуализации данных в виде графиков.
Этот популярный подход к мониторингу должен помочь вам поддерживать ваши приложения и радовать ваших клиентов.
Как всегда, код для демо-версии, используемой в этой статье, можно найти на GitHub .
Оригинал: “https://dev.to/mokkapps/monitoring-spring-boot-application-with-micrometer-prometheus-and-grafana-using-custom-metrics-bb”