Устранение проблем с высокой активностью WAL и управление дисковым пространством архивных журналов

Узнайте, как устранять и управлять чрезмерной генерацией журналов упреждающей записи (WAL) в PostgreSQL. Это руководство охватывает распространенные причины высокой активности WAL, такие как массовые операции и проблемы репликации, и предоставляет практические решения для настройки архивирования WAL, управления слотами репликации и предотвращения исчерпания дискового пространства. Обязательное чтение для администраторов PostgreSQL, ориентированных на стабильность и эффективное использование дискового пространства.

Устранение проблем с высокой активностью WAL и управление дисковым пространством архивных журналов

Высокая активность журналов упреждающей записи (WAL) в PostgreSQL сама по себе не является проблемой. Нагруженная база данных должна генерировать WAL. Проблема возникает, когда скорость генерации WAL становится неожиданной, когда архивные WAL никогда не очищаются или когда pg_wal растет из-за того, что что-то мешает PostgreSQL перерабатывать старые сегменты.

Самый быстрый способ усугубить инцидент с WAL — вручную удалить файлы из pg_wal. Не делайте этого. Относитесь к полному диску WAL как к ситуации восстановления: определите, что удерживает WAL, создайте свободное пространство, если это безопасно, затем исправьте неисправный архив, отстающую реплику или заброшенный слот, вызвавший рост.

Понимание журнала упреждающей записи (WAL)

PostgreSQL записывает записи изменений в WAL до того, как соответствующие страницы данных будут безопасно записаны. После сбоя PostgreSQL воспроизводит WAL, чтобы зафиксированные изменения не были потеряны. Тот же поток также используется для потоковой репликации и восстановления на момент времени.

Файлы WAL хранятся в сегментных файлах фиксированного размера. Во многих установках используются сегменты по 16 МБ, поскольку это распространенное значение по умолчанию, но размер выбирается при инициализации кластера. Нагрузка с интенсивной записью может быстро создать большое количество сегментов. Старые сегменты перерабатываются или удаляются только после того, как PostgreSQL больше не нуждается в них для восстановления после сбоя, контрольных точек, архивирования, репликации или слотов.

Ключевые концепции WAL:

  • Долговечность: зафиксированные транзакции могут быть восстановлены после сбоя.
  • Репликация: реплики получают записи WAL от основного сервера.
  • Восстановление на момент времени (PITR): базовые резервные копии плюс архивные WAL позволяют восстановиться до выбранного момента в пределах окна хранения.
  • Сегменты WAL: WAL хранится в файлах сегментов в каталоге pg_wal.

Распространенные причины высокой активности WAL

Несколько факторов могут способствовать необычно высокому объему генерации WAL. Определение первопричины — первый шаг в эффективном устранении неполадок.

1. Массовая загрузка и модификация данных

Операции, такие как INSERT, UPDATE, DELETE, TRUNCATE и COPY, могут генерировать значительные объемы WAL. Массовые операции, особенно над большими таблицами, естественным образом создадут больше записей WAL, чем небольшие отдельные транзакции.

  • Пример: Одна команда COPY FROM для вставки миллионов строк может сгенерировать гигабайты данных WAL.
  • Пример: Выполнение крупномасштабной миграции данных или пакетного скрипта обновления.

2. Задержка репликации и проблемы с репликами

Если ваши реплики не успевают за основным сервером (задержка репликации), файлы WAL будут накапливаться на основном сервере. Основной сервер не может удалить завершенные сегменты WAL, пока не будет подтверждено, что они были отправлены и обработаны всеми подключенными репликами (если не настроены wal_keep_size или max_slot_wal_keep_size, или если слоты используются неправильно).

  • Сценарий: Реплика отключена, отключена от сети или испытывает проблемы с производительностью, что мешает ей потреблять записи WAL от основного сервера.

3. Запись полных страниц после контрольных точек

После контрольной точки первое изменение страницы данных может зарегистрировать образ полной страницы, когда включен full_page_writes. Этот параметр защищает восстановление от разорванных страниц и обычно оставлен включенным. Если контрольные точки происходят слишком часто, образы полных страниц могут заметно увеличить объем WAL. Обычно решение заключается в настройке поведения контрольных точек, а не в отключении защиты долговечности.

4. Неуправляемый рост каталога pg_wal

Если архивирование WAL включено и не работает, PostgreSQL сохраняет сегменты WAL, которые еще нужно заархивировать. Если архивирование не включено, pg_wal все равно должен перерабатывать старые сегменты, когда они больше не нужны, если только репликация, слоты или давление контрольных точек не удерживают их.

5. Слоты репликации не освобождаются

Слоты репликации гарантируют, что сегменты WAL не будут удалены до того, как они будут потреблены конкретной репликой или клиентом логического декодирования. Если слот создан, но потребитель останавливается или отключается без удаления слота, сегменты WAL, требуемые этим слотом, будут сохранены, даже если реплика больше не активна.

Управление дисковым пространством WAL: конфигурация и решения

Решение проблемы высокой активности WAL требует многостороннего подхода, включающего мониторинг, настройку конфигурации и правильные процедуры обслуживания.

1. Включение и мониторинг архивирования WAL

Архивирование WAL является наиболее важным механизмом для управления дисковым пространством и обеспечения PITR. Когда архивирование включено, завершенные файлы WAL копируются в отдельное место (например, сетевую файловую папку, корзину S3 или другой диск).

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

Измените файл postgresql.conf:

wal_level = replica         # Или logical для логической репликации
archive_mode = on           # Включить архивирование
archive_command = 'cp %p /path/to/archive/%f'

# Пример для S3 с использованием wal-g или аналогичного инструмента:
# archive_command = 'wal-g wal-push %p'
  • %p: Заполнитель для полного пути к файлу WAL, который нужно заархивировать.
  • %f: Заполнитель для имени файла WAL.

Важно: archive_command должен выполняться успешно. Если он возвращает ненулевой код выхода, PostgreSQL будет считать архивирование неудачным, что может привести к тому, что файлы WAL не будут удалены. Убедитесь, что в целевом каталоге достаточно места и у пользователя, запускающего PostgreSQL, есть права на запись.

Мониторинг архивирования

Используйте SQL-запросы для проверки статуса архивирования:

SELECT archived_count,
       failed_count,
       last_archived_wal,
       last_archived_time,
       last_failed_wal,
       last_failed_time
FROM pg_stat_archiver;

Если failed_count постоянно увеличивается или last_archived_time устарел, а база данных продолжает запись, исправьте целевой каталог архива, прежде чем настраивать параметры размера WAL.

2. Управление размером каталога pg_wal

Даже при включенном архивировании каталог pg_wal на основном сервере может расти, если сегменты WAL не удаляются после архивирования. Это происходит, если:

  • Реплики не успевают, и основной сервер сохраняет дополнительный WAL для репликации.
  • Слоты репликации удерживают файлы WAL.

wal_keep_size

Этот параметр сохраняет дополнительный WAL на основном сервере для потоковой репликации. Он заменил более старую настройку wal_keep_segments в PostgreSQL 13. Он полезен для реплик, которые не используют слоты, но не гарантирует, что сильно отстающая реплика всегда сможет догнать.

# postgresql.conf на основном сервере
wal_keep_size = 1024 # Хранить 1 ГБ WAL на диске

Слоты репликации часто предпочтительнее, когда требуется, чтобы основной сервер сохранял WAL для конкретного потребителя, но за слотами необходимо следить, поскольку они могут удерживать WAL бесконечно.

max_slot_wal_keep_size (PostgreSQL 13+)

Этот параметр ограничивает объем WAL, который может удерживать слот репликации. Это защита от бесконечного роста из-за неисправного слота, но он также может привести к тому, что отстающий потребитель потеряет необходимый ему WAL и потребует переинициализации.

# postgresql.conf на основном сервере
max_slot_wal_keep_size = 2048 # Ограничить слоты до 2 ГБ WAL

# Также рассмотрите: wal_keep_size -- все еще актуально для потоковой передачи без слотов
# wal_keep_size = 1024 # Хранить 1 ГБ для потоковой передачи без слотов

Если слот слишком сильно отстает и превышает этот лимит, PostgreSQL может удалить необходимый WAL во время контрольной точки. Это защищает дисковое пространство, но затронутая реплика или клиент логической репликации могут больше не иметь возможности продолжить со своей старой позиции.

Слоты репликации

Слоты репликации имеют решающее значение для предотвращения потери WAL и обеспечения надежной репликации. Однако они могут привести к накоплению файлов WAL, если за ними неправильно управлять.

  • Проблема: Слот репликации создан, но потребитель (реплика или логический клиент) отключается или выходит из строя, и слот никогда не удаляется. Основной сервер будет хранить все файлы WAL, которые ожидает слот.
  • Решение: Регулярно контролируйте слоты репликации и удаляйте те, которые больше не используются.
-- Список слотов репликации
SELECT slot_name,
       plugin,
       slot_type,
       active,
       restart_lsn,
       wal_status,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC NULLS LAST;

-- Удалить неиспользуемый слот
SELECT pg_drop_replication_slot('slot_name_to_drop');

Предупреждение: Удаление слота репликации приведет к потере позиции любым подключенным потребителем. Перед удалением убедитесь, что потребитель больше не нужен или был правильно переинициализирован.

3. Настройка min_wal_size и max_wal_size

Эти параметры влияют на частоту контрольных точек и объем WAL, который PostgreSQL пытается сохранить для повторного использования. Они не ограничивают WAL, сохраняемый для архивирования или репликации.

  • min_wal_size: побуждает PostgreSQL сохранять как минимум этот объем WAL для повторного использования вместо немедленного удаления.
  • max_wal_size: объем WAL, который обычно инициирует контрольную точку. Это не жесткий максимум, когда WAL сохраняется по другим причинам.
# postgresql.conf
min_wal_size = 1GB
max_wal_size = 4GB

Увеличение max_wal_size может дать системе больше запаса во время пиковых нагрузок на запись, но это также означает, что больше дискового пространства будет занято предварительно выделенными файлами WAL.

4. Регулярная очистка архивных файлов WAL

Архивирование WAL, хотя и необходимо для восстановления, также может привести к проблемам с дисковым пространством, если архивные файлы никогда не очищаются. У вас должна быть стратегия управления хранением архивных файлов WAL.

  • Стратегия: Реализуйте скрипт или используйте специальный инструмент (например, pg_archivecleanup, pgBackRest, wal-g, barman) для удаления старых файлов WAL из места архивации, когда они больше не нужны для PITR или репликации.

  • Использование pg_archivecleanup: Эта утилита может быть запущена на основном сервере для удаления старых файлов WAL из каталога архива.

    pg_archivecleanup /path/to/archive/location 0000000100000037000000AF
    

    Второй аргумент — это имя самого старого файла WAL, который все еще необходимо сохранить, а не произвольный возраст. На практике такие инструменты резервного копирования, как pgBackRest, Barman и WAL-G, безопаснее, поскольку они понимают политику хранения резервных копий и WAL, необходимый для восстановления.

    Важно: Всегда убеждайтесь, что ваша стратегия очистки соответствует требованиям резервного копирования и восстановления на момент времени (PITR). Вам необходимо хранить файлы WAL достаточно долго, чтобы покрыть желаемое окно восстановления.

5. Мониторинг дискового пространства и скорости генерации WAL

Упреждающий мониторинг является ключом к предотвращению исчерпания дискового пространства.

  • Мониторинг дискового пространства: Отслеживайте свободное место в каталоге данных, pg_wal, временных файлах и местах архивации.

  • Мониторинг генерации WAL: Используйте разницу LSN с течением времени для оценки скорости генерации.

    SELECT now() AS sample_time,
           pg_current_wal_lsn() AS current_lsn;
    

    Периодически сохраняйте это значение и сравнивайте выборки с помощью pg_wal_lsn_diff(new_lsn, old_lsn). Для быстрого просмотра текущего размера каталога pg_wal:

    SELECT pg_size_pretty(sum(size)) AS pg_wal_size
    FROM pg_ls_waldir();
    

Действия по устранению неполадок при полных дисках

Если ваш диск уже заполнен из-за активности WAL, требуются немедленные действия:

  1. Определите причину: Проверьте pg_stat_archiver на наличие сбоев архивирования. Изучите pg_replication_slots на наличие неиспользуемых или проблемных слотов. Проверьте задержку репликации на репликах.
  2. Освободите место без ущерба для восстановления:
    • Не удаляйте файлы из pg_wal вручную.
    • Если место архивации заполнено, удаляйте старые архивные WAL только в том случае, если они выходят за пределы окна хранения резервных копий.
    • Если возможно, добавьте хранилище или переместите место архивации, затем позвольте PostgreSQL архивировать и перерабатывать в обычном режиме.
  3. Устраните первопричину:
    • Исправьте архивирование: Убедитесь, что archive_command корректен и в месте назначения есть место.
    • Управляйте слотами: Удалите все неиспользуемые слоты репликации.
    • Исправьте репликацию: Решите проблемы, вызывающие задержку реплики.
    • Увеличьте дисковое пространство: Временно или постоянно добавьте больше хранилища.
  4. Подтолкните архиватор: После исправления команды архивирования или места назначения PostgreSQL должен повторить попытку. Перезагрузки может быть достаточно для изменений конфигурации; полный перезапуск должен быть крайней мерой во время инцидента с диском.

Более безопасная ментальная модель

Когда pg_wal растет, задайте три вопроса по порядку:

  1. Генерирует ли PostgreSQL больше WAL, чем обычно, из-за изменения рабочей нагрузки?
  2. Не может ли PostgreSQL архивировать WAL?
  3. Указано ли PostgreSQL сохранять WAL для репликации или слота?

Эти ответы указывают на разные исправления. Массовые записи могут потребовать планирования, пакетной обработки или настройки контрольных точек. Сбои архивирования требуют исправления хранилища и команд. Удержание слотов требует восстановления потребителя, очистки слота или ограничения на удержание. Угадывание с max_wal_size редко решает реальную проблему само по себе.