Перейти к содержанию

Администрирование

Администрирование PostgreSQL

Установить PostgreSQL — 5 минут. Настроить для продакшена — совсем другая история. В этой статье разберём ключевые аспекты администрирования: конфигурацию, безопасность, обслуживание и мониторинг.


postgresql.conf — главный конфиг

Файл postgresql.conf определяет поведение сервера. Большинство параметров можно изменить без перезагрузки (SELECT pg_reload_conf()), но некоторые требуют рестарта.

Память

INI
# Общий буферный кеш — основной кеш данных в RAM
# Рекомендация: 25% от RAM (но не больше 8-16 GB на SSD)
shared_buffers = 4GB

# Рабочая память для одного запроса (сортировка, hash join)
# Осторожно: умножается на количество одновременных операций!
# 100 сессий × 256MB = 25GB
work_mem = 256MB

# Память для обслуживающих операций (VACUUM, CREATE INDEX)
maintenance_work_mem = 1GB

# Кеш, управляемый ОС — подсказка планировщику
# Рекомендация: 75% от RAM
effective_cache_size = 12GB

work_mem — самый опасный параметр

work_mem выделяется на каждую операцию сортировки/хеширования, а их может быть несколько в одном запросе. При 200 подключениях и work_mem = 512MB сервер может съесть 100 GB RAM. Начинай с 64-128 MB, увеличивай для конкретных сессий через SET work_mem = '512MB'.

Запись и WAL

INI
# Синхронная запись WAL — безопасность vs скорость
synchronous_commit = on        # on = безопасно, off = быстрее, риск потери <0.5s

# Размер WAL-сегмента
wal_buffers = 64MB

# Checkpoints — как часто данные из WAL сбрасываются на диск
checkpoint_timeout = 15min     # дефолт 5min, можно увеличить для write-heavy
max_wal_size = 4GB             # Макс WAL между чекпоинтами
min_wal_size = 1GB

Подключения

INI
max_connections = 200          # Не ставь 1000 — используй PgBouncer

Параметры, требующие рестарта

Параметр Что делает Рестарт?
shared_buffers Размер буферного кеша Да
max_connections Лимит подключений Да
wal_level Уровень WAL (minimal/replica/logical) Да
work_mem Память на операцию Нет (reload)
random_page_cost Оценка стоимости случайного чтения Нет (reload)
effective_cache_size Подсказка планировщику Нет (reload)
SQL
-- Применить изменения без рестарта
SELECT pg_reload_conf();

-- Проверить текущее значение
SHOW shared_buffers;
SHOW work_mem;

-- Временно для текущей сессии
SET work_mem = '512MB';

pg_hba.conf — контроль доступа

Файл pg_hba.conf определяет кто, откуда и как может подключиться. PostgreSQL проверяет правила сверху вниз — первое совпадение побеждает.

Text Only
# TYPE  DATABASE  USER      ADDRESS         METHOD
local   all       postgres                  peer
host    all       all       127.0.0.1/32    scram-sha-256
host    etl_db    etl_user  10.0.0.0/24     scram-sha-256
host    all       all       0.0.0.0/0       reject
Метод Описание Когда использовать
peer ОС-аутентификация (Linux user = PG user) Локальные подключения
scram-sha-256 Пароль с хешированием (безопасный) Удалённые подключения
md5 Пароль с MD5 (устаревший) Legacy-совместимость
reject Отклонить Явный запрет
cert Клиентский SSL-сертификат Продакшн с высокой безопасностью

Никогда не используй trust

trust пропускает любого без пароля. Допустимо только для локальной разработки в изолированном контейнере.


Роли и привилегии

PostgreSQL использует роли (roles) вместо понятий «пользователь» и «группа». Роль может иметь атрибут LOGIN (тогда это пользователь) или не иметь (тогда это групповая роль).

Создание ролей

SQL
-- Пользователь для приложения (минимальные права)
CREATE ROLE app_user LOGIN PASSWORD 'strong_password';

-- Групповая роль для аналитиков
CREATE ROLE analytics NOLOGIN;

-- Назначить групповую роль пользователю
GRANT analytics TO data_engineer;

Принцип наименьших привилегий

SQL
-- Отозвать все права по умолчанию
REVOKE ALL ON DATABASE etl_db FROM PUBLIC;
REVOKE ALL ON SCHEMA public FROM PUBLIC;

-- Приложению — только CRUD
GRANT CONNECT ON DATABASE etl_db TO app_user;
GRANT USAGE ON SCHEMA public TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO app_user;

-- Аналитикам — только чтение
GRANT CONNECT ON DATABASE etl_db TO analytics;
GRANT USAGE ON SCHEMA public TO analytics;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO analytics;

-- Для будущих таблиц
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO analytics;

Аудит ролей

SQL
-- Кто имеет доступ к таблице?
SELECT grantee, privilege_type
FROM information_schema.table_privileges
WHERE table_name = 'customers';

-- Все роли и их атрибуты
SELECT rolname, rolsuper, rolcreatedb, rolcanlogin
FROM pg_roles
ORDER BY rolname;

VACUUM — обслуживание таблиц

PostgreSQL использует MVCC (Multi-Version Concurrency Control): при UPDATE создаётся новая версия строки, старая помечается как «мёртвая» (dead tuple). VACUUM очищает мёртвые строки и обновляет статистику.

Виды VACUUM

SQL
-- Обычный VACUUM — освобождает место для переиспользования (не уменьшает файл)
VACUUM orders;

-- VACUUM ANALYZE — VACUUM + обновление статистики для планировщика
VACUUM ANALYZE orders;

-- VACUUM FULL — полная перезапись таблицы (уменьшает файл, но блокирует таблицу!)
VACUUM FULL orders;
Вид Блокировка Уменьшает файл Скорость Когда
VACUUM Нет (concurrent) Нет Быстро Автоматически (autovacuum)
VACUUM FULL Exclusive lock! Да Медленно Крайне редко, при критическом bloat
VACUUM ANALYZE Нет Нет Быстро После массовых INSERT/UPDATE

Autovacuum

Autovacuum запускается автоматически и обычно достаточно. Но для больших таблиц может отставать.

SQL
-- Текущие autovacuum-процессы
SELECT pid, datname, relid::regclass, phase, heap_blks_scanned, heap_blks_total
FROM pg_stat_progress_vacuum;

-- Когда был последний vacuum?
SELECT relname, last_vacuum, last_autovacuum, n_dead_tup, n_live_tup
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 10;

-- Настройка autovacuum для конкретной таблицы
ALTER TABLE events SET (
    autovacuum_vacuum_threshold = 1000,
    autovacuum_vacuum_scale_factor = 0.05,  -- запускать при 5% мёртвых (дефолт 20%)
    autovacuum_analyze_threshold = 500
);

Формула запуска autovacuum

Autovacuum запускается когда: dead_tuples > threshold + scale_factor × n_live_tup. По умолчанию: 50 + 0.2 × n_live_tup. Для таблицы в 10 млн строк это 2 млн мёртвых строк — может быть слишком поздно.

Transaction ID Wraparound

PostgreSQL использует 32-битные transaction ID (XID). При ~2 млрд транзакций ID «оборачивается» и все данные становятся «из будущего» → база встаёт. Autovacuum предотвращает это через FREEZE.

SQL
-- Проверить возраст XID
SELECT datname, age(datfrozenxid), datfrozenxid
FROM pg_database
ORDER BY age(datfrozenxid) DESC;

-- Опасно если age > 200_000_000
-- Критично если age > 1_000_000_000

Мониторинг

Ключевые представления

SQL
-- Активные запросы
SELECT pid, usename, state, query_start,
       now() - query_start AS duration,
       LEFT(query, 80) AS query
FROM pg_stat_activity
WHERE state = 'active' AND pid != pg_backend_pid()
ORDER BY duration DESC;

-- Размер таблиц и индексов
SELECT relname,
       pg_size_pretty(pg_total_relation_size(relid)) AS total,
       pg_size_pretty(pg_relation_size(relid)) AS table_only,
       pg_size_pretty(pg_indexes_size(relid)) AS indexes
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;

-- Кеш-хит rate (должен быть > 99%)
SELECT datname,
       blks_hit::float / NULLIF(blks_hit + blks_read, 0) * 100 AS cache_hit_pct
FROM pg_stat_database
WHERE datname = current_database();

pg_stat_statements

Расширение для анализа производительности запросов — must-have для продакшена.

SQL
-- Включить
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

-- postgresql.conf: shared_preload_libraries = 'pg_stat_statements'

-- Самые медленные запросы
SELECT LEFT(query, 80) AS query,
       calls,
       round(total_exec_time::numeric / 1000, 2) AS total_sec,
       round(mean_exec_time::numeric, 2) AS avg_ms,
       rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;

Блокировки

SQL
-- Текущие блокировки
SELECT blocked.pid AS blocked_pid,
       blocked.query AS blocked_query,
       blocking.pid AS blocking_pid,
       blocking.query AS blocking_query
FROM pg_stat_activity blocked
JOIN pg_locks bl ON bl.pid = blocked.pid
JOIN pg_locks lock ON lock.locktype = bl.locktype
     AND lock.relation = bl.relation
     AND lock.pid != bl.pid
JOIN pg_stat_activity blocking ON blocking.pid = lock.pid
WHERE NOT bl.granted;

PgBouncer — пул подключений

PostgreSQL создаёт отдельный процесс на каждое подключение (~5-10 MB RAM). При 500+ подключениях сервер тратит ресурсы на управление процессами вместо запросов.

PgBouncer — лёгкий прокси (~2 KB на подключение), который управляет пулом.

Режимы

Режим Описание Для кого
session Подключение к PG живёт всю сессию клиента Legacy-приложения, prepared statements
transaction Подключение возвращается в пул после каждой транзакции Большинство приложений — рекомендуется
statement Возврат после каждого SQL-запроса Простые read-only нагрузки

Конфигурация

INI
# pgbouncer.ini
[databases]
etl_db = host=127.0.0.1 port=5432 dbname=etl_kitchen

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt

pool_mode = transaction
default_pool_size = 20        # подключений к PG на БД
max_client_conn = 1000        # клиентских подключений
min_pool_size = 5
reserve_pool_size = 5

Мониторинг PgBouncer

SQL
-- Подключиться к PgBouncer admin
-- psql -p 6432 pgbouncer

SHOW POOLS;    -- состояние пулов
SHOW CLIENTS;  -- клиентские подключения
SHOW STATS;    -- статистика

PostgreSQL 14+ и встроенный пулинг

pg_prewarm и параметр max_connections + reserved_connections в PostgreSQL 17 упрощают ситуацию, но PgBouncer всё ещё лучше для >200 подключений.


Бэкапы

pg_dump — логический бэкап

Bash
# Полный дамп базы в custom-формат (сжатый, параллельный восстановление)
pg_dump -Fc -j4 -d etl_kitchen -f etl_kitchen.dump

# Только структура
pg_dump -s -d etl_kitchen -f schema.sql

# Только данные конкретной таблицы
pg_dump -t orders --data-only -d etl_kitchen -f orders_data.sql

# Восстановление
pg_restore -d etl_kitchen -j4 etl_kitchen.dump

pg_basebackup — физический бэкап

Bash
# Полная копия кластера (для PITR)
pg_basebackup -D /backup/base -Ft -z -P -X stream

# С WAL-архивированием для Point-in-Time Recovery
Метод Скорость PITR Гранулярность Размер
pg_dump Медленнее Нет Таблица/БД Меньше (только данные)
pg_basebackup Быстрее Да Весь кластер Больше (полная копия)

Попробуй сам

Посмотри статистику текущей базы данных.


Проверь себя


Источники