Возможные причины разрастания pg_wal в PostgreSQL.
Напомним, каталог pg_wal (ранее назывался pg_xlog до версии PostgreSQL 10) используется PostgreSQL для хранения WAL (Write-Ahead Logging) файлов. WAL — это ключевой механизм, обеспечивающий надежность и целостность данных в базе данных.
Вот основные функции каталога pg_wal:
· Восстановление после сбоев: Когда происходит изменение в базе данных (например, вставка, обновление или удаление данных), PostgreSQL сначала записывает это изменение в WAL-журнал в каталоге pg_wal, прежде чем фактически применяет его к самим данным на диске. Это позволяет гарантировать, что все изменения могут быть восстановлены в случае сбоя. В случае аварийного завершения работы сервера PostgreSQL может восстановить состояние базы данных, используя файлы WAL. Это достигается путем повторного применения всех изменений, записанных в WAL.
· Репликация: WAL-файлы используются в механизмах репликации, чтобы передавать изменения на реплицированные сервера. Это помогает поддерживать копии базы данных в синхронизации с основным сервером.
· Архивирование и резервное копирование: Для создания резервных копий с возможностью восстановления до определенного момента времени (Point-in-Time Recovery, PITR) WAL-файлы могут архивироваться и сохраняться для последующего восстановления данных.
Полезно следить за размером каталога pg_wal, так как его чрезмерный рост может занять много места на диске. PostgreSQL предоставляет механизмы для автоматической очистки и архивирования старых WAL-файлов, перед их удалением. На диске WAL-журналы хранятся сегментами, размером по 16 Мб каждый. Сегменты получают названия последовательно, переключение на следующий сегмент происходит при заполнении предыдущего.
Нужно отметить, что размер ещё незаполненного сегмента тоже 16Мб, он резервируется сразу при создании файла. (размер сегмента журнала можно задать отличным от 16Мб в момент инициализации кластера БД initdb --wal-segsize=размер
)
Итак, перейдём к возможным причинам:
1. Первое, что приходит на ум - это неправильные настройки max_wal_size и checkpoint_timeout.
Когда случается успешная контрольная точка, PostgreSQL может удалить сегменты журнала WAL, записанные до нее. Если вы установили значение параметра checkpoint_timeout слишком большим, чтобы уменьшить нагрузку на дисковую подсистему, то контрольные точки могут проходить слишком редко и за это время может накопиться слишком много сегментов журнала.
Это же касается и параметра max_wal_size. Если вы его поставили слишком большим, то и журнал может разрастаться до неприлично больших размеров.
2. Неактивный слот репликации.
Бывает так, реплика стала не нужна, вы ее убрали, а слот репликации удалить забыли, или не проконтролировали его автоматическое удаление. Или, по причине каких-то неполадок у вас возник большой лаг в репликации.
В первом случае PostgreSQL будет видеть, что слот репликации существует и будет считать, что журнальные записи все ещё нужны реплике, и будет их накапливать до тех пор, пока не кончится место на диске, отведённое под pg_wal. Данная проблема актуальна для обоих типов репликации, как физической (мастер-реплики), так и логической (публикатор-подписчики).
Вот таким запросом можно проверить наличие неактивных слотов репликации:
SELECT slot_name, wal_status, active
FROM pg_replication_slots;
В 13-й версии PostgreSQL появилась защита от такой ситуации в виде параметра max_slot_wal_keep_size. Это максимальный объем сегментов WAL, который может удерживаться слотом. После достижения этого объема сегменты будут удалены. Значение по умолчанию -1, т.е. бесконечно.
Если вы находите неактивный слот репликации, который ведет к росту директории pg_wal, то достаточно его удалить, PostgreSQL уже удалит все накопленные сегменты журнала самостоятельно. Делается это вызовом функции:
SELECT pg_drop_replication_slot('имя_слота');
Во втором случае с сильно отстающим слотом репликации, те журнальные записи, которые ещё не успели попасть на реплику, тоже будут накапливаться и могут стать причиной переполнения диска.
Отставание слота можно посмотреть следующим запросом:
SELECT pg_size_pretty(pg_current_wal_lsn() - restart_lsn) as delay, slot_name
FROM pg_replication_slots ORDER BY delay DESC;
Здесь уже нужно диагностировать по какой причине происходит сильное отставание в репликации, проверять сеть и загруженность серверов.
Также, слот репликации на сервере могут открывать и такие утилиты как pg_receivewal и pg_basebackup. Первая служит для ведения потокового архива WAL и по-хорошему должна использовать слот, чтобы защититься от возможных пропусков в журнале. Вторая утилита открывает слот репликации на время копирования PGDATA сервера, и после окончания копирования, оставляет слот существовать, дабы запустив автономную копию в качестве реплики, она продолжила получать WAL-записи с того же места, т.е. с того же LSN (Log Sequence Number), на котором завершила копирование pg_basebackup.
3. Неисправность в работе команды archive_command.
Этот параметр используется для архивирования журнала предзаписи. Но случается так, что команда для архивации, которую вы добавили в параметр archive_command
начинает глючить, она может завершаться с ошибкой, или генерация сегментов журнала WAL может происходить быстрее, чем они успевают архивироваться. Все это тоже приводит к разрастанию директории pg_wal.
Первое, что нужно проверить, завершается ли ваша команда, прописанная в archive_command
успешно или нет. Для этого можно заглянуть в логи PostgreSQL и поискать там ошибку такого вида:
archive command failed with exit code 1
Если ошибки нет, то может команда и отрабатывает нормально, только по какой-то причине тормозит и успевают накопиться сегменты журнала. Здесь причин может быть несколько, от медленной сети, если у вас сегменты передаются в какое-то сетевое хранилище, до медленного сжатия сегментов, с которым может не справляться CPU сервера.
Общую картину по архивированию сегментов журнала WAL вы можете посмотреть с помощью представленияp pg_stat_archiver с помощью вот такого запроса:
SELECT * FROM pg_stat_archiver;
В следующей статье мы рассмотрим влияние настроек, имеющих отношение к буферному кэшу и журналу, на производительность сервера PostgreSQL.