Базы данных PostgreSQL — основа тысяч проектов: от небольших веб-приложений до высоконагруженных корпоративных систем. Но даже самая надёжная СУБД требует контроля: замедление запросов, нехватка памяти или внезапные блокировки могут обернуться простоями и потерями данных. Правильный мониторинг PostgreSQL помогает предотвратить проблемы ещё на этапе их зарождения, оптимизировать производительность и планировать масштабирование.

В этой статье разберём, какие метрики критично отслеживать, какие инструменты для этого подходят (от встроенных утилит до enterprise-решений), и как настроить систему оповещений, чтобы не пропустить сбои. Особое внимание уделим скрытым "узким местам" PostgreSQL, которые часто упускают из виду: например, влияние автовакуума на IO-нагрузку или рост размера WAL-файлов при репликации.

Какие метрики PostgreSQL нужно мониторить в первую очередь

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

  • 📊 Загрузка CPU: высокое потребление процессора часто указывает на неоптимизированные запросы или недостаток индексов. Особенно критично отслеживать CPU usage by query — какие именно операции "жрут" ресурсы.
  • 🗄️ Использование памяти: PostgreSQL активно кэширует данные в shared_buffers. Если кэш постоянно сбрасывается на диск (buffer cache hit ratio ниже 99%), это сигнал к увеличению RAM или настройке параметров.
  • 🔄 IO-операции: медленные диски — частая причина тормозов. Следите за read/write latency, количеством checkpoints и объёмом записываемых WAL-файлов.
  • 🔒 Блокировки: длительные LOCK (особенно ExclusiveLock) могут парализовать работу. Важно отслеживать, какие транзакции блокируют другие и насколько долго.
  • ⏱️ Время выполнения запросов: даже если среднее время ответа в норме, отдельные slow queries (дольше 1-2 секунд) могут указывать на проблемы с индексами или планировщиком.

Не менее важны метрики репликации (если она используется): lag между мастером и репликами, объём передаваемых данных и ошибки синхронизации. Например, рост replication lag свыше 10 секунд может говорить о сетевых проблемах или перегрузке мастера.

⚠️ Внимание: В PostgreSQL 16+ изменилась логика сбора статистики для некоторых метрик (например, pg_stat_activity теперь показывает больше деталей о параллельных запросах). Если используете новую версию, сверьте список доступных показателей в официальной документации.

Встроенные инструменты PostgreSQL: когда хватит штатных средств

PostgreSQL поставляется с набором утилит, которых часто достаточно для базового мониторинга. Их главный плюс — нет необходимости устанавливать стороннее ПО, а минус — ограниченная визуализация и отсутствие алертов.

Основные инструменты:

  • 🛠️ pg_stat_activity: показывает все активные подключения, выполняемые запросы и их статус. Полезно для поиска "зависших" транзакций:
    SELECT pid, usename, query, state, now() - query_start AS duration
    

    FROM pg_stat_activity

    WHERE state = 'active';

  • 📈 pg_stat_statements: расширение для анализа производительности запросов. Требует подключения в postgresql.conf:
    shared_preload_libraries = 'pg_stat_statements'
    

    pg_stat_statements.track = all

    После этого можно получить топ самых медленных запросов:

    SELECT query, calls, total_exec_time, mean_exec_time
    

    FROM pg_stat_statements

    ORDER BY mean_exec_time DESC

    LIMIT 10;

  • 🔍 EXPLAIN ANALYZE: не совсем мониторинг, но незаменим для диагностики конкретных запросов. Показывает план выполнения и реальное время каждого шага.

Для визуализации данных из этих инструментов можно использовать psql в режиме \watch (автообновление вывода) или простые скрипты на Bash/Python, которые будут слать отчёты по почте. Однако для крупных систем такого подхода явно недостаточно.

📊 Какой инструмент вы используете для мониторинга PostgreSQL?
Встроенные утилиты (pg_stat, EXPLAIN)
Grafana + Prometheus
Zabbix/Нagios
Платные решения (Datadog, Percona)
Собственные скрипты

Grafana + Prometheus: золотая пара для мониторинга

Комбинация Prometheus (для сбора метрик) и Grafana (для визуализации) стала де-факто стандартом для мониторинга инфраструктуры. Для PostgreSQL этот дуэт подходит идеально благодаря гибкости и открытости.

Чтобы настроить мониторинг:

  1. Установите экспортер метрик: самый популярный — postgres_exporter от Prometheus Community. Он подключается к базе и транслирует метрики в формат, понятный Prometheus.

    Пример команды для запуска:

    docker run -d --name postgres_exporter \
    

    -e DATA_SOURCE_NAME="postgresql://user:password@host:port/dbname?sslmode=disable" \

    -p 9187:9187 \

    prometheuscommunity/postgres-exporter

  2. Настройте Prometheus: добавьте job в конфиг prometheus.yml:
    - job_name: 'postgresql'
    

    static_configs:

    - targets: ['localhost:9187']

  3. Импортируйте дашборд в Grafana: готовые шаблоны есть в официальной библиотеке. Популярный вариант — PostgreSQL Overview (ID 9628).

Преимущества этого подхода:

  • 📌 Гибкая настройка алертов через Alertmanager (например, оповещение при росте replication lag свыше 5 секунд).
  • 📊 Возможность корреляции метрик PostgreSQL с другими сервисами (например, связать нагрузку на базу с пиками трафика на веб-сервере).
  • 🔄 Легкое масштабирование: можно мониторить десятки инстансов PostgreSQL с одного Prometheus.
⚠️ Внимание: По умолчанию postgres_exporter собирает метрики с интервалом в 1 секунду. Для высоконагруженных баз это может создать дополнительную нагрузку. Увеличьте интервал до 5-10 секунд в параметре --collect.interval.

Установить postgres_exporter с правильными правами доступа|Добавить job в prometheus.yml|Проверить доступность метрик на порту 9187|Импортировать дашборд в Grafana|Настроить алерты для критических метрик-->

Платные решения: когда стоит платить за мониторинг

Если ваша инфраструктура включает десятки серверов PostgreSQL или требуется глубокий анализ производительности с поддержкой 24/7, стоит рассмотреть платные инструменты. Они предлагают:

  • 🛡️ Встроенную поддержку и SLA (важно для предприятий).
  • 🔍 Продвинутую диагностику (например, автоматический анализ EXPLAIN для медленных запросов).
  • 📱 Мобильные приложения и интеграции с Slack/Teams.

Сравнение популярных решений:

Инструмент Цена (от) Ключевые фичи Минусы
Datadog $15/хост/мес Автоматическое обнаружение аномалий, интеграция с 600+ сервисами, APM для SQL-запросов Дорого для небольших проектов, сложная настройка тарификации
Percona PMM Бесплатно (Enterprise от $1000/год) Специализирован для СУБД, поддержка MongoDB/MySQL, детальная диагностика Сложный интерфейс, требует глубоких знаний PostgreSQL
TimescaleDB + Promscale Бесплатно (Enterprise от $500/мес) Оптимизирован для временных рядов, долгое хранение метрик, SQL-интерфейс Ограниченная визуализация без Grafana
pgMonitor $29/мес Простота настройки, фокус на PostgreSQL, встроенные алерты Мало интеграций, подходит только для PostgreSQL

Для большинства средних проектов оптимальным по соотношению цена/качество будет Percona PMM или TimescaleDB. А вот Datadog целесообразен, если у вас уже есть его экосистема для мониторинга другой инфраструктуры.

💡

Перед покупкой платного инструмента запросите trial-версию и протестируйте его на тестовом стенде. Обратите внимание, как решение справляется с длительными транзакциями и репликацией — это частые "слабые места" в мониторинге.

Мониторинг репликации: как не пропустить lag

Репликация в PostgreSQL — это не только резервирование, но и способ распределить нагрузку. Однако lag (задержка) между мастером и репликами может стать критичной проблемой. Вот что нужно отслеживать:

  • 🕒 Replication Lag: разница во времени между мастером и репликой. В идеале она должна быть близка к нулю. Для мониторинга используйте запрос:
    SELECT
    

    pg_current_wal_lsn() - replay_lsn AS lag_bytes,

    pg_size_pretty(pg_current_wal_lsn() - replay_lsn) AS lag_size

    FROM pg_stat_replication;

  • 📤 Объём WAL: если мастер генерирует слишком много WAL-файлов, реплики не успевают их обрабатывать. Следите за pg_stat_bgwriter.
  • 🔄 Синхронность: если используется synchronous_commit = on, мастер будет ждать подтверждения от реплик, что может замедлять запись.

Частые причины роста lag:

  • 🖥️ Недостаточные ресурсы реплики (CPU, IO, память).
  • 🌐 Сетевые проблемы между мастером и репликой.
  • 🔧 Длинные транзакции на мастере, блокирующие репликацию.

Для диагностики используйте расширение pg_stat_replication и инструменты вроде pgBadger (анализирует логи PostgreSQL). Если lag превышает 10 секунд, проверьте:

  1. Нагрузку на диск реплики (iostat -x 1).
  2. Сетевую задержку (ping и traceroute между серверами).
  3. Наличие длинных транзакций на мастере (SELECT now() - xact_start FROM pg_stat_activity;).
Что делать, если lag растёт экспоненциально?

Если задержка репликации увеличивается лавинообразно (например, с 1 секунды до 1 минуты за час), это часто указывает на нехватку ресурсов для обработки WAL на реплике. Временное решение — увеличить max_wal_size на мастере (но это отсрочит проблему, не решив её). Радикальный способ — пересоздать реплику с нуля (pg_basebackup), если lag превысил несколько часов.

Алерты и нотификации: как не утонуть в потоке данных

Собирать метрики мало — нужно реагировать на проблемы до того, как они повлияют на пользователей. Правильные алерты экономят часы на диагностике. Вот какие уведомления стоит настроить:

  • 🚨 Критические ошибки: падение сервиса, невозможность подключиться к базе, ошибки репликации (FATAL в логах).
  • ⚠️ Предупреждения:
    • Загрузка CPU > 90% более 5 минут.
    • Replication lag > 10 секунд.
    • Количество блокировок > 50 (из pg_locks).
    • Свободное место на диске < 10%.
  • 📈 Тренды: рост времени выполнения запросов на 30% за неделю, увеличение размера базы на 20% за месяц.

Примеры настройки алертов:

В Prometheus + Alertmanager:

- alert: HighPostgresCPU

expr: rate(process_cpu_seconds_total{job="postgresql"}[5m]) * 100 > 90

for: 5m

labels:

severity: warning

annotations:

summary: "High CPU usage on PostgreSQL (instance {{ $labels.instance }})"

description: "CPU usage is {{ $value }}% (above 90% for 5m)"

В Zabbix:

Создайте триггер с условием:

{postgresql:pg_locks.count[locktype=ExclusiveLock]} > 50

Важно настроить эскалацию уведомлений:

  • Первое оповещение — в Slack или на почту.
  • Если проблема не решена за 30 минут — звонок на дежурный телефон.
  • Через 1 час — уведомление руководству.
⚠️ Внимание: Избегайте "алертной усталости" — когда уведомления приходят слишком часто и перестают восприниматься серьёзно. Настройте inhibit_rules в Alertmanager, чтобы подавлять второстепенные алерты при критических сбоях (например, не слать предупреждения о высоком CPU, если база вообще не отвечает).

Скрытые проблемы: что упускают 90% админов

Даже опытные администраторы PostgreSQL иногда не обращают внимания на неочевидные метрики, которые могут приводить к деградации производительности. Вот что часто упускают:

  • 🧹 Автовакуум: если он не успевает очищать "мёртвые" строки, таблицы раздуваются, а индексы становятся неэффективными. Проверяйте:
    SELECT schemaname, relname, n_dead_tup, last_autovacuum
    

    FROM pg_stat_all_tables

    WHERE n_dead_tup > 10000;

    Решение: увеличьте autovacuum_vacuum_scale_factor или настройте ручной VACUUM FULL в непиковые часы.
  • 🗑️ Bloat индексов: индексы со временем "разбухают", занимая лишнее место и замедляя запросы. Найдите их так:
    SELECT schemaname, tablename, indexname, pg_size_pretty(pg_relation_size(indexname::regclass)) as size
    

    FROM pg_indexes

    WHERE schemaname NOT LIKE 'pg_%' AND schemaname != 'information_schema'

    ORDER BY pg_relation_size(indexname::regclass) DESC;

    Решение: пересоздайте индекс (REINDEX) или используйте pg_repack.
  • 🔄 Длинные транзакции: даже одна транзакция, открытая на час, может заблокировать автовакуум и репликацию. Ищите их в pg_stat_activity по полю xact_start.
  • 📡 Сетевые задержки: если мастер и реплики в разных ЦОД, проверьте ping и traceroute. Лаг в 100+ мс может сделать репликацию бесполезной.

Ещё одна распространённая проблема — неправильно настроенные параметры памяти. Например, если shared_buffers установлен в 25% от RAM (как часто советуют), но на сервере работает ещё и приложение, это приведёт к свапу. Оптимальное значение — 25-40% от физической памяти, но не более 8-16 ГБ для большинства задач.

💡

Регулярно проверяйте размер pg_stat и pg_dynshmem — если они занимают гигабайты, это признак утечки памяти в PostgreSQL или некорректной настройки параметров типа track_activity_query_size.

FAQ: Ответы на частые вопросы

Как мониторить PostgreSQL в Docker-контейнере?

Для контейнеризированного PostgreSQL подход тот же, но есть нюансы:

  1. Используйте docker stats для мониторинга ресурсов контейнера.
  2. Настройте postgres_exporter как sidecar-контейнер или подключайтесь к базе извне.
  3. Следите за docker logs — там могут быть критические ошибки, не попадающие в стандартные логи PostgreSQL.

Пример docker-compose.yml с мониторингом:

services:

postgres:

image: postgres:15

environment:

POSTGRES_PASSWORD: example

volumes:

- ./data:/var/lib/postgresql/data

exporter:

image: prometheuscommunity/postgres-exporter

environment:

DATA_SOURCE_NAME: "postgresql://postgres:example@postgres:5432/postgres?sslmode=disable"

ports:

- "9187:9187"

Можно ли мониторить PostgreSQL без установки дополнительного ПО?

Да, но с ограничениями. Варианты:

  • Использовать psql в режиме \watch для периодического выполнения запросов (например, WATCH 1 обновляет вывод каждую секунду).
  • Написать простой Bash-скрипт, который будет слать уведомления по почте при превышении порогов:
    #!/bin/bash
    

    LAG=$(psql -U user -d dbname -c "SELECT EXTRACT(EPOCH FROM (now() - replay_lsn)) FROM pg_stat_replication;" | grep -oP '\d+\.\d+')

    if (( $(echo "$LAG > 10" | bc -l) )); then

    echo "Replication lag is $LAG seconds!" | mail -s "PostgreSQL Alert" admin@example.com

    fi

  • Настроить cron для регулярного сбора статистики в CSV/JSON.

Минус: нет исторических данных и удобной визуализации.

Какие метрики важны для PostgreSQL в облаке (AWS RDS, Google Cloud SQL)?

Облачные провайдеры предоставляют ограниченный доступ к хосту, поэтому фокусируйтесь на:

  • CloudWatch Metrics (для AWS RDS): CPUUtilization, FreeStorageSpace, ReplicaLag.
  • Query Insights (Google Cloud SQL): анализ медленных запросов с разбивкой по времени и ресурсам.
  • Логи ошибок: в облаках они часто доступны через консоль или API (например, aws rds download-db-log-file-portion).
  • Сетевой трафик: в облаке за исходящий трафик между репликами может взиматься плата.

Обратите внимание: в облачных сервисах нельзя:

  • Установить postgres_exporter напрямую (используйте управляемые решения вроде Datadog или Prometheus на отдельном сервере).
  • Изменить некоторые параметры PostgreSQL (например, shared_buffers часто фиксирован).
Как мониторить производительность конкретного запроса?

Используйте комбинацию инструментов:

  1. pg_stat_statements: покажет, сколько раз запрос выполнялся и сколько времени занял в сумме.
    SELECT query, calls, total_exec_time, mean_exec_time
    

    FROM pg_stat_statements

    WHERE query LIKE '%your_table%'

    ORDER BY mean_exec_time DESC;

  2. EXPLAIN ANALYZE: даст детальный план выполнения с реальным временем каждого шага.
    EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM large_table WHERE id = 123;
  3. pgBadger: проанализирует логи и покажет, какие запросы чаще всего вызывают ошибки или блокировки.
  4. Auto-explain: расширение, которое логирует планы выполнения для всех запросов медленнее заданного порога. Настройка в postgresql.conf:
    shared_preload_libraries = 'auto_explain'
    

    auto_explain.log_min_duration = '100ms'

    auto_explain.log_analyze = on

    auto_explain.log_buffers = on

Если запрос тормозит из-за блокировок, проверьте:

SELECT blocked_locks.pid AS blocked_pid,

blocked_activity.usename AS blocked_user,

blocking_locks.pid AS blocking_pid,

blocking_activity.usename AS blocking_user,

blocked_activity.query AS blocked_statement

FROM pg_catalog.pg_locks blocked_locks

JOIN pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid

JOIN pg_catalog.pg_locks blocking_locks

ON blocking_locks.locktype = blocked_locks.locktype

AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE

AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation

AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page

AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple

AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid

AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid

AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid

AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid

AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid

AND blocking_locks.pid != blocked_locks.pid

JOIN pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid

WHERE NOT blocked_locks.GRANTED;

Сколько истории метрик нужно хранить?

Зависит от задачи:

  • Для оперативного мониторинга (поиск причин сбоев): 7–30 дней. Этого достаточно, чтобы проанализировать инциденты.
  • Для трендов и планирования (масштабирование, покупка железа): 1–2 года. Позволяет увидеть сезонные нагрузки (например, рост трафика в чёрную пятницу).
  • Для комплаенса (аудит, SLA): 3–5 лет. Может потребоваться по юридическим причинам.

Технические ограничения:

  • Prometheus: по умолчанию хранит данные 15 дней (настраивается в retention).
  • Grafana Cloud: от 14 дней в бесплатном тарифе до неограниченного в Enterprise.
  • TimescaleDB: оптимизирован для долговременного хранения (может хранить годы данных без потери производительности).

Совет: для долговременного хранения используйте downsampling — агрегируйте метрики (например, хранить не каждую секунду, а средние значения за 5 минут).