Streaming replication в PostgreSQL кажется простой: подняли standby, включили репликацию, и оно «как-то» работает. Проблемы обычно приходят позже — когда реплика отстаёт, сеть моргнула, бэкап-сервер завис, или кто-то забыл, что WAL нельзя хранить бесконечно. Итог бывает двух типов: либо standby перестаёт догонять и требует пересоздания, либо primary уходит в WAL disk full и начинает ошибиться на записи из‑за переполнения диска.
Ниже разложу по полочкам две ключевые техники удержания WAL для реплик: параметр wal_keep_size и replication slots. Покажу, как выставлять лимиты (max_slot_wal_keep_size), как читать pg_stat_replication и pg_replication_slots, и что делать, если место уже заканчивается.
Почему «пропадают» WAL и что значит WAL disk full
WAL (Write-Ahead Log) — это сегменты журнала, которые primary генерирует при любых изменениях данных. Реплика в streaming replication подтягивает эти записи и применяет у себя. Но PostgreSQL не хранит WAL вечно: он удаляет старые сегменты, когда считает их больше не нужными (для восстановления после сбоя и для всех потребителей WAL).
Если standby долго не забирает WAL (лаг, сеть, реплика выключена), у primary возникает дилемма:
- либо удалить старый WAL и «сломать» реплику (ей больше неоткуда догонять);
- либо удерживать WAL дольше — и рискнуть переполнить диск.
WAL disk full — это ситуация, когда каталог pg_wal разрастается так, что заполняет файловую систему. После этого база начинает получать ошибки записи, растёт риск сбоев фоновых процессов, а под нагрузкой инцидент развивается быстро: любые операции, генерирующие WAL, упираются в ENOSPC.
Если вы включаете механизм, который заставляет PostgreSQL удерживать WAL (slots или большой
wal_keep_size), мониторинг ростаpg_walи отставания реплик обязателен. Иначе проблема «реплика отстала» превратится в «primary лёг».
wal_keep_size: простой буфер для кратковременного отставания
wal_keep_size — это «подушка безопасности»: PostgreSQL старается держать минимум указанного объёма WAL-сегментов, даже если они уже не нужны для crash recovery. Это помогает коротким отставаниям реплики, когда она вскоре догонит.
Что важно понимать про wal_keep_size
- Это не гарантия «хватит на N часов». Это объём (МБ/ГБ), а скорость генерации WAL зависит от нагрузки.
- Это минимальный объём удержания, но фактический объём WAL может быть больше из‑за других факторов (архивация, чекпоинты, слоты).
wal_keep_sizeне привязан к конкретной реплике: это общий параметр инстанса.
Типовой подход: выбрать значение, которое покрывает ожидаемое кратковременное окно «реплика отвалилась/перезапускается/есть сетевые потери» при пиковом профиле записи.
Как прикинуть значение на практике
В идеале вы знаете среднюю и пиковую скорость генерации WAL (метрики, статистика). В «полевых» условиях достаточно прикинуть: сколько времени реплика может быть недоступна без инцидента и сколько WAL вы генерируете в самые тяжёлые 10–15 минут. Подушка должна пережить именно пик, а не среднее.
Если база живёт на VPS/VDS, имеет смысл сразу закладывать диск под «плохой день» (пики записи плюс удержание WAL плюс место под VACUUM и временные файлы). Под это обычно удобнее VDS, где проще управлять диском, IOPS и мониторингом.
Replication slots: гарантия, что WAL не удалится «раньше времени»
Replication slots решают другую задачу: это механизм, который говорит primary «не удаляй WAL, пока конкретный потребитель не подтвердит, что забрал нужные позиции». Для streaming replication используются physical slots.
Плюс слотов: реплика не «сломается» из‑за того, что primary успел удалить WAL. Минус: если реплика зависла или выключена, слот продолжит удерживать WAL — и вы легко получите WAL disk full, если не поставили ограничения.
Когда слоты нужны, а когда опасны
- Нужны, если реплика должна переживать краткосрочные/среднесрочные отказы связи без пересоздания из бэкапа.
- Опасны, если реплика «периодическая» (включают раз в неделю) или если нет мониторинга: слот будет удерживать WAL весь период простоя.
Если у вас репликация строится вокруг резервного копирования и восстановления «по расписанию», отдельно проверьте, что у вас выстроен корректный цикл бэкап → восстановление. По теме PITR и WAL-архивации пригодится материал: PITR в PostgreSQL: WAL-архивация и восстановление до точки во времени.

Критически важный предохранитель: max_slot_wal_keep_size
max_slot_wal_keep_size — ремень безопасности против бесконечного роста WAL из-за слотов. Он ограничивает, сколько WAL может быть удержано для слота. При превышении лимита PostgreSQL перестаёт гарантировать, что реплика «догонит» без вмешательства: реплику придётся пересинхронизировать или переинициализировать.
На практике это компромисс:
- без лимита — рискуете положить primary переполнением диска;
- со слишком маленьким лимитом — рискуете получить «сломавшуюся» реплику при длительном простое.
Рабочая рекомендация: выставляйте max_slot_wal_keep_size так, чтобы он покрывал реально допустимое окно недоступности реплики (с запасом на пик WAL), но не превышал объём, который вы готовы держать на том же файловом разделе, что и pg_wal.
Диагностика: что смотреть в pg_stat_replication
pg_stat_replication показывает активные подключения реплик к primary и их состояние. Это самый быстрый способ понять: «реплика живая или нет» и насколько она отстаёт.
Быстрая проверка:
psql -X -c "SELECT pid, application_name, client_addr, state, sync_state, write_lag, flush_lag, replay_lag FROM pg_stat_replication ORDER BY application_name;"
Как читать результат:
state: если неstreaming, уже повод разбираться.sync_state:async/sync/quorum— напрямую влияет на то, ждёт ли коммит реплику.write_lag,flush_lag,replay_lag: удобные подсказки, но иногда бываютNULLили «скачут»; для точной картины смотрите LSN.
Для LSN-диагностики:
psql -X -c "SELECT application_name, sent_lsn, write_lsn, flush_lsn, replay_lsn FROM pg_stat_replication ORDER BY application_name;"
Диагностика слотов: pg_replication_slots и «кто удерживает WAL»
Когда растёт pg_wal, ключевой вопрос: что именно удерживает WAL. Для слотов ответ даёт pg_replication_slots.
psql -X -c "SELECT slot_name, slot_type, active, restart_lsn, confirmed_flush_lsn, wal_status FROM pg_replication_slots ORDER BY slot_name;"
Ориентиры:
active=falseу physical slot — тревожный сигнал: реплика не подключена, но WAL удерживается.restart_lsnпоказывает, начиная с какой позиции WAL ещё нужен слоту.wal_status(если доступен в вашей версии) помогает понять, не упёрлись ли вы в лимиты удержания.
Чтобы оценить объём WAL, удерживаемый каждым слотом:
psql -X -c "SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained, active FROM pg_replication_slots ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC;"
Это один из самых прикладных запросов при расследовании WAL disk full: сразу видно, какой слот удерживает больше всего.

Типовые сценарии аварий и что делать
Сценарий 1: реплика выключена, слот удерживает WAL, диск заканчивается
Симптомы: быстро растёт pg_wal, в pg_replication_slots слот active=false, а удерживаемый объём — десятки или сотни гигабайт.
План действий (в порядке минимизации риска для primary):
- Оцените свободное место и темп роста WAL (важен не только «сколько осталось», но и «на сколько минут хватит»).
- Если реплику реально быстро вернуть в строй — поднимайте её: восстановите сеть, проверьте доступ replication-пользователя, убедитесь, что standby стартует и подключается.
- Если реплику быстро поднять нельзя — примите решение, что важнее прямо сейчас: спасать primary или сохранять возможность догнать реплику без пересоздания.
- Если нужно срочно освобождать место — обычно приходится удалить слот. Это управляемая потеря: реплика, скорее всего, потребует пересоздания.
Удаление слота — это не «починка», а осознанное действие: вы прекращаете удержание WAL ради живучести primary. Зафиксируйте решение и причину в инциденте.
Удаление слота на primary:
psql -X -c "SELECT pg_drop_replication_slot('standby1');"
Сценарий 2: слотов нет, но pg_wal всё равно раздувается
Если слотов нет, рост pg_wal чаще связан с чекпоинтами, архивацией (если включена), либо с тем, что реплика постоянно «на грани» и держится только за счёт wal_keep_size. Проверьте:
- не включено ли архивирование, которое не успевает (например, архивная команда падает или упирается в место);
- настройки чекпоинтов и общую «WAL-экономику» (это отдельная тема);
- фактическое отставание реплики и стабильность канала (потери пакетов, MTU, QoS).
Сценарий 3: сработал max_slot_wal_keep_size, реплика больше не догоняет
Это «правильная» авария: лучше потерять реплику, чем primary. Тактика обычно такая:
- пересоздать реплику из свежего basebackup или бэкапа;
- переоценить лимит
max_slot_wal_keep_sizeи причины простоя реплики; - настроить мониторинг, чтобы узнавать о проблеме до момента срабатывания лимита.
Если вы используете pgBackRest, имеет смысл держать понятный регламент восстановления и регулярные тесты восстановления на отдельной машине. См. практический разбор: pgBackRest: бэкапы и восстановление PostgreSQL.
Для публичных сервисов и админок не забывайте про TLS: корректный сертификат упрощает жизнь и пользователям, и автоматизации. По теме — SSL-сертификаты для продакшена.
Практический чек-лист настроек для production
Ниже — набор практик, которые обычно предотвращают и «битые реплики», и WAL disk full.
- Определитесь, нужны ли слоты. Для постоянно включённых реплик — да, почти всегда. Для «редко включаемых» — чаще нет.
- Ставьте
max_slot_wal_keep_size. Без него любая поломка реплики может превратиться в поломку primary. - Держите умеренный
wal_keep_size. Он полезен даже со слотами как небольшой буфер на краткие сбои. - Мониторьте: размер
pg_wal, удержание WAL по слотам, появлениеactive=falseу слотов, lag репликации (LSN и/или время). - Пропишите план инцидента заранее: кто принимает решение «дропаем слот», как пересоздаёте реплику, где лежит актуальный бэкап.
Мини-набор команд для дежурного: быстро понять ситуацию
Когда места на диске осталось мало, времени на долгое расследование нет. Сохраните себе минимальный набор запросов.
1) Кто подключен и в каком состоянии
psql -X -c "SELECT application_name, client_addr, state, sync_state FROM pg_stat_replication ORDER BY application_name;"
2) Какие слоты есть и активны ли они
psql -X -c "SELECT slot_name, slot_type, active, restart_lsn FROM pg_replication_slots ORDER BY slot_name;"
3) Кто удерживает больше всего WAL
psql -X -c "SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained, active FROM pg_replication_slots ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC;"
Вывод: как не наступать на WAL disk full
Если упростить до одной фразы: wal_keep_size — это мягкая подушка, а replication slots — жёсткая гарантия. И именно жёсткая гарантия чаще всего приводит к переполнению диска, если её не ограничить.
Устойчивый вариант для продакшена обычно такой: используете physical slots для постоянных реплик, обязательно ограничиваете удержание через max_slot_wal_keep_size, держите умеренный wal_keep_size на случай коротких сбоев, и регулярно смотрите pg_stat_replication вместе с pg_replication_slots. Тогда даже при поломке реплики вы получите управляемый инцидент (пересоздать standby), а не катастрофу на primary из‑за раздувшегося pg_wal.


