Потоковая репликация PostgreSQL 18 со слотами репликации#
Пошаговое руководство по настройке физической потоковой репликации (physical streaming replication) в асинхронном режиме с обязательным использованием слотов репликации.
Используется штатный кластер 18/main, который создаётся автоматически при
установке пакета postgresql-18. Никаких дополнительных кластеров, каталогов данных,
systemd-юнитов и правок сервисов не требуется.
Схема: один master (primary) и произвольное число реплик (standby), читающих WAL напрямую с master. Слот репликации гарантирует, что master не удалит WAL-сегменты, которые ещё нужны конкретной реплике.
Все команды рассчитаны на чистую систему Debian/Ubuntu без предустановленного PostgreSQL.
Обозначения в тексте: блоки bash выполняются в оболочке на указанном узле,
блоки sql — в интерактивном клиенте psql от имени суперпользователя
(psql -U postgres), уже после подключения к нужному серверу.
Штатная раскладка кластера#
После установки пакета postgresql-18 на Debian/Ubuntu автоматически создаётся
кластер 18/main, которым управляет postgresql-common:
Что |
Где |
|---|---|
Каталог данных (PGDATA) |
|
Конфиги |
|
Каталог для доп. настроек |
|
Лог |
|
systemd-юнит |
|
Утилиты управления |
|
Важная особенность: postgresql.conf и pg_hba.conf лежат вне каталога данных
(в /etc/postgresql/18/main/), а postmaster запускается с
-c config_file=/etc/postgresql/18/main/postgresql.conf. Поэтому базовый бэкап
не затрагивает конфиги реплики — их не нужно восстанавливать после pg_basebackup.
Переменные, используемые в инструкции#
Перед началом подставьте свои значения — далее по тексту используются именно они:
# --- пути штатного кластера ---
PGDATA=/var/lib/postgresql/18/main # каталог данных
PGCONF=/etc/postgresql/18/main # каталог конфигов
CONFD=/etc/postgresql/18/main/conf.d # каталог доп. настроек
PGBIN=/usr/lib/postgresql/18/bin # бинарники PostgreSQL 18
UNIT=postgresql@18-main.service # штатный systemd-юнит кластера
PGPASS=/var/lib/postgresql/.pgpass # файл паролей (домашний каталог postgres)
# --- сеть ---
MASTER_IP=192.0.2.10 # адрес master
REPLICA_IP=192.0.2.11 # адрес ЭТОЙ реплики (на каждой свой)
SUBNET=192.0.2.0/24 # подсеть, из которой разрешены подключения
# --- репликация ---
REPL_USER=replicator # пользователь БД для репликации
REPL_PASS=CHANGE_ME_strong_password # пароль пользователя репликации
SLOT=replica1_slot # имя слота ЭТОЙ реплики (у каждой своё)
APP_NAME=replica1 # application_name ЭТОЙ реплики
1. Установка PostgreSQL 18#
Выполняется на всех узлах (и master, и реплики).
1.1. Подключить репозиторий PGDG#
sudo apt update
sudo apt install -y wget ca-certificates
# ключ репозитория
sudo install -d -m 0755 /usr/share/keyrings
sudo wget -q -O /usr/share/keyrings/pgdg.asc \
https://www.postgresql.org/media/keys/ACCC4CF8.asc
sudo chmod 0644 /usr/share/keyrings/pgdg.asc
# сам репозиторий
echo "deb [signed-by=/usr/share/keyrings/pgdg.asc] https://apt.postgresql.org/pub/repos/apt $(. /etc/os-release; echo $VERSION_CODENAME)-pgdg main" \
| sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt update
В Debian 13 (trixie) пакета
postgresql-18в основных репозиториях нет — он есть только в PGDG. Если репозиторий PGDG уже подключён, шаг можно пропустить.
1.2. Установить пакеты#
sudo apt install -y postgresql-18 postgresql-client-18
При установке автоматически создаётся и запускается кластер 18/main.
Проверка:
pg_lsclusters
Ожидаемо:
Ver Cluster Port Status Owner Data directory Log file
18 main 5432 online postgres /var/lib/postgresql/18/main /var/log/postgresql/postgresql-18-main.log
Проверка версии:
psql --version # psql (PostgreSQL) 18.x
Важно. Пакет сразу поднимает кластер на порту 5432 и слушает только
localhost. Никаких дополнительных кластеров создавать не нужно — вся дальнейшая настройка делается в этом же штатном кластере.Если вы хотите использовать другой каталог данных, создайте отдельный кластер:
sudo pg_createcluster 18 <имя> --datadir=/путь/к/данными далее по тексту замените18/mainна18/<имя>и путьPGDATA.
2. Настройка MASTER#
2.1. Параметры репликации#
Настройки кладём в отдельный файл в каталоге conf.d — так штатный postgresql.conf
остаётся нетронутым, а настройки переживают обновление пакета. Каталог conf.d
подключается в postgresql.conf директивой include_dir = 'conf.d' (в поставке
Debian она уже присутствует).
sudo tee $CONFD/replication.conf >/dev/null <<'EOF'
# -----------------------------------------------------------------------------
# РЕПЛИКАЦИЯ (physical streaming replication)
# -----------------------------------------------------------------------------
listen_addresses = '*' # по умолчанию localhost — репликам нужен TCP
wal_level = replica # WAL содержит всё необходимое для репликации
max_wal_senders = 10 # макс. число одновременных процессов walsender
max_replication_slots = 10 # макс. число слотов репликации
hot_standby = on # разрешить чтение на резервном сервере
hot_standby_feedback = on # реплика сообщает master'у о своих запросах
wal_keep_size = 512MB # страховка, если слот придётся пересоздать
max_slot_wal_keep_size = 2GB # защита диска от «зависшего» слота
# Синхронную репликацию НЕ включаем (режим асинхронный):
# synchronous_standby_names = 'ANY 1 (replica1, replica2)'
EOF
sudo chown postgres:postgres $CONFD/replication.conf
sudo chmod 0644 $CONFD/replication.conf
Ключевые параметры:
Параметр |
Зачем |
|---|---|
|
единственный параметр, который обязательно нужно поменять: по умолчанию |
|
уровень WAL, при котором возможна потоковая репликация |
|
без него не запустятся процессы |
|
обязателен для слотов репликации |
|
разрешает выполнять read-only запросы на реплике |
|
реплика сообщает master’у о своих долгих запросах |
|
сколько WAL держать дополнительно к слотам |
|
аварийный предел: слот не сможет занять весь диск |
Примечание. В PostgreSQL 18 значения
wal_level = replica,max_wal_senders = 10,max_replication_slots = 10иhot_standby = onявляются значениями по умолчанию. В файле они указаны явно — чтобы настройка была самодокументируемой и не зависела от изменения умолчаний в будущих версиях.
2.2. Правила доступа в pg_hba.conf#
sudo tee -a $PGCONF/pg_hba.conf >/dev/null <<EOF
# --- Физическая репликация (streaming) с резервных серверов ---
host replication $REPL_USER $SUBNET scram-sha-256
EOF
Тип подключения обязан быть
replication. Если указатьall,pg_basebackupи walreceiver получат ошибкубаза данных "replication" не существует.Строку нужно добавить на master для каждой реплики — либо одной строкой на всю подсеть, как в примере выше.
2.3. Перезапустить кластер#
listen_addresses — параметр уровня postmaster, поэтому требуется именно перезапуск,
а не reload:
sudo systemctl restart postgresql@18-main.service
Эквивалентный вариант «в стиле Debian»:
sudo pg_ctlcluster 18 main restart
Проверка состояния:
pg_lsclusters
2.4. Проверить, что параметры применились#
SELECT name, setting
FROM pg_settings
WHERE name IN ('data_directory', 'listen_addresses', 'wal_level', 'max_wal_senders',
'max_replication_slots', 'hot_standby', 'hot_standby_feedback',
'wal_keep_size', 'max_slot_wal_keep_size')
ORDER BY name;
Ожидаемо:
data_directory | /var/lib/postgresql/18/main
hot_standby | on
hot_standby_feedback | on
listen_addresses | *
max_replication_slots | 10
max_slot_wal_keep_size| 2048
max_wal_senders | 10
wal_keep_size | 512
wal_level | replica
Проверить, что pg_hba.conf прочитан без ошибок (столбец error должен быть пустым):
SELECT line_number, type, database, user_name, address, auth_method, error
FROM pg_hba_file_rules
ORDER BY line_number;
2.5. Создать пользователя репликации#
ALTER ROLE postgres WITH PASSWORD 'CHANGE_ME_postgres_password';
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'CHANGE_ME_strong_password';
Проверка:
SELECT rolname, rolsuper, rolreplication, rolcanlogin
FROM pg_roles
WHERE rolname IN ('postgres', 'replicator');
2.6. Создать слоты репликации#
Для каждой реплики — свой слот. Имя слота должно совпадать с SLOT
в настройках соответствующей реплики.
SELECT pg_create_physical_replication_slot('replica1_slot');
SELECT pg_create_physical_replication_slot('replica2_slot');
Проверка (пока active = f, restart_lsn пустой — реплики ещё не подключились):
SELECT slot_name, slot_type, active, restart_lsn
FROM pg_replication_slots
ORDER BY slot_name;
MASTER готов. Дальше каждую реплику настраиваем одинаково, меняя только
REPLICA_IP, SLOT и APP_NAME.
Проверка доступности репликационного протокола с узла реплики выполняется в разделе 3 (шаг 3.2) — после того как на реплике создан файл паролей.
3. Настройка РЕПЛИКИ#
Выполняется на каждой реплике.
3.1. Создать .pgpass для аутентификации на master#
Чтобы не хранить пароль открытым текстом в конфигах и не передавать его
в командной строке, используем стандартный файл паролей libpq. Его читают
и pg_basebackup, и walreceiver.
sudo -u postgres tee $PGPASS >/dev/null <<EOF
# host:port:database:user:password
# Поле database = *: физическая репликация подключается к псевдо-БД "replication",
# поэтому это поле надёжнее не ограничивать. host/port/user заданы точно.
$MASTER_IP:5432:*:$REPL_USER:$REPL_PASS
EOF
sudo chown postgres:postgres $PGPASS
sudo chmod 0600 $PGPASS
sudo ls -l $PGPASS # ожидаем -rw------- postgres postgres
Формат строки — host:port:database:user:password. Если пароль содержит :
или \, их нужно экранировать обратным слешем.
Требования libpq к файлу паролей: владелец — тот пользователь, от которого запущен процесс (
postgres), права строго0600. Если права шире, файл молча игнорируется и подключение падает с ошибкой аутентификации.
$PGPASS— это~postgres/.pgpass, то есть/var/lib/postgresql/.pgpass(домашний каталог пользователяpostgresв Debian). Файл можно положить и в другое место — тогда путь задаётся явно:passfile=вprimary_conninfo(шаг 3.7) иPGPASSFILEдляpg_basebackup(шаг 3.6). Именно так сделано ниже, чтобы не зависеть от переменнойHOMEпроцесса postmaster.
3.2. Проверить доступ к master#
Прежде чем ломать существующий кластер, убеждаемся, что реплика умеет подключиться к master с правами репликации. Пароль нигде не вводится — он берётся из созданного файла:
sudo -u postgres env PGPASSFILE="$PGPASS" \
psql "host=$MASTER_IP port=5432 user=$REPL_USER dbname=replication replication=true" \
-tAc "IDENTIFY_SYSTEM"
Ожидаемый ответ — systemid | timeline | xlogpos | dbname, например:
7685292910932688140|1|0/17645F8|
Для физической репликации обязательно
replication=true. Если указатьreplication=database, сервер попытается открыть реальную БД с именемreplicationи вернётбаза данных "replication" не существует.
Если подключение не прошло — дальше идти нет смысла: проверьте правила
в pg_hba.conf на master (шаг 2.2), владельца и права $PGPASS.
3.3. Файл настроек в conf.d#
На реплике из параметров репликации реально нужен только
hot_standby_feedback = on — остальное уже включено умолчаниями.
sudo tee $CONFD/replication.conf >/dev/null <<'EOF'
# -----------------------------------------------------------------------------
# РЕПЛИКАЦИЯ (physical streaming replication)
# -----------------------------------------------------------------------------
listen_addresses = '*' # чтобы реплику можно было читать по сети
hot_standby = on # разрешить read-only запросы
hot_standby_feedback = on # не отменять длинные SELECT на реплике
wal_level = replica
EOF
sudo chown postgres:postgres $CONFD/replication.conf
sudo chmod 0644 $CONFD/replication.conf
Если реплика не должна принимать клиентские подключения,
listen_addressesможно не менять — оставитьlocalhost.
3.4. Остановить кластер#
sudo systemctl stop postgresql@18-main.service
Проверка:
pg_lsclusters # статус должен стать down
3.5. Очистить каталог данных#
pg_basebackup требует, чтобы целевой каталог был пустым. Каталог данных штатного
кластера удаляем целиком, но конфиги в /etc/postgresql/18/main/ не трогаем —
они лежат отдельно и останутся на месте.
sudo rm -rf $PGDATA
Удаляем именно
$PGDATA(/var/lib/postgresql/18/main), а не/var/lib/postgresql/18. Родительский каталог нужен, и его права должны остаться стандартными (0755, владелецpostgres) — иначеpg_lsclustersперестанет определять владельца кластера.
3.6. Снять базовый бэкап с master#
sudo -u postgres env PGPASSFILE="$PGPASS" \
$PGBIN/pg_basebackup \
--host=$MASTER_IP \
--port=5432 \
--username=$REPL_USER \
--pgdata=$PGDATA \
--format=plain \
--wal-method=stream \
--checkpoint=fast \
--slot=$SLOT \
--progress --verbose
Разбор ключей:
Ключ |
Смысл |
|---|---|
|
куда положить копию (штатный каталог данных) |
|
обычная копия каталога (не tar) |
|
WAL, накопившийся за время копирования, льётся параллельно |
|
принудительный немедленный checkpoint (быстрее старт) |
|
использовать слот репликации, чтобы master не удалил нужный WAL |
|
показывать прогресс |
Пароль не передаётся ни в командной строке, ни через
PGPASSWORD— он берётся из файла, указанного вPGPASSFILE. Это и есть продакшн-вариант: пароля нет ни в аргументах процесса (видны вps), ни в истории команд.Ключ
-Rздесь не используется намеренно: он прописываетprimary_conninfoавтоматически, но без явногоpassfile. Подключение настраивается явно на следующем шаге.
3.7. Объявить сервер резервным#
Два обязательных элемента: файл-маркер standby.signal и параметры подключения
к master в postgresql.auto.conf.
# 1) маркер: сервер стартует в режиме восстановления (hot standby)
sudo -u postgres touch $PGDATA/standby.signal
# 2) подключение к master + привязка к слоту репликации
sudo -u postgres tee -a $PGDATA/postgresql.auto.conf >/dev/null <<EOF
# --- настройки реплики ---
primary_conninfo = 'host=$MASTER_IP port=5432 user=$REPL_USER passfile=$PGPASS application_name=$APP_NAME'
primary_slot_name = '$SLOT'
EOF
Пароля в
primary_conninfoнет — аутентификация идёт черезpassfile=$PGPASS. Параметрpassfileуказан явно, а не передан через~/.pgpassпо умолчанию, потому что переменнаяHOMEв окружении процесса postmaster может быть не задана.Альтернатива — держать пароль прямо в
primary_conninfo(password=...). Технически это тоже допустимо:postgresql.auto.confимеет режим0600и читается только пользователемpostgres. Но такой пароль попадает в дампы конфигурации, вpg_settingsи в вывод диагностических команд, поэтому вариант с.pgpassпредпочтительнее.
postgresql.auto.conf — единственный конфиг, который живёт внутри PGDATA: он
не затирается при обновлении конфигов в /etc и персональный для каждого узла.
Именно здесь pg_basebackup -R хранит primary_conninfo.
application_name задавать полезно: под этим именем реплика видна в
pg_stat_replication на master, и это же имя используется в
synchronous_standby_names при включении синхронного режима.
3.8. Запустить кластер#
sudo systemctl start postgresql@18-main.service
Проверка:
pg_lsclusters
Ожидаемо — статус online,recovery:
Ver Cluster Port Status Owner Data directory Log file
18 main 5432 online,recovery postgres /var/lib/postgresql/18/main /var/log/postgresql/postgresql-18-main.log
3.9. Быстрая локальная проверка#
SELECT pg_is_in_recovery(); -- -> t
SELECT status, sender_host, sender_port, slot_name
FROM pg_stat_wal_receiver;
Ожидаемо:
status | streaming
sender_host | 192.0.2.10
sender_port | 5432
slot_name | replica1_slot
Повторите раздел 3 для каждой следующей реплики, задав ей свой
SLOT и APP_NAME, и не забудьте создать под неё слот на master (шаг 2.6)
и добавить её адрес в pg_hba.conf master (шаг 2.2).
4. Проверка, что всё работает#
4.1. На master: видим все реплики#
SELECT pid, usename, application_name, client_addr, state,
sync_state, sent_lsn, replay_lsn,
pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag_bytes
FROM pg_stat_replication
ORDER BY application_name;
Ожидаемо — по строке на каждую реплику со state = streaming,
sync_state = async и лагом 0.
4.2. На master: слоты активны#
SELECT slot_name, slot_type, active, restart_lsn,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots
ORDER BY slot_name;
Ожидаемо: все слоты active = t, retained_wal = 0 bytes.
4.3. Сквозная проверка репликации данных#
На master:
CREATE TABLE repl_check (id serial PRIMARY KEY,
note text,
created_at timestamptz DEFAULT now());
INSERT INTO repl_check (note) SELECT 'row-' || g FROM generate_series(1, 5) g;
SELECT pg_switch_wal();
На каждой реплике:
SELECT * FROM repl_check ORDER BY id;
Должны появиться те же 5 строк.
4.4. На реплике: запись запрещена#
INSERT INTO repl_check(note) VALUES ('should-fail');
Ожидаемая ошибка:
ОШИБКА: в транзакции в режиме "только чтение" нельзя выполнить INSERT
4.5. Проверка, что слот реально удерживает WAL#
Самый показательный тест: останавливаем реплику, пишем данные на master, убеждаемся, что слот удерживает WAL, поднимаем реплику — она догоняет.
# на реплике
sudo systemctl stop postgresql@18-main.service
На master пишем данные, пока реплика выключена:
INSERT INTO repl_check (note)
SELECT 'while-replica-down-' || g FROM generate_series(1, 3) g;
SELECT pg_switch_wal();
На master смотрим состояние слота — он неактивен, но WAL удерживается:
SELECT slot_name, active, restart_lsn,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots
ORDER BY slot_name;
Ожидаемо, например:
replica1_slot | f | 0/504F918 | 16 MB <- реплика выключена, WAL копится
replica2_slot | t | 0/6000000 | 0 bytes
Поднимаем реплику обратно:
sudo systemctl start postgresql@18-main.service
На реплике проверяем, что она догнала:
SELECT count(*) FROM repl_check; -- -> 8
Данные, записанные пока реплика была выключена, доехали — слот работает.
4.6. Убрать тестовые данные#
На master:
DROP TABLE IF EXISTS repl_check;
5. Эксплуатация#
5.1. Мониторинг отставания#
На master:
SELECT application_name, client_addr, state, sync_state,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes,
replay_lag
FROM pg_stat_replication
ORDER BY application_name;
На реплике:
SELECT status, sender_host, slot_name,
pg_last_wal_replay_lsn() AS replay_lsn,
now() - pg_last_xact_replay_timestamp() AS replay_delay
FROM pg_stat_wal_receiver;
Признаки проблем:
Симптом |
Вероятная причина |
|---|---|
|
реплика не подключилась — смотрите |
|
реплика отстала или слот «осиротел», WAL копится |
|
walreceiver не запущен: проверьте |
слот |
реплика подключается без слота либо с другим слотом |
5.2. Полезные команды управления кластером#
pg_lsclusters # список кластеров и их статус
sudo pg_ctlcluster 18 main restart # перезапуск
sudo pg_ctlcluster 18 main reload # перечитать конфиги без перезапуска
sudo systemctl status postgresql@18-main.service
sudo tail -f /var/log/postgresql/postgresql-18-main.log
5.3. Добавить новую реплику#
На master создать слот:
SELECT pg_create_physical_replication_slot('replica3_slot');
Добавить адрес новой реплики в
pg_hba.confmaster, затем:SELECT pg_reload_conf();
На новой машине выполнить раздел 3, задав
SLOT=replica3_slotи свойAPP_NAME.
5.4. Пересоздать «сломанную» реплику#
Самое частое — слот инвалидирован (переполнение max_slot_wal_keep_size),
и реплика просит уже удалённый WAL.
На master:
SELECT pg_drop_replication_slot('replica1_slot');
SELECT pg_create_physical_replication_slot('replica1_slot');
На реплике: остановить кластер и заново выполнить шаги 3.4–3.8
(снять новый базовый бэкап в очищенный PGDATA).
5.5. Promote реплики (ручной failover)#
На реплике, которую делаем новым master:
sudo pg_ctlcluster 18 main stop
sudo pg_ctlcluster 18 main promote
sudo pg_ctlcluster 18 main start
SELECT pg_is_in_recovery(); -- -> f
После этого остальные реплики нужно перевести на нового master: изменить
primary_conninfo в их postgresql.auto.conf, создать на новом master слоты
под них и перезапустить реплики.
5.6. Включить синхронную репликацию (опционально)#
На master в $CONFD/replication.conf:
synchronous_standby_names = 'ANY 1 (replica1, replica2)'
Затем:
sudo pg_ctlcluster 18 main reload
SELECT pg_reload_conf();
Теперь COMMIT на master будет ждать подтверждения минимум от одной реплики.
Имена в списке должны совпадать с application_name реплик.
6. Типовые ошибки и их решение#
Ошибка |
Причина |
Решение |
|---|---|---|
|
на master |
шаги 2.1 и 2.2, перезапуск кластера |
|
в |
добавить |
|
каталог данных не очищен |
остановить кластер и удалить |
|
слот занят другим процессом |
погасить старый walreceiver либо пересоздать слот |
реплика не стартует: отсутствует |
не создан маркер режима восстановления |
|
|
слот отсутствовал или инвалидирован |
пересоздать слот и снять новый базовый бэкап |
реплика отвергает SELECT-запросы |
|
поставить |
|
изменены права |
вернуть |
изменения в |
|
проверить порядок директив |
|
у файла неверный владелец или права (libpq молча игнорирует такой файл) |
|
в логе |
права на файл паролей шире |
|
|
не совпало поле |
использовать в |
Проверить, что файл паролей реально работает, можно так (пароль нигде не вводится):
sudo -u postgres env PGPASSFILE="$PGPASS" \
psql "host=$MASTER_IP port=5432 user=$REPL_USER dbname=replication replication=true" \
-tAc "IDENTIFY_SYSTEM"
Если подключение прошло — .pgpass настроен верно. Если появилась ошибка
аутентификации, проверьте владельца и права файла.
Проверить, что пароля нет в конфиге реплики:
sudo grep -c 'password=' $PGDATA/postgresql.auto.conf # ожидаем 0
Проверить, что сервер видит актуальные настройки:
SELECT name, setting, pending_restart
FROM pg_settings
WHERE name IN ('listen_addresses', 'wal_level', 'max_wal_senders',
'max_replication_slots', 'hot_standby');
pending_restart = true означает, что для применения параметра нужен перезапуск.
7. Приложение А. Итоговые конфиги#
/etc/postgresql/18/main/conf.d/replication.conf (master)#
listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
hot_standby = on
hot_standby_feedback = on
wal_keep_size = 512MB
max_slot_wal_keep_size = 2GB
/etc/postgresql/18/main/pg_hba.conf (добавленные строки на master)#
# --- Физическая репликация (streaming) с резервных серверов ---
host replication replicator 192.0.2.0/24 scram-sha-256
/var/lib/postgresql/18/main/postgresql.auto.conf (только на репликах)#
# --- настройки реплики ---
primary_conninfo = 'host=192.0.2.10 port=5432 user=replicator passfile=/var/lib/postgresql/.pgpass application_name=replica1'
primary_slot_name = 'replica1_slot'
/var/lib/postgresql/.pgpass (только на репликах)#
# host:port:database:user:password
192.0.2.10:5432:*:replicator:CHANGE_ME_strong_password
Владелец — postgres, права строго 0600.
/var/lib/postgresql/18/main/standby.signal (только на репликах)#
Пустой файл-маркер.
8. Приложение Б. Краткая шпаргалка#
# ================= НА ВСЕХ УЗЛАХ: установка =================
sudo apt update
sudo install -d -m 0755 /usr/share/keyrings
sudo wget -q -O /usr/share/keyrings/pgdg.asc https://www.postgresql.org/media/keys/ACCC4CF8.asc
echo "deb [signed-by=/usr/share/keyrings/pgdg.asc] https://apt.postgresql.org/pub/repos/apt $(. /etc/os-release; echo $VERSION_CODENAME)-pgdg main" \
| sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt update
sudo apt install -y postgresql-18 postgresql-client-18
pg_lsclusters # кластер 18/main создан и online
# ================= MASTER =================
CONFD=/etc/postgresql/18/main/conf.d
PGCONF=/etc/postgresql/18/main
# conf.d/replication.conf: listen_addresses='*' + wal_level/max_wal_senders/
# max_replication_slots/hot_standby/wal_keep_size
# pg_hba.conf: host replication replicator <subnet> scram-sha-256
sudo systemctl restart postgresql@18-main.service
# далее в psql:
# CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD '...';
# SELECT pg_create_physical_replication_slot('replica1_slot');
# SELECT pg_create_physical_replication_slot('replica2_slot');
# ================= РЕПЛИКА (для каждой своя SLOT / APP_NAME) =================
PGDATA=/var/lib/postgresql/18/main
PGPASS=/var/lib/postgresql/.pgpass
SLOT=replica1_slot
APP_NAME=replica1
MASTER_IP=192.0.2.10
sudo systemctl stop postgresql@18-main.service
sudo rm -rf $PGDATA
# файл паролей вместо пароля в командной строке
sudo -u postgres tee $PGPASS >/dev/null <<EOF
$MASTER_IP:5432:*:replicator:$REPL_PASS
EOF
sudo chown postgres:postgres $PGPASS
sudo chmod 0600 $PGPASS
sudo -u postgres env PGPASSFILE="$PGPASS" \
/usr/lib/postgresql/18/bin/pg_basebackup -h $MASTER_IP -p 5432 -U replicator \
-D $PGDATA -Fp -Xs --checkpoint=fast -S $SLOT -P
sudo -u postgres touch $PGDATA/standby.signal
sudo -u postgres tee -a $PGDATA/postgresql.auto.conf >/dev/null <<EOF
primary_conninfo = 'host=$MASTER_IP port=5432 user=replicator passfile=$PGPASS application_name=$APP_NAME'
primary_slot_name = '$SLOT'
EOF
sudo systemctl start postgresql@18-main.service
pg_lsclusters # ожидаем статус online,recovery
9. Ожидаемый результат#
Проверка |
master |
реплика |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
— |
|
|
— |
|
|
|
— |
|
— |
|
лаг реплея |
— |
|
|
1 |
1 |
|
|
|
запись на реплике |
разрешена |
запрещена ( |
Если все пункты совпали — репликация настроена корректно: данные с master попадают на реплики, слоты удерживают WAL при отключении реплики, а после перезапуска master реплики переподключаются автоматически.