Как устроен сервер баз данных и как привести его в рабочее состояние
pg_ctlcluster и systemdpostgresql.conf, понимая контексты применения параметровpg_hba.confpsql и пользоваться метакомандамиPostgreSQL построен на процессах, а не на потоках. На каждое клиентское соединение операционная система создаёт отдельный процесс. Это решение объясняет и надёжность сервера, и стоимость соединения.
┌─────────────────────┐
клиент 1 ──────────▶│ backend процесс 1 │──┐
клиент 2 ──────────▶│ backend процесс 2 │──┤
клиент N ──────────▶│ backend процесс N │──┤
└─────────────────────┘ │
▼
postmaster ┌───────────────┐
(главный процесс, │ Shared Buffers│
принимает │ общая память │
соединения) └───────┬───────┘
│
фоновые процессы: ▼
background writer ──────────────▶ ┌─────────────┐
WAL writer ──────────────▶ │ файлы на │
checkpointer ──────────────▶ │ диске │
autovacuum launcher ──────────────▶ └─────────────┘
stats collector
max_connections нельзя ставить произвольно большим, и приложению нужен пул соединений. Открывать соединение на каждый HTTP-запрос — верный способ положить сервер.Shared Buffers — общая область памяти, через которую все процессы работают с данными. Запрос никогда не читает файл напрямую: страница сначала попадает в общий буфер, а изменения сначала пишутся в журнал (WAL), и только потом — в файлы данных. Отсюда правило: если сервер выключился внезапно, при старте PostgreSQL воспроизведёт журнал и восстановит согласованное состояние.
Четыре понятия, которые постоянно путают. В терминологии PostgreSQL они означают строго определённые вещи.
initdb.public.Сервер (машина)
└── Экземпляр PostgreSQL (порт 5432)
└── Кластер = /var/lib/postgresql/17/main
├── База postgres (служебная)
├── База template0 (эталон, не трогать)
├── База template1 (шаблон для новых баз)
└── База nevabit
├── Схема public
│ ├── Таблица users
│ └── Таблица posts
└── Схема reports
└── Представление monthly_activity
На одной машине можно запустить несколько экземпляров — разных версий или с разными настройками. Каждый займёт свой порт и свой каталог данных. В Debian это штатный сценарий, поддержанный инструментами.
cp у работающего сервера и нельзя открывать сторонними программами. Файлы внутри — не самостоятельные документы, а часть согласованного состояния, зависящего от журнала. Для копирования есть pg_dump и pg_basebackup; о них в разделе 6.Debian 13 (Trixie) содержит PostgreSQL 17 в основном репозитории, поэтому установка сводится к одной команде.
# Обновить список пакетов и установить сервер с клиентом
sudo apt update
sudo apt install postgresql postgresql-client
# Проверить, что установилось
psql --version
# psql (PostgreSQL) 17.x
Если нужна версия новее той, что в дистрибутиве, подключают официальный репозиторий проекта — PGDG:
# Репозиторий PostgreSQL Global Development Group
sudo apt install curl ca-certificates
sudo install -d /usr/share/postgresql-common/pgdg
sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \
--fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] \
https://apt.postgresql.org/pub/repos/apt trixie-pgdg main" \
| sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt update
sudo apt install postgresql-17
unattended-upgrades. PGDG нужен только тогда, когда требуется версия, которой в дистрибутиве ещё нет. Для учебных и большинства рабочих задач достаточно штатного пакета.Что установка сделала с системой:
postgres — от его имени работают все процессы сервера.initdb и создан кластер с именем main.postgres и роль суперпользователя postgres.localhost:5432 — снаружи недоступен.Debian раскладывает файлы иначе, чем это делает initdb по умолчанию: конфигурация отделена от данных.
| Путь | Что там |
|---|---|
/etc/postgresql/17/main/ | postgresql.conf, pg_hba.conf, pg_ident.conf |
/var/lib/postgresql/17/main/ | каталог данных: файлы таблиц, WAL, служебные каталоги |
/var/log/postgresql/ | журналы сервера |
/usr/lib/postgresql/17/bin/ | исполняемые файлы: postgres, initdb, pg_dump |
/var/run/postgresql/ | сокет и pid-файл |
SHOW config_file;, а не поиском по диску.В Debian есть свой слой управления кластерами — пакет postgresql-common. Он позволяет держать несколько версий и несколько кластеров одновременно.
# Список всех кластеров на машине
pg_lsclusters
# Ver Cluster Port Status Owner Data directory Log file
# 17 main 5432 online postgres /var/lib/postgresql/17/main /var/log/...
# Управление конкретным кластером: версия, имя, действие
sudo pg_ctlcluster 17 main start
sudo pg_ctlcluster 17 main stop
sudo pg_ctlcluster 17 main restart
sudo pg_ctlcluster 17 main reload # перечитать конфигурацию без разрыва соединений
# Создать второй кластер на другом порту
sudo pg_createcluster 17 test --port=5433 --start
Параллельно работает обычное управление через systemd:
sudo systemctl status postgresql@17-main
sudo systemctl restart postgresql@17-main
sudo systemctl enable postgresql@17-main # автозапуск
# postgresql.service — это обёртка, управляющая всеми кластерами сразу
sudo systemctl restart postgresql
restart и reload существенна. reload заставляет сервер перечитать конфигурацию, не разрывая соединений и не прерывая работу приложения. restart обрывает все соединения. На рабочем сервере всегда сначала пробуйте reload — большинство параметров этого достаточно.Если сервер не поднимается — смотреть нужно журнал, а не гадать:
sudo tail -n 50 /var/log/postgresql/postgresql-17-main.log
sudo journalctl -u postgresql@17-main -n 50 --no-pager
Основной файл конфигурации. Формат простой: параметр = значение, комментарии после #.
listen_addresses — на каких адресах слушать. 'localhost' по умолчанию, '*' — на всех интерфейсах.port — порт, по умолчанию 5432.max_connections — предел одновременных соединений. Каждое стоит памяти.shared_buffers — размер общего буферного кэша. Ориентир — 25% ОЗУ.effective_cache_size — подсказка планировщику, сколько памяти суммарно доступно под кэш (включая кэш ОС). Память не выделяет, влияет только на выбор плана. Ориентир — 50–75% ОЗУ.work_mem — память на одну операцию сортировки или хеширования. Выделяется на операцию, а не на соединение: сложный запрос может занять несколько порций.maintenance_work_mem — память под VACUUM, CREATE INDEX, ALTER TABLE.wal_level — объём информации в журнале: replica по умолчанию, logical для логической репликации.log_min_duration_statement — писать в журнал запросы дольше указанного времени в миллисекундах. Главный инструмент поиска медленных запросов.password_encryption — scram-sha-256 начиная с PostgreSQL 14.Не всякий параметр можно изменить на лету. У каждого есть контекст, определяющий, что нужно сделать для вступления изменений в силу.
| Контекст | Что требуется | Примеры |
|---|---|---|
postmaster | перезапуск сервера | shared_buffers, max_connections, listen_addresses, port |
sighup | reload | log_min_duration_statement, autovacuum |
superuser | изменение в сессии суперпользователем | log_statement |
user | изменение в своей сессии любым пользователем | work_mem, search_path |
internal | задаётся при сборке или initdb, изменить нельзя | block_size, lc_collate |
-- Узнать текущее значение и контекст параметра
SHOW shared_buffers;
SELECT name, setting, unit, context, source
FROM pg_settings
WHERE name IN ('shared_buffers', 'work_mem', 'max_connections');
-- Какие параметры изменены относительно умолчаний
SELECT name, setting, source
FROM pg_settings
WHERE source NOT IN ('default', 'override');
-- Где лежат файлы конфигурации
SHOW config_file;
SHOW hba_file;
SHOW data_directory;
postgresql.conf — базовый способ, файл под контролем администратора и системы конфигурации.conf.d/ — если в основном файле есть include_dir 'conf.d'. Удобно: свои настройки лежат отдельно от дистрибутивных и переживают обновление пакета.ALTER SYSTEM — команда SQL, пишет в postgresql.auto.conf. Этот файл читается последним и перекрывает всё остальное.-- Изменить параметр из SQL
ALTER SYSTEM SET log_min_duration_statement = '500ms';
SELECT pg_reload_conf();
-- Отменить своё изменение и вернуться к значению из postgresql.conf
ALTER SYSTEM RESET log_min_duration_statement;
SELECT pg_reload_conf();
postgresql.conf, перезапускает сервер, а значение не меняется — потому что тот же параметр когда-то задали через ALTER SYSTEM, и он лежит в postgresql.auto.conf. Столбец source в pg_settings сразу показывает, откуда взято действующее значение. Проверяйте его первым делом.HBA расшифровывается как Host-Based Authentication. Этот файл решает, кому разрешено подключаться и каким способом он должен доказать, что он — это он.
Формат строки — пять или шесть полей:
# ТИП БАЗА ПОЛЬЗОВАТЕЛЬ АДРЕС МЕТОД
local all postgres peer
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
host nevabit nevabit_app 10.0.0.0/24 scram-sha-256
hostssl nevabit nevabit_app 0.0.0.0/0 scram-sha-256
host all all 0.0.0.0/0 reject
local — через Unix-сокет; host — по TCP с шифрованием или без; hostssl — только с TLS; hostnossl — только без TLS.all.+имя_группы или all.local не указывается.| Метод | Как проверяет | Когда применять |
|---|---|---|
scram-sha-256 | пароль по протоколу SCRAM | основной метод для сетевых подключений |
peer | имя системного пользователя ОС | локальные подключения через сокет |
ident | внешняя служба ident | практически не используется |
md5 | устаревшее хеширование пароля | только для старых клиентов |
cert | клиентский TLS-сертификат | сервис-сервис без паролей |
trust | пускает без проверки | никогда вне изолированного стенда |
reject | отказывает всегда | явный запрет в конце файла |
all all перекрыло узкое. Порядок строк здесь — часть логики, а не оформление.Метод peer объясняет, почему сразу после установки работает такая команда:
# Переключиться на системного пользователя postgres и войти в psql
sudo -u postgres psql
Пароль не спрашивается: PostgreSQL спрашивает у ядра, от чьего имени пришло соединение через сокет, видит системного пользователя postgres и пускает его в роль с тем же именем.
pg_hba.conf достаточно reload — перезапуск не нужен. Проверить, какое правило сработало для действующих соединений, можно запросом к pg_hba_file_rules: он же покажет строки с синтаксическими ошибками до того, как вы их примените.-- Проверить файл на ошибки, не перезагружая конфигурацию
SELECT line_number, type, database, user_name, address, auth_method, error
FROM pg_hba_file_rules
WHERE error IS NOT NULL;
psql — штатный клиент командной строки. Он не только выполняет SQL, но и умеет исследовать структуру базы метакомандами, начинающимися с обратной косой черты.
# Подключение: пользователь, база, хост, порт
psql -U nevabit_app -d nevabit -h localhost -p 5432
# Строка подключения одним аргументом
psql "postgresql://nevabit_app@localhost:5432/nevabit"
# Выполнить один запрос и выйти
psql -U postgres -c "SELECT version();"
# Выполнить файл
psql -U nevabit_app -d nevabit -f socialnet_db.sql
\l — список баз данных\c имя_базы — переключиться на другую базу\dt — таблицы текущей схемы\d имя_таблицы — структура таблицы: столбцы, типы, индексы, ограничения\d+ имя_таблицы — то же плюс размер и описания\du — список ролей и их атрибутов\dn — список схем\di — индексы\x — расширенный вывод: строки печатаются по вертикали, спасает на широких таблицах\timing — показывать время выполнения каждого запроса\e — открыть текущий запрос в редакторе\i файл.sql — выполнить файл\conninfo — параметры текущего соединения\? — справка по метакомандам, \h SELECT — справка по синтаксису команды\q — выходСоздание рабочей базы и пользователя приложения — минимальный сценарий после установки:
-- От имени postgres
CREATE ROLE nevabit_app LOGIN PASSWORD 'смените_этот_пароль';
CREATE DATABASE nevabit OWNER nevabit_app ENCODING 'UTF8';
-- Проверка
\l
\du
ENCODING 'UTF8' и локаль ru_RU.UTF-8. Если создать базу с локалью C, сортировка русского текста пойдёт по кодам символов: «Ёж» окажется после «Яблока».Значения по умолчанию у PostgreSQL намеренно скромные — они рассчитаны на то, чтобы сервер запустился где угодно. На типичном VPS их нужно поднимать; на очень маленьком — следить, чтобы сервер не съел всю память.
Пример расчёта для машины 1 CPU / 1 ГБ ОЗУ — распространённая конфигурация недорогого VPS:
| Параметр | По умолчанию | Для 1 ГБ | Обоснование |
|---|---|---|---|
shared_buffers | 128MB | 256MB | 25% ОЗУ |
effective_cache_size | 4GB | 512MB | подсказка планировщику, память не занимает |
work_mem | 4MB | 4MB | умножается на число операций — повышать опасно |
maintenance_work_mem | 64MB | 64MB | разово при VACUUM и построении индексов |
max_connections | 100 | 40 | остальное закрывается пулом соединений |
max_worker_processes | 8 | 2 | одно ядро |
max_parallel_workers_per_gather | 2 | 0 | параллелизм на одном ядре только вредит |
work_mem. Параметр выделяется на каждую операцию сортировки или хеширования в каждом запросе. При work_mem = 64MB, сорока соединениях и трёх сортировках на запрос теоретический предел — почти 8 ГБ. Сервер уйдёт в swap или будет убит OOM-killer'ом.Настройки уровня операционной системы, без которых маленький сервер живёт хуже:
# Swap обязателен даже при быстром диске — как страховка от OOM
# Но обращаться к нему система должна неохотно
sudo sysctl -w vm.swappiness=10
echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf
# Посмотреть, сколько памяти реально занято
free -h
ps -o pid,rss,cmd -C postgres
transaction позволяет сотне клиентов приложения работать через десяток реальных соединений к базе. Это дешевле, чем увеличивать max_connections, и почти всегда быстрее.Свежеустановленный PostgreSQL закрыт разумно, но первые же шаги по «настройке доступа» обычно эту защиту снимают.
listen_addresses = '*' без необходимости. Если приложение на той же машине — оставьте localhost. Порт 5432, открытый в интернет, сканируется в первые же часы.trust для сетевых подключений. Метод trust пускает вообще без проверки. Единственное его законное применение — восстановление доступа, когда забыт пароль суперпользователя, и то временно.nevabit_app с правами только на свою базу; о разграничении прав — раздел 6.scram-sha-256. Проверьте password_encryption и убедитесь, что в pg_hba.conf нет md5.ufw с разрешёнными 22, 80 и 443; порт базы наружу не выставляется.hostssl вместо host, чтобы незашифрованное соединение просто не устанавливалось.postgres. После установки его нет: роль доступна только через peer. Задавать пароль стоит лишь тогда, когда он действительно нужен.# Проверить, что снаружи порт закрыт
sudo ss -tlnp | grep 5432
# LISTEN 127.0.0.1:5432 — хорошо
# LISTEN 0.0.0.0:5432 — открыт на всех интерфейсах, проверьте файрвол
sudo ufw status
host all all 0.0.0.0/0 trust, чтобы заработало» встречается в интернете постоянно и означает: любой, кто дотянулся до порта, получает права суперпользователя базы. Если подключение не работает — читайте журнал сервера, там написана точная причина отказа и номер сработавшей строки pg_hba.conf./etc/postgresql/17/main/, данные в /var/lib/postgresql/17/main/; в Docker и PGDG — иначеSHOW config_file, а не поиском по дискуreload перечитывает конфигурацию без разрыва соединений; restart обрывает всеreloadALTER SYSTEM пишет в postgresql.auto.conf и перекрывает postgresql.conf; источник виден в pg_settings.sourcepg_hba.conf побеждает первое подходящее правило — порядок строк является логикойwork_mem выделяется на каждую операцию, а не на соединение