Администрирование базы данных PostgreSQL для веб-приложения

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Администрирование базы данных PostgreSQL для веб-приложения
Сложная
постоянная поддержка
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Администрирование базы данных PostgreSQL для веб-приложения

PostgreSQL — не «поставил и забыл». По умолчанию он настроен консервативно для запуска на самом широком спектре железа. Без регулярного обслуживания: таблицы раздуваются от dead tuples, индексы фрагментируются, bloat занимает гигабайты, медленные запросы тянут всё приложение вниз. Системная администрация — это совокупность регулярных задач и постоянного мониторинга.

Начальный аудит инсталляции

Первое, что делается при подключении к новой базе:

-- Версия и конфигурация
SELECT version();
SHOW config_file;
SHOW data_directory;

-- Размер баз данных
SELECT datname,
       pg_size_pretty(pg_database_size(datname)) AS size
FROM pg_database
ORDER BY pg_database_size(datname) DESC;

-- Топ-10 таблиц по размеру с учётом bloat
SELECT schemaname,
       relname,
       pg_size_pretty(pg_total_relation_size(relid)) AS total,
       pg_size_pretty(pg_relation_size(relid))       AS table,
       pg_size_pretty(pg_indexes_size(relid))        AS indexes
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;

-- Таблицы с большим количеством dead tuples (кандидаты на VACUUM)
SELECT relname, n_dead_tup, n_live_tup,
       round(n_dead_tup::numeric / nullif(n_live_tup + n_dead_tup, 0) * 100, 1) AS dead_pct,
       last_autovacuum, last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 20;

VACUUM и ANALYZE

Автовакуум работает в фоне, но иногда его настроек недостаточно для высоконагруженных таблиц:

-- Ручной vacuum для конкретной таблицы
VACUUM (VERBOSE, ANALYZE) orders;

-- Для таблицы с огромным bloat — FULL (эксклюзивная блокировка!)
-- Выполнять в окно обслуживания
VACUUM FULL orders;

VACUUM FULL блокирует таблицу на всё время выполнения. Для продакшн без окна — используем pg_repack:

# Дефрагментация без блокировки
pg_repack -h localhost -U postgres -d mydb -t orders

Настройка автовакуума для активно обновляемых таблиц:

ALTER TABLE orders SET (
    autovacuum_vacuum_scale_factor = 0.01,  -- vacuum при 1% dead tuples (вместо 20%)
    autovacuum_analyze_scale_factor = 0.005,
    autovacuum_vacuum_cost_delay = 2        -- ms, агрессивнее по умолчанию
);

Управление индексами

-- Неиспользуемые индексы (расходуют место и замедляют INSERT/UPDATE)
SELECT schemaname, relname, indexrelname,
       idx_scan, pg_size_pretty(pg_relation_size(indexrelid)) AS idx_size
FROM pg_stat_user_indexes
WHERE idx_scan = 0
  AND indexrelname NOT LIKE '%_pkey'
ORDER BY pg_relation_size(indexrelid) DESC;

-- Дублирующиеся индексы
SELECT a.indexrelid::regclass AS index1,
       b.indexrelid::regclass AS index2,
       a.indrelid::regclass   AS table_name
FROM pg_index a
JOIN pg_index b ON a.indrelid = b.indrelid
               AND a.indexrelid < b.indexrelid
               AND a.indkey = b.indkey;

-- Создание индекса без блокировки записи
CREATE INDEX CONCURRENTLY idx_orders_user_id ON orders(user_id);

CONCURRENTLY обязателен на продакшне — стандартный CREATE INDEX блокирует запись в таблицу.

Резервное копирование

# pg_dump — логический бэкап конкретной базы
pg_dump -h localhost -U postgres -Fc -Z 9 mydb > /backups/mydb_$(date +%Y%m%d_%H%M).dump

# Восстановление
pg_restore -h localhost -U postgres -d mydb_restored /backups/mydb_20250101_0300.dump

# pg_basebackup — физический бэкап для PITR
pg_basebackup -h localhost -U replication -D /backups/base -Ft -z -P

Расписание через cron:

# /etc/cron.d/postgres-backup
0 3 * * * postgres pg_dump -Fc mydb | gzip > /backups/mydb_$(date +\%Y\%m\%d).dump.gz
# Ротация: хранить 30 дней
0 4 * * * find /backups/ -name "*.dump.gz" -mtime +30 -delete

Бэкапы нужно тестировать восстановлением — хотя бы раз в месяц запускать pg_restore в изолированное окружение.

Репликация (streaming replication)

# postgresql.conf на primary
wal_level = replica
max_wal_senders = 3
wal_keep_size = 1GB

# pg_hba.conf
host replication replication 10.0.0.2/32 scram-sha-256
# Инициализация реплики
pg_basebackup -h 10.0.0.1 -U replication -D /var/lib/postgresql/14/main \
  -P -Xs -R
# -R создаёт standby.signal и recovery.conf автоматически

Мониторинг лага репликации:

-- На primary
SELECT client_addr,
       state,
       sent_lsn,
       write_lsn,
       flush_lsn,
       replay_lsn,
       (sent_lsn - replay_lsn) AS replication_lag_bytes
FROM pg_stat_replication;

Управление соединениями: PgBouncer

PostgreSQL плохо масштабируется при тысячах одновременных соединений — каждое занимает ~5–10 МБ памяти. PgBouncer решает это через пулинг:

# /etc/pgbouncer/pgbouncer.ini
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb

[pgbouncer]
pool_mode        = transaction  # transaction pooling — наиболее эффективный
max_client_conn  = 1000
default_pool_size = 25
reserve_pool_size = 5
server_idle_timeout = 600

Приложение подключается к PgBouncer на порту 6432, не напрямую к PostgreSQL.

Регулярные задачи

Задача Частота Инструмент
pg_dump бэкап Ежедневно cron + pg_dump
VACUUM ANALYZE Автоматически autovacuum
Проверка bloat Еженедельно pg_repack
Ротация логов Ежедневно logrotate
Проверка реплики Постоянно мониторинг
Обновление статистики Автоматически autovacuum
Архивирование WAL Постоянно archive_command

Роли и права

-- Принцип минимальных привилегий
CREATE ROLE app_user LOGIN PASSWORD 'strong_password';
GRANT CONNECT ON DATABASE mydb 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;

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

-- Read-only роль для аналитики/репорт-серверов
CREATE ROLE readonly_user LOGIN PASSWORD 'password';
GRANT CONNECT ON DATABASE mydb TO readonly_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_user;

Обновление мажорной версии

PostgreSQL не обновляется через apt upgrade между мажорными версиями. Используется pg_upgrade:

# Пример: 14 -> 16
pg_upgrade \
  -b /usr/lib/postgresql/14/bin \
  -B /usr/lib/postgresql/16/bin \
  -d /var/lib/postgresql/14/main \
  -D /var/lib/postgresql/16/main \
  --link  # hard links вместо копирования — быстрее, но 14 нельзя запустить после

Для нулевого downtime — logical replication между старой и новой версией, переключение при равенстве LSN.