29.5. WAL Конфигурация#
29.5. WAL Конфигурация
Существует несколько параметров конфигурации, связанных с WAL, которые влияют на производительность базы данных. В этом разделе объясняется их использование. Для общей информации о настройке параметров конфигурации сервера обратитесь к Глава 19.
Checkpoints точки в последовательности транзакций, на которых гарантируется, что файлы данных кучи и индекса были обновлены всей информацией, записанной до этой контрольной точки. Во время контрольной точки все грязные страницы данных сбрасываются на диск, и в журнальный файл записывается специальная запись контрольной точки. (Изменения были ранее сброшены в файлы WAL). В случае сбоя процедура восстановления после сбоя просматривает последнюю запись контрольной точки, чтобы определить точку в журнале (известную как запись redo), с которой следует начать операцию REDO. Любые изменения, внесенные в файлы данных до этой точки, гарантированно уже находятся на диске. Таким образом, после контрольной точки сегменты журнала, предшествующие тому, который содержит запись redo, больше не нужны и могут быть переработаны или удалены. (При выполнении архивирования 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, частично противоречащий цели использования более маленького интервала, и в любом случае приводит к большему вводу-выводу на диске.
Все операции по контрольным точкам достаточно затратны, во-первых, потому что они требуют записи всех текущих грязных буферов, и, во-вторых, потому что они приводят к дополнительному трафику 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 SE завершит каждую контрольную точку
немного раньше, чем следующая запланированная контрольная точка (примерно за 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
, ненужные файлы сегментов будут удалены до тех пор, пока система не вернется к этому ограничению. При значении ниже этого предела система перерабатывает достаточное количество файлов журнала предзаписи для покрытия ожидаемой потребности до следующей контрольной точки и удаляет остальные. Оценка основана на скользящем среднем количества использованных файлов журнала предзаписи в предыдущих циклах контрольных точек. Скользящее среднее увеличивается немедленно, если фактическое использование превышает оценку, поэтому оно в некоторой степени учитывает пиковое использование, а не среднее использование. min_wal_size
устанавливает минимальное количество перерабатываемых файлов журнала предзаписи для будущего использования; столько же WAL всегда перерабатывается для будущего использования, даже если система неактивна и оценка использования WAL указывает на небольшую потребность в WAL.
Независимо от значения переменной max_wal_size
,
последние wal_keep_size мегабайтов
WAL-файлов, а также один дополнительный WAL-файл,
хранятся всегда. Кроме того, если используется архивация WAL-файлов, старые сегменты не могут быть
удалены или переработаны, пока они не будут заархивированы. Если архивация WAL-файлов не успевает
соответствовать темпу генерации WAL-файлов или если archive_command
или archive_library
постоянно сбоит, старые WAL-файлы будут накапливаться в pg_wal
до устранения проблемы. Медленный или неработающий сервер-подчиненный, использующий слот репликации,
будет иметь тот же эффект (см.
Раздел 26.2.6).
В режиме восстановления из архива или режиме ожидания сервер периодически выполняет точки перезапуска,
которые аналогичны контрольным точкам в нормальной работе: сервер принудительно записывает все свои состояния на диск, обновляет файл pg_control
, чтобы указать, что уже обработанные данные 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 должны быть записаны и сброшены с помощью запроса 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 определяет, как
Tantor SE будет запрашивать ядро для принудительной
записи обновлений WAL на диск.
Все варианты должны быть одинаково надежными, за исключением fsync_writethrough
, который иногда
может принудительно сбросить кеш диска, даже если другие варианты этого не делают.
Однако, наиболее быстрым будет зависеть от конкретной платформы.
Вы можете проверить скорость различных вариантов, используя программу pg_test_fsync.
Обратите внимание, что этот параметр не имеет значения, если fsync
был отключен.
Включение параметра конфигурации wal_debug (при условии, что Tantor SE был скомпилирован с поддержкой этого параметра) приведет к записи каждого вызова функций 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 SE.
Настройки maintenance_io_concurrency и wal_decode_buffer_size ограничивают параллелизм и расстояние предварительной загрузки соответственно. По умолчанию он установлен в try
, что включает эту функцию на системах, где доступна функция posix_fadvise
.