Модуль мониторинга PM2 приложений с экспортом в Prometheus и Grafana
Мониторинг node.js приложения является одним из важных этапов анализа качества и корректной работы приложения. Он позволяет выявлять происходящие проблемы и быстро принимать решения для их исправления.
PM2 предоставляет средства для мониторинга всех ваших приложений, но в бесплатной версии они доступны только через консольную команду pm2 monit
или же предоставляет подписку PM2 Plus с дополнительным функционалом.
К сожалению ни тот, ни другой способ не всегда подходит для мониторинга, потому что в первом случае вам необходимо видеть не только текущие показатели работы, но и изменение значений с учетом времени. Например, рост использования памяти внутри приложения или количество его перезагрузок. А второй вариант - во-первых платный, а во-вторых он не интегрируется в вашу общую систему мониторинга и находится на стороннем сервисе.
В большинстве случаев проекты используют связку Prometheus + Grafana которые позволяют не только собирать данные и отображать их в виде графиков, но и настроить алерты при изменении каких-либо метрик.
К сожалению PM2 не предоставляет удобного и простого способа экспортировать данные в Prometheus, по-этому пришлось реализовать свой собственный модуль который позволял бы это делать. Кроме того этот модуль должен уметь экспортировать дополнительные метрики на которые опирается другой мой модуль pm2-autoscale.
Модуль pm2-prom-module был реализован и сейчас доступен для всех желающих. Установить его можно с помощью команды pm2 install
pm2 install pm2-prom-module
После установки поднимается сервер мониторинга на порту 9988
и к нему можно обращаться по адресу http://localhost:9988/
.
Модуль можно конфигурировать и указывать другой порт или название вашего сервиса. Например,
pm2 set pm2-prom-module:port 10801
pm2 set pm2-prom-module:service_name MyApp
Указание сервиса очень удобно, когда вы устанавливаете модуль на разные проекты, а в Grafana используете один dashboard. Так можно сделать выпадающий список со всеми сервисами и быстро между ними переключаться.
Данный модуль собирает все доступные метрики которые предоставляет PM2 и еще несколько дополнительных. Полный список выглядит примерно так:
- Доступная свободная память
- Количество CPU
- Количество запущенных приложений
- Количество инстансов для каждого приложения
- Среднее использование памяти под каждое приложение
- Общее количество используемой памяти под каждое приложение
- Средняя нагрузка на CPU по каждому приложению
- Текущая нагрузка на CPU по каждому приложению
- Количество рестартов каждого приложения
- Uptime по каждому приложению
А так же вся статистика внутри PM2:
- Used Heap Size
- Heap Usage
- Heap Size
- Event Loop Latency p95
- Event Loop Latency
- Active handles
- Active requests
- HTTP req/min
- HTTP P95 Latency
- HTTP Mean Latency
Местами PM2 отдает очень странные данные которые требуют перепроверки, например, Active requests
или HTTP req/min
(в реальности больше похоже на req\sec). Надеюсь потом покопаться во внутренностях и получить больше информации о том как данные считаются.
Вот пример вывода работы модуля:
# HELP pm2_free_memory Show available host free memory
# TYPE pm2_free_memory gauge
pm2_free_memory{serviceName="my-app"} 377147392
# HELP pm2_cpu_count Show available CPUs count
# TYPE pm2_cpu_count gauge
pm2_cpu_count{serviceName="my-app"} 4
# HELP pm2_available_apps Show available apps to monitor
# TYPE pm2_available_apps gauge
pm2_available_apps{serviceName="my-app"} 1
# HELP pm2_app_instances Show app instances count
# TYPE pm2_app_instances gauge
pm2_app_instances{app="app",serviceName="my-app"} 2
# HELP pm2_app_average_memory Show average using memory of an app
# TYPE pm2_app_average_memory gauge
pm2_app_average_memory{app="app",serviceName="my-app"} 60813927
# HELP pm2_app_total_memory Show total using memory of an app
# TYPE pm2_app_total_memory gauge
pm2_app_total_memory{app="app",serviceName="my-app"} 121626624
# HELP pm2_event_loop_latency_p95 Event Loop Latency p95. Unit "ms"
# TYPE pm2_event_loop_latency_p95 gauge
pm2_event_loop_latency_p95{app="app",instance="1",serviceName="my-app"} 2.55
pm2_event_loop_latency_p95{app="app",instance="2",serviceName="my-app"} 2.48
В итоге в Grafana получилось настроить вот такой dashboard
В нашем случае каждый node.js проект мы пакуем в Docker контейнер и внутри устанавливаем PM2 и дополнительные модули. Все параметры, такие как название сервиса или порт, передаются через аргументы. В итоге Docker контейнер выглядит примерно таким образом.
FROM node:14-bullseye-slim
#### Установка PM2
RUN npm i -g [email protected]
# ...
# Сборка проекта
#...
ARG PROJECT_NAME
ARG ENV_METRICS_PORT
#### Установка модулей для PM2
RUN pm2 install pm2-autoscale && pm2 install pm2-prom-module && pm2 set pm2-prom-module:port $ENV_METRICS_PORT && pm2 set pm2-prom-module:service_name $PROJECT_NAME
CMD ["pm2-runtime", "--json", ".ecosystem.config.js"]
На данный момент модуль не умеет экспортировать метрики из самих приложений, но я надеюсь реализовать это в будущих версиях.