- PVSM.RU - https://www.pvsm.ru -
Для сбора и удобного просмотра данных о том, как работает PostgreSQL (общая производительность сервера, самые медленные запросы, самые частые запросы) мы долгое время использовали отличную утилиту POWA [1]. Однако, это решение было далеко не идеальным и нам удалось найти более удачный вариант, к тому же полностью интегрированный с нашей основной системой мониторинга.
POWA минимально удовлетворяла большинству наших нужд:
Однако, были и неприятные минусы:
Пара скриншотов POWA для примера:
В связи с этим, было решено попробовать собирать метрики с PostgreSQL с помощью postgres_exporter [2] для Prometheus.
TL;DR: вот роль для Ansible, писалась под CentOS 7, но после минимальных правок (замена firewalld на iptables) должна работать на любой системе с systemd — https://github.com/UnitedTraders/ansible-postgresql-exporter [3]
Я не буду подробно рассказывать про сам Prometheus, материалов про него достаточно, но пройдусь по общей архитектуре и экспортеру.
Prometheus использует pull модель сбора метрик: у него есть список экспортеров и он опрашивает их по HTTP, собирая с них список метрик и кладя их к себе в хранилище.
Экспортер — это агент, который занимается сбором метрик непосредственно с сущности (сервера в целом, или конкретного приложения), которую надо мониторить. У Prometheus богатые возможности для инструментации, поэтому экспортеры есть для большинства популярных приложений, и написать свой в случае надобности не представляет особого труда.
postgres_exporter работает следующим образом: он подключается к PostgreSQL, выполняет запросы к служебным таблицам и выставляет результаты в специальном формате с помощью внутреннего HTTP-сервера для забора их Prometheus'ом. Важный момент: помимо большого набора дефолтных запросов, можно определить свои и собирать любые данные, которые можно получить с помощью SQL, включая какие-нибудь бизнес-метрики.
Таким образом, настройка postgres_exporter'а сводится к трем действиям:
Экспортер написан на Go, так что все банально:
DATA_SOURCE_NAME="postgresql://postgres@localhost:5432/?sslmode=disable"
[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 сводится к трем простым шагам:
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.
С вышеуказанным конфигом, экспортер будет генерировать значительное количество метрик — по 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 самых продолжительных запросов к базеВ графане это выглядит примерно вот так:
Автор: Антон Маркелов
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/postgresql/271459
Ссылки в тексте:
[1] POWA: https://dalibo.github.io/powa/
[2] postgres_exporter: https://github.com/wrouesnel/postgres_exporter
[3] https://github.com/UnitedTraders/ansible-postgresql-exporter: https://github.com/UnitedTraders/ansible-postgresql-exporter
[4] https://github.com/wrouesnel/postgres_exporter/releases: https://github.com/wrouesnel/postgres_exporter/releases
[5] Источник: https://habrahabr.ru/post/345370/?utm_source=habrahabr&utm_medium=rss&utm_campaign=345370
Нажмите здесь для печати.