Модуль мониторинга PM2 приложений с экспортом в Prometheus и Grafana

Мониторинг node.js приложения является одним из важных этапов анализа качества и корректной работы приложения. Он позволяет выявлять происходящие проблемы и быстро принимать решения для их исправления.

PM2 предоставляет средства для мониторинга всех ваших приложений, но в бесплатной версии они доступны только через консольную команду pm2 monit или же предоставляет подписку PM2 Plus с дополнительным функционалом.

Результат исполнения команды pm2 monit

К сожалению ни тот, ни другой способ не всегда подходит для мониторинга, потому что в первом случае вам необходимо видеть не только текущие показатели работы, но и изменение значений с учетом времени. Например, рост использования памяти внутри приложения или количество его перезагрузок. А второй вариант - во-первых платный, а во-вторых он не интегрируется в вашу общую систему мониторинга и находится на стороннем сервисе.

В большинстве случаев проекты используют связку 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

Dashboard для мониторинга PM2 приложений

В нашем случае каждый node.js проект мы пакуем в Docker контейнер и внутри устанавливаем PM2 и дополнительные модули. Все параметры, такие как название сервиса или порт, передаются через аргументы. В итоге Docker контейнер выглядит примерно таким образом.

FROM node:14-bullseye-slim 

#### Установка PM2
RUN npm i -g pm2@5.2.2

# ...
# Сборка проекта
#...

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"]

На данный момент модуль не умеет экспортировать метрики из самих приложений, но я надеюсь реализовать это в будущих версиях.