28.5. WAL Конфигурация#
28.5. WAL Конфигурация #
Существует несколько параметров конфигурации, связанных с WAL, которые влияют на производительность базы данных. В этом разделе объясняется их использование. Для общей информации о настройке параметров конфигурации сервера обратитесь к Глава 18.
Checkpoints являются точками в последовательности транзакций, в которых гарантируется, что файлы данных кучи и индекса были обновлены всей информацией, записанной до этой контрольной точки. В момент контрольной точки все измененные страницы данных сбрасываются на диск, и специальная запись контрольной точки записывается в файл WAL. (Записи изменений ранее были сброшены в файлы WAL.) В случае сбоя процедура восстановления после сбоя просматривает последнюю запись контрольной точки, чтобы определить точку в WAL (известную как запись повторного выполнения), с которой следует начать операцию REDO. Любые изменения, внесенные в файлы данных до этой точки, гарантированно уже находятся на диске. Таким образом, после контрольной точки сегменты 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
ожидается, что Tantor BE завершит каждую контрольную точку
немного раньше, чем следующая запланированная контрольная точка (примерно за 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, сгенерированного в предыдущих циклах контрольных точек. Когда старые файлы
сегментов WAL больше не нужны, они удаляются или перерабатываются (то есть,
переименовываются, чтобы стать будущими сегментами в нумерованной последовательности). Если из-за
кратковременного пика скорости вывода 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
до устранения проблемы. Медленный или неработающий сервер-подчиненный, использующий слот репликации,
будет иметь тот же эффект (см.
Раздел 25.2.6).
В режиме восстановления из архива или режиме ожидания сервер периодически выполняет точки перезапуска,
которые аналогичны контрольным точкам в нормальной работе: сервер принудительно записывает все свое состояние на диск, обновляет файл pg_control
для указания, что уже обработанные данные WAL не нужно сканировать снова, а затем перерабатывает любые старые файлы сегментов WAL в каталоге pg_wal
.
Точки перезапуска не могут выполняться чаще, чем контрольные точки на основном сервере, потому что точки перезапуска могут выполняться только на записях контрольных точек.
Точка перезапуска срабатывает, когда достигается запись контрольной точки, если прошло по крайней мере checkpoint_timeout
секунд с момента последней точки перезапуска, или если размер WAL вот-вот превысит max_wal_size
. Однако из-за ограничений на выполнение точки перезапуска, max_wal_size
часто превышается во время восстановления, до объема одного цикла контрольной точки WAL.
(max_wal_size
в любом случае никогда не является жестким ограничением, поэтому всегда следует оставлять достаточно свободного места, чтобы избежать нехватки дискового пространства.)
Существует две часто используемые внутренние функции WAL:
XLogInsertRecord
и XLogFlush
.
XLogInsertRecord
используется для размещения новой записи в
буферы WAL в общей памяти. Если нет
места для новой записи, XLogInsertRecord
должен будет
записать (переместить в кэш ядра) несколько заполненных буферов WAL.
Это нежелательно, потому что XLogInsertRecord
используется при каждом низкоуровневом изменении базы данных (например, вставке строки)
в момент, когда на затронутые страницы данных наложен эксклюзивный блок, поэтому операция
должна быть как можно быстрее. Что еще хуже, запись буферов WAL может также
вынудить создание нового сегмента WAL, что занимает еще больше
времени. Обычно буферы WAL должны записываться
и сбрасываться по запросу XLogFlush
, который
выполняется, в основном, в момент фиксации транзакции, чтобы гарантировать, что
записи транзакций сброшены на постоянное хранилище. В системах
с высоким выходом WAL запросы 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. Значение, равное половине среднего времени, которое программа сообщает, что требуется для сброса после одной операции записи 8kB, часто является наиболее эффективной настройкой для 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 определяет, как
Tantor BE будет запрашивать ядро для принудительной
записи обновлений WAL на диск.
Все варианты должны быть одинаково надежными, за исключением fsync_writethrough
, который иногда
может принудительно сбросить кеш диска, даже если другие варианты этого не делают.
Однако, наиболее быстрым будет зависеть от конкретной платформы.
Вы можете проверить скорость различных вариантов, используя программу pg_test_fsync.
Обратите внимание, что этот параметр не имеет значения, если fsync
был отключен.
Включение параметра конфигурации wal_debug (при условии, что Tantor BE был скомпилирован с поддержкой этого параметра) приведет к записи каждого вызова функций XLogInsertRecord
и XLogFlush
WAL в журнал сервера. Эта опция может быть заменена более общим механизмом в будущем.
Существуют две внутренние функции для записи данных WAL на диск: XLogWrite
и issue_xlog_fsync
. Когда track_wal_io_timing включено, общее время записи XLogWrite
и синхронизации 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_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 может использоваться для сокращения времени ожидания ввода-вывода во время восстановления, указывая ядру начинать чтение дисковых блоков, которые скоро понадобятся, но в настоящее время не находятся в буферном пуле Tantor BE.
Настройки maintenance_io_concurrency и wal_decode_buffer_size ограничивают параллелизм и расстояние предварительной загрузки соответственно. По умолчанию он установлен в try
, что включает эту функцию на системах, где доступна функция posix_fadvise
.