Настройка WAL

29.4. Настройка WAL

Существует несколько конфигурационных параметров относящихся к WAL, которые влияют на производительность СУБД. Далее рассказывается об их использовании. Общую информацию об установке параметров конфигурации сервера смотрите в Chapter 18.

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

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

Серверный процесс фоновой записи автоматически выполняет контрольную точку так часто, как это необходимо. Контрольная точка создаётся через каждые checkpoint_segments сегментов журнала или каждые checkpoint_timeout секунд, в зависимости от того, какое событие наступит первым. По умолчанию, соответственно настраивается 3 сегмента и 300 секунд (5 минут). Также возможен принудительный запуск контрольной точки с помощью SQL команды CHECKPOINT.

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

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

Чтобы избежать "завала" большим количеством системных операций дискового ввода/вывода из-за взрывного количества операций записи страниц, запись заполненных буферов во время контрольной точки "размазывается" на определённый период времени. Этот период управляется параметром checkpoint_completion_target, который задаётся как часть интервала контрольной точки. Количество данных ввода/вывода согласуется так, чтобы контрольная точка завершалась, когда данная часть checkpoint_segments сегментов WAL будет израсходована с момента старта контрольной точки или когда заданная часть checkpoint_timeout секунд истечёт, смотря какое событие из вышеуказанных наступит быстрее. С значением 0.5, заданным по умолчанию, PostgreSQL может ожидать завершения каждой контрольной точки примерно половину времени перед стартом следующей контрольной точки. На системах, которые очень близки к максимальному потоку данных ввода/вывода во время обычного функционирования, вы возможно захотите увеличить checkpoint_completion_target, чтобы снизить загрузку по вводу/выводу, возникающую из-за контрольных точек. Недостаток такого подхода состоит в том, что пролонгированные контрольные точки влияют на время восстановления, потому что при восстановлении нужно будет использовать большее количество сегментов WAL. Хотя значение checkpoint_completion_target может быть установлено столь высоким как 1.0, лучше оставить его поменьше (по крайней мере, предположительно, меньше 0.9), так как контрольные точки включают некоторые другие операции, помимо записи заполненных буферов. Установка значения 1.0 вполне вероятно приведёт к тому, что контрольные точки не будут завершаться вовремя, что приведёт к потере производительности из-за неожиданного изменения количества необходимых сегментов WAL.

Всегда будет по крайней мере один файл сегмента WAL и обычно также будет не более чем (2 + checkpoint_completion_target) * checkpoint_segments + 1 или checkpoint_segments + wal_keep_segments + 1 файлов. Каждый файл сегмента обычно имеет размер в 16 Mb (однако, этот размер можно изменить при компиляции сервера). Вы можете использовать этот размер для оценки требуемого дискового пространства для WAL. Обычно, когда старые файлы сегментов больше не нужны, они циклически перезаписываются (переименовываются по в порядке нумерации, для того, чтобы принять следующие сегменты). Если из-за кратковременного возрастания количества данных при выводе в журнал, образовалось более, чем 3 * checkpoint_segments + 1 файлов сегментов, ненужные файлы сегментов вместо циклической перезаписи будут удаляться до тех пор, пока система не вернётся в обычный режим работы.

В режиме архивного восстановления или горячего резерва, сервер периодически выполняет restartpoints (точку рестарта), которая похожа на которольные точки в обычном режиме работы: сервер принудительно сбрасывает своё состояние на диск, обновляет файл pg_control, чтобы показать, что уже обработанные WAL данные не нужно сканировать снова и затем циклически перезаписывает все старые файлы сегментов в каталоге pg_xlog. Точка рестарта срабатывает, если был осуществлён накат по крайей мере одной записи контрольной точки и прошло checkpoint_timeout секунд с момента последней точки рестарта. В режиме горячего резерва, точка рестарта также срабатывает если с момента последней точки рестарта был осуществлён накат checkpoint_segments сегментов журнала и был осуществлён накат по крайней мере одной контрольной точки. Точки рестарта не могут выполняться более часто, чем контрольные точки на мастер-сервере, потому что точки рестарта могут выполняться только на записях контрольных точек.

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

Параметр commit_delay задаёт как много микросекунд серверный процесс будет ожидать после записи в журнал с помощью функции LogInsert перед выполнением функции LogFlush. Данная задержка позволяет другим серверным процессам добавить свои записи в журнал так, чтобы все они были затем сохранены на диск за один проход. Если параметр fsync не включен или если в данный момент времени количество сессий в режиме транзакций меньше, чем commit_siblings задержки не будет; это помогает избежать задержки, когда маловероятно, что какая-либо другая сессия будет в ближайшее время подтверждать транзакцию. Обратите внимание, что на большинстве платформ, время задержки составляет 10 миллисекунд, так что любые ненулевые значения параметра commit_delay от 1 до 100000 микросекунд будут давать тот же эффект. Хорошие значения для этих параметров пока посоветовать трудно; требуется экспериментировать.

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

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

Back to top

(С) Виктор Вислобоков, 2008-2023