Перейти к основному содержимому

Настройка WAL

примечание

Эта страница переведена при помощи нейросети GigaChat.

Существует несколько параметров конфигурации, связанных с WAL, которые влияют на производительность базы данных. В этом разделе объясняется их использование. Обратитесь к разделу «Настройка сервера» для получения общей информации о настройке параметров конфигурации сервера.

Контрольные точки – это моменты в последовательности транзакций, в которых гарантируется, что файлы данных кучи и индекса были обновлены всей информацией, записанной до этой контрольной точки. В момент контрольной точки все грязные страницы данных сбрасываются на диск, и специальная запись контрольной точки записывается в файл журнала (записи изменений ранее были сброшены в файлы WAL). В случае сбоя процедура восстановления после сбоя проверяет последнюю запись контрольной точки, чтобы определить точку в журнале (известную как запись повторного выполнения), с которой она должна начать операцию ПОВТОРНОГО ВЫПОЛНЕНИЯ. Любые изменения, внесенные в файлы данных до этого момента, гарантированно уже находятся на диске. Таким образом, после контрольной точки сегменты журнала, предшествующие сегменту, содержащему запись повторного выполнения, больше не нужны и могут быть переработаны или удалены. Когда выполняется архивирование WAL, сегменты журнала должны быть заархивированы перед их переработкой или удалением.

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

Процесс контрольной точки сервера автоматически выполняет контрольную точку каждые несколько секунд. Контрольная точка начинается каждые checkpoint_timeout или если max_wal_size вот-вот будет превышен, что произойдет раньше. Значения по умолчанию составляют 5 минут и 1 ГБ соответственно. Если с момента последней контрольной точки не было записано ни одного WAL, новые контрольные точки будут пропущены даже в том случае, если прошло checkpoint_timeout. Если используется архивирование WAL, и необходимо установить нижнюю границу частоты архивирования файлов для ограничения потенциальной потери данных, то следует настроить параметр archive_timeout вместо параметров контрольной точки. Также возможно принудительное выполнение контрольной точки с помощью команды SQL CHECKPOINT.

Уменьшение checkpoint_timeout и/или max_wal_size приводит к более частому возникновению контрольных точек. Это позволяет быстрее восстанавливаться после сбоя, поскольку потребуется меньше работы для повторения. Однако необходимо сбалансировать это с увеличенными затратами на более частый сброс грязных страниц данных. Если установлен параметр full_page_writes (как установлено по умолчанию), следует учитывать еще один фактор. Чтобы обеспечить согласованность страницы данных, первое изменение страницы данных после каждой контрольной точки приводит к записи всего содержимого страницы в журнал. В этом случае меньший интервал контрольной точки увеличивает объем вывода в журнал WAL, частично нейтрализуя цель использования меньшего интервала, и в любом случае вызывает большее количество операций ввода-вывода диска.

Контрольные точки являются довольно дорогими, во-первых, потому что они требуют записи всех текущих поврежденных буферов, а во-вторых, потому что это приводит к дополнительному последующему трафику WAL, как обсуждалось выше. Поэтому разумно установить параметры контрольной точки достаточно высоко, чтобы контрольные точки не выполняись слишком часто. В качестве простой проверки параметров контрольной точки можно установить параметр checkpoint_warning. Если контрольные точки происходят чаще, чем через checkpoint_warning секунд, сообщение будет выведено в журнал сервера с рекомендацией увеличить max_wal_size. Периодическое появление такого сообщения не является поводом для тревоги, но если оно появляется часто, то параметры управления контрольными точками должны быть увеличены. Массовые операции, такие как COPY с большим объемом данных, могут привести к появлению нескольких таких предупреждений, если значение max_wal_size не установлено достаточно большим.

Чтобы избежать «затопления» системы ввода-вывода потоком записей страниц, запись поврежденных буферов во время контрольной точки распределяется на определенный период времени. Этот период контролируется параметром checkpoint_completion_target, который задан как доля интервала контрольной точки (настроенного с использованием checkpoint_timeout). Скорость ввода-вывода регулируется таким образом, чтобы контрольная точка завершалась, когда проходит данная доля от checkpoint_timeout секунд или до того, как будет превышено значение max_wal_size, в зависимости от того, что произойдет раньше. С значением по умолчанию 0.9, PostgreSQL можно ожидать завершения каждой контрольной точки немного раньше следующей запланированной контрольной точки (около 90% продолжительности последней контрольной точки). Это максимально распределяет ввод-вывод, так что нагрузка ввода-вывода контрольной точки остается постоянной в течение всего интервала контрольной точки. Недостатком этого является то, что затягивание контрольных точек влияет на время восстановления, поскольку потребуется сохранить больше сегментов WAL для возможного использования при восстановлении. Пользователь, обеспокоенный количеством времени, необходимого для восстановления, может пожелать уменьшить checkpoint_timeout таким образом, чтобы контрольные точки происходили чаще, но все равно распределить ввод-вывод по интервалу контрольной точки. В качестве альтернативы, checkpoint_completion_target могло бы быть уменьшено, но это привело бы к временам более интенсивного ввода-вывода (во время контрольной точки) и временам менее интенсивного ввода-вывода (после завершения контрольной точки, но до следующей запланированной контрольной точки), поэтому это не рекомендуется. Хотя checkpoint_completion_target можно было бы установить до 1.0, обычно рекомендуется устанавливать его не выше 0.9 (по умолчанию), поскольку контрольные точки включают некоторые другие действия помимо записи поврежденных буферов. Установка значения 1.0 весьма вероятно приведет к тому, что контрольные точки не будут завершены вовремя, что приведет к потере производительности из-за неожиданного изменения количества необходимых сегментов WAL.

На платформах Linux и POSIX checkpoint_flush_after позволяет принудительно сообщить ОС о том, что страницы, записанные контрольной точкой, должны быть сброшены на диск после настраиваемого количества байт. В противном случае эти страницы могут оставаться в кеше страниц ОС, вызывая задержку при выдаче команды fsync в конце контрольной точки. Эта настройка часто помогает снизить задержку транзакций, но она также может оказать неблагоприятное влияние на производительность; особенно для рабочих нагрузок, которые больше, чем shared_buffers, но меньше кеша страниц ОС.

Количество файлов сегмента WAL в каталоге pg_wal зависит от min_wal_size, max_wal_size и объема WAL, созданного в предыдущих циклах контрольных точек. Когда старые файлы сегментированного журнала больше не нужны, они удаляются или перерабатываются (то есть переименовываются, чтобы стать будущими сегментами в пронумерованной последовательности). Если из-за кратковременного пика скорости вывода журнала max_wal_size превышен, ненужные файлы сегментов будут удаляться до тех пор, пока система снова не выйдет под этот предел. Ниже этого предела система перерабатывает достаточно файлов WAL, чтобы покрыть предполагаемую потребность до следующей контрольной точки, а остальные удаляет. Оценка основана на скользящем среднем количества файлов WAL, использованных в предыдущих циклах контрольных точек. Скользящее среднее значение немедленно увеличивается, если фактическое использование превышает оценку, поэтому оно учитывает пиковое использование, а не среднее использование до некоторой степени. min_wal_size устанавливает минимальное количество файлов WAL, которые перерабатываются для будущего использования; столько WAL всегда перерабатывается для будущего использования, даже если система простаивает, и оценка использования WAL предполагает, что требуется мало WAL.

Независимо от max_wal_size, последние wal_keep_size мегабайт файлов WAL плюс один дополнительный файл WAL всегда сохраняются. Кроме того, если используется архивирование WAL, старые сегменты не могут быть удалены или переработаны до их архивирования. Если архивирование WAL не может угнаться за темпом генерации WAL или если archive_command или archive_library неоднократно терпит неудачу, старые файлы WAL будут накапливаться в pg_wal до тех пор, пока ситуация не будет решена. Медленный или сбойный сервер-репликат, использующий репликационный слот, окажет такой же эффект (см. раздел «Слоты репликации»).

В режиме архивного восстановления или режима ожидания сервер периодически выполняет точки перезапуска, аналогичные контрольным точкам в обычном режиме работы: сервер заставляет записать свое состояние на диск, обновляет файл pg_control для указания того, что уже обработанные данные WAL не требуют повторного сканирования, затем повторно использует любые устаревшие файлы сегментов WAL в директории pg_wal. Точки перезапуска не могут происходить чаще, чем контрольные точки на основном сервере, так как точки перезапуска могут выполняться только на записях контрольных точек. Запрос на создание точки перезапуска может исходить от расписания или внешнего запроса. Счетчик restartpoints_timed в представлении pg_stat_checkpointer считает первые случаи, тогда как счетчик restartpoints_req --- вторые. Точка перезапуска запускается по расписанию, когда достигается запись контрольной точки, если с момента последнего выполненного перезапуска прошло не менее checkpoint_timeout секунд или если предыдущая попытка выполнить перезапуск потерпела неудачу. В последнем случае следующая точка перезапуска будет назначена через 15 секунд. Точка перезапуска инициируется запросом по аналогичным причинам, как и контрольная точка, но главным образом, если размер WAL близок к превышению max_wal_size. Тем не менее, из-за ограничений относительно того, когда может быть выполнена точка перезапуска, max_wal_size часто превышается во время восстановления, вплоть до одного цикла контрольной точки WAL. (max_wal_size никогда не является жестким ограничением, поэтому всегда следует оставлять достаточный запас свободного места на диске, чтобы избежать исчерпания пространства.) Счетчик restartpoints_done в представлении pg_stat_checkpointer подсчитывает реально выполненные точки перезапуска.

Иногда, когда скорость увеличения размера WAL на главном сервере быстро возрастает, например, во время массовой вставки, счетчик restartpoints_req на подчиненном сервере может демонстрировать пиковый рост. Это происходит потому, что запросы на создание новой точки перезапуска вследствие повышенного потребления XLOG не могут быть выполнены, так как безопасная запись контрольной точки со времени предыдущего перезапуска еще не была воспроизведена на подчиненном сервере. Такое поведение нормально и не ведет к увеличению потребления системных ресурсов. Только среди показателей, относящихся к точке перезапуска, показатель restartpoints_done указывает на заметное расходование системных ресурсов.

Существует две обычно используемые внутренние функции WAL: XLogInsertRecord и XLogFlush. XLogInsertRecord используется для размещения новой записи в буферах WAL в общей памяти. Если нет места для новой записи, XLogInsertRecord придется записать (переместить в кеш ядра) несколько заполненных буферов WAL. Это нежелательно, потому что XLogInsertRecord используется при каждом низкоуровневом изменении базы данных (например, вставке строки) в момент, когда удерживается исключительная блокировка затронутых страниц данных, поэтому операция должна быть максимально быстрой. Что еще хуже, запись буферов WAL также может привести к созданию нового сегмента журнала, что займет еще больше времени. Обычно буферы WAL должны быть записаны и очищены запросом XLogFlush, который делается главным образом во время фиксации транзакции, чтобы гарантировать, что записи транзакций очищаются в постоянное хранилище. В системах с высоким выходом журнала запросы XLogFlush могут происходить недостаточно часто, чтобы предотвратить необходимость выполнения записей XLogInsertRecord. В таких системах следует увеличить количество буферов WAL, изменив параметр wal_buffers. Когда full_page_writes установлен и система очень загружена, установка wal_buffers выше поможет сгладить время отклика в период сразу после каждой контрольной точки.

Параметр commit_delay определяет, сколько микросекунд процесс группового коммита будет спать после получения блокировки внутри XLogFlush, пока процессы группового коммита следуют за лидером. Эта задержка позволяет другим серверным процессам добавлять свои записи фиксации в буферы WAL, чтобы все они были очищены окончательной операцией синхронизации лидера. Сон не произойдет, если fsync не включен или если менее чем commit_siblings других сеансов в настоящее время находятся в активных транзакциях; это предотвращает сон, когда маловероятно, что какая-либо другая сессия скоро зафиксируется. Обратите внимание, что на некоторых платформах разрешение запроса сна составляет десять миллисекунд, так что любое ненулевое значение commit_delay между 1 и 10000 микросекунд имело бы тот же эффект. Также обратите внимание, что на некоторых платформах операции сна могут занять немного больше времени, чем указано параметром.

Поскольку цель commit_delay состоит в том, чтобы позволить стоимости каждой операции очистки амортизироваться среди одновременно фиксируемых транзакций (потенциально за счет задержки транзакции), необходимо количественно оценить эту стоимость, прежде чем настройка сможет быть выбрана разумно. Чем выше эта стоимость, тем эффективнее, как ожидается, будет commit_delay для увеличения пропускной способности транзакций, до определенной точки. Программа pg_test_fsync может использоваться для измерения среднего времени в микросекундах, которое занимает одна операция очистки WAL. Значение половины среднего времени, которое программа сообщает о необходимости очистки после одной операции записи 8 КБ, часто является наиболее эффективной настройкой для commit_delay, поэтому это значение рекомендуется использовать в качестве отправной точки при оптимизации для конкретной рабочей нагрузки. Хотя настройка commit_delay особенно полезна, когда журнал WAL хранится на вращающихся дисках с высокой задержкой, преимущества могут быть значительными даже на носителях хранения с очень быстрым временем синхронизации, таких как твердотельные накопители или массивы RAID с батарейным источником питания для записи; но это определенно должно быть протестировано против репрезентативной рабочей нагрузки. Более высокие значения commit_siblings следует использовать в таких случаях, тогда как меньшие значения commit_siblings часто полезны на носителях с большей задержкой. Обратите внимание, что вполне возможно, что настройка commit_delay, которая слишком высока, может настолько увеличить задержку транзакции, что общая производительность транзакций пострадает.

Когда commit_delay установлен на ноль (по умолчанию), все еще возможна форма групповой фиксации, но каждая группа будет состоять только из сеансов, которые достигают точки, где им нужно очистить свои записи фиксации во время окна, в котором происходит предыдущая операция очистки (если есть). При более высоком количестве клиентов имеет тенденцию возникать эффект «прохода», так что эффекты групповой фиксации становятся значимыми даже при commit_delay равном нулю, и таким образом явная установка commit_delay имеет тенденцию помогать меньше. Установка commit_delay может помочь только тогда, когда (1) существуют некоторые параллельно фиксируемые транзакции и (2) пропускная способность ограничена до некоторой степени скоростью фиксации, но с высокой латентностью вращения эта настройка может быть эффективна для увеличения пропускной способности транзакций всего лишь двумя клиентами (т.е. одним клиентом с одной побочной транзакцией).

Параметр wal_sync_method определяет, каким образом PostgreSQL будет просить ядро принудительно записывать обновления WAL на диск. Все опции должны быть одинаковыми с точки зрения надежности, за исключением fsync_writethrough, который иногда может заставить выполнить сброс кеша диска даже тогда, когда другие параметры этого не делают. Однако скорость работы каждого из них сильно зависит от платформы. Можно протестировать скорости различных опций с помощью программы pg_test_fsync. Обратите внимание, что этот параметр не имеет значения, если fsync отключен.

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

Есть две внутренние функции для записи данных WAL на диск: XLogWrite и issue_xlog_fsync. Когда track_wal_io_timing включен, общее время, затраченное на запись XLogWrite данных WAL и синхронизацию issue_xlog_fsync данных WAL с диском, учитывается как wal_write_time и wal_sync_time в pg_stat_wal соответственно. XLogWrite обычно вызывается XLogInsertRecord (когда нет места для новой записи в буферах WAL), XLogFlush и писателем WAL для записи буферов WAL на диск и вызова issue_xlog_fsync. issue_xlog_fsync обычно вызывается XLogWrite для синхронизации файлов WAL с диском. Если wal_sync_method равно либо open_datasync, либо open_sync, операция записи в XLogWrite гарантирует синхронизацию записанных данных WAL с диском, а issue_xlog_fsync ничего не делает. Если wal_sync_method равно либо fdatasync, либо fsync, либо fsync_writethrough, операция записи перемещает буферы WAL в кеш ядра, а issue_xlog_fsync синхронизирует их с диском. Независимо от настройки track_wal_io_timing, количество операций записи XLogWrite и синхронизации issue_xlog_fsync данных WAL также учитываются как wal_write и wal_sync в pg_stat_wal соответственно.

Параметр recovery_prefetch может использоваться для уменьшения времени ожидания ввода-вывода во время восстановления, инструктируя ядро инициировать чтение блоков диска, которые скоро понадобятся, но в настоящее время отсутствуют в пуле буферов PostgreSQL. Параметры maintenance_io_concurrency и wal_decode_buffer_size ограничивают соответственно степень параллелизма предварительной выборки и расстояние. По умолчанию он установлен на try, что включает эту функцию на системах, где доступен posix_fadvise.