POWA-like мониторинг PostgreSQL с помощью Prometheus

в 4:51, , рубрики: postgresql, prometheus, Администрирование баз данных, системное администрирование

Предыстория

Для сбора и удобного просмотра данных о том, как работает PostgreSQL (общая производительность сервера, самые медленные запросы, самые частые запросы) мы долгое время использовали отличную утилиту POWA. Однако, это решение было далеко не идеальным и нам удалось найти более удачный вариант, к тому же полностью интегрированный с нашей основной системой мониторинга.

POWA минимально удовлетворяла большинству наших нужд:

  • Простая в установке и эксплуатации (установи расширение для Postgres, установи веб-морду, пользуйся);
  • Имеет веб-интерфейс (разработчики у нас не имеют доступа на продакшн сервера, а смотреть, как ведет себя база, хочется);
  • Собирает необходимый для нас минимум метрик.

Однако, были и неприятные минусы:

  • Неудобно смотреть данные с нескольких серверов;
  • Интерфейс никак не кастомизируется;
  • Нет возможности прикрутить (без боли) централизованную авторизацию;
  • Нет возможности добавить свои метрики;
  • Нет интеграции с нашей системой мониторинга (мы используем Prometheus для сбора метрик и Grafana для их виуализации).

Пара скриншотов POWA для примера:
POWA-like мониторинг PostgreSQL с помощью Prometheus - 1
POWA-like мониторинг PostgreSQL с помощью Prometheus - 2

В связи с этим, было решено попробовать собирать метрики с PostgreSQL с помощью postgres_exporter для Prometheus.

Установка

TL;DR: вот роль для Ansible, писалась под CentOS 7, но после минимальных правок (замена firewalld на iptables) должна работать на любой системе с systemd — https://github.com/UnitedTraders/ansible-postgresql-exporter

Архитектура решения

Я не буду подробно рассказывать про сам Prometheus, материалов про него достаточно, но пройдусь по общей архитектуре и экспортеру.

Prometheus использует pull модель сбора метрик: у него есть список экспортеров и он опрашивает их по HTTP, собирая с них список метрик и кладя их к себе в хранилище.

Экспортер — это агент, который занимается сбором метрик непосредственно с сущности (сервера в целом, или конкретного приложения), которую надо мониторить. У Prometheus богатые возможности для инструментации, поэтому экспортеры есть для большинства популярных приложений, и написать свой в случае надобности не представляет особого труда.

postgres_exporter работает следующим образом: он подключается к PostgreSQL, выполняет запросы к служебным таблицам и выставляет результаты в специальном формате с помощью внутреннего HTTP-сервера для забора их Prometheus'ом. Важный момент: помимо большого набора дефолтных запросов, можно определить свои и собирать любые данные, которые можно получить с помощью SQL, включая какие-нибудь бизнес-метрики.

Таким образом, настройка postgres_exporter'а сводится к трем действиям:

  • Установить postgres_exporter на сервер, который мы хотим мониторить;
  • Написать запросы (если нужно) для мониторинга своих параметров;
  • Показать серверу Prometheus, откуда забирать метрики.

Установка экспортера

Экспортер написан на Go, так что все банально:

  • Качаем нужный бинарник из https://github.com/wrouesnel/postgres_exporter/releases
  • Определяем переменную окружения в env-файле DATA_SOURCE_NAME="postgresql://postgres@localhost:5432/?sslmode=disable"
  • Создаем systemd юнит, типа такого:

[Unit]
Description=Prometheus exporter for Postgresql (https://github.com/wrouesnel/postgres_exporter)

[Service]
WorkingDirectory=/opt/postgres_exporter
EnvironmentFile=/opt/postgres_exporter/env
ExecStart=/opt/postgres_exporter/postgres_exporter_v0.4.1_linux-amd64/postgres_exporter --extend.query-path=/opt/postgres_exporter/metrics.yaml --web.listen-address=:9187
User=pg_exporter

[Install]
WantedBy=multi-user.target

  • Создаем файл с кастомными запросами для своих метрик (см. ниже);
  • Запускаем сервис.

Настройка своих метрик

По умолчанию, postgres_exporter не умеет собирать данные по запросам. Но в PostgreSQL есть очень полезное расширение pg_stat_statements, которое именно этим и занимается. Установка pg_stat_statements сводится к трем простым шагам:

  • Установить contrib-модули для PostgreSQL;
  • Добавить в postgresql.conf параметр shared_preload_libraries = 'pg_stat_statements';
  • Создать расширение в самом постгресе: CREATE EXTENSION pg_stat_statements.

Т.к. нам важно было собирать в первую очередь время выполнения запросов, то файл с метриками получился вот такой:

pg_database:
  query: " SELECT pg_database.datname, pg_database_size(pg_database.datname) as size FROM pg_database"
  metrics:
    - datname:
        usage: "LABEL"
        description: "Name of the database"
    - size:
        usage: "GAUGE"
        description: "Disk space used by the database"

pg_stat_statements:
  query: "SELECT queryid, datname, left(query, 100) as short_query, sum(calls) as calls, sum(total_time) as total_time, min(min_time) as min_time, max(max_time) as max_time, sum(mean_time*calls)/sum(calls) as mean_time FROM pg_stat_statements JOIN pg_database ON pg_stat_statements.dbid = pg_database.oid group by queryid, short_query, datname"
  metrics:
    - queryid:
        usage: "LABEL"
        description: "Query ID"
    - datname:
        usage: "LABEL"
        description: "Database name"
    - short_query:
        usage: "LABEL"
        description: "Query limited to 100 symbols"
    - calls:
        usage: "COUNTER"
        description: "Number of times executed"
    - total_time:
        usage: "COUNTER"
        description: "Total time spent in the statement, in milliseconds"
    - min_time:
        usage: "GAUGE"
        description: "Minimum time spent in the statement, in milliseconds"
    - max_time:
        usage: "GAUGE"
        description: "Maximum time spent in the statement, in milliseconds"
    - mean_time:
        usage: "GAUGE"
       description: "Mean time spent in the statement, in milliseconds"

Тут есть один подводный камень: записи из pg_stat_statements необходимо агрегировать, т.к. в этой таблице может существовать несколько записей с одинаковым сочетанием query id, database id и query. Наличие таких записей приводит к падению postgres_exporter, т.к. он формирует названия метрик, исходя из этих данных, а они должны быть уникальными.

Для упрощения, я не стал добавлять метрики по чтению/записи (shared_blks_written и т.д., добавляются они по аналогии). Также, повторюсь, подобные запросы можно делать к любой таблице, а не только к pg_stat_statements.

Примеры запросов в Prometheus

С вышеуказанным конфигом, экспортер будет генерировать значительное количество метрик — по 5 штук на каждый вид запроса. Агрегировать мы их будем на стороне Prometheus.

Примеры запросов (сразу с графановскими переменными для templating):

  • sum(rate(pg_stat_statements_mean_time{datname!~"template.*", datname!~"postgres", instance=~"$server"}[1m])) by (instance) — среднее время запроса за последнюю минуту по всему серверу
  • sum(rate(pg_stat_statements_mean_time{datname!~"template.*", datname!~"postgres", instance=~"$server", datname=~"$database"}[1m])) by (datname) — среднее время запроса за последнюю минуту по выбранной базе
  • sum(increase(pg_stat_statements_calls{datname!~"template.*", datname!~"postgres", instance=~"$server", datname=~"$database"}[1m])) by (datname) — количество запросов за минуту к базе
  • topk(20, increase(pg_stat_statements_calls{instance=~"$server", datname=~"$database"}[10m])) — top-20 самых частых запросов к базе за последние 10 минут
  • topk(20, pg_stat_statements_mean_time{instance=~"$server", datname=~"$database"}) — top-20 самых продолжительных запросов к базе

В графане это выглядит примерно вот так:

POWA-like мониторинг PostgreSQL с помощью Prometheus - 3

POWA-like мониторинг PostgreSQL с помощью Prometheus - 4

Автор: Антон Маркелов

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js