что такое wal postgresql

WAL в PostgreSQL: 2. Журнал предзаписи

В прошлый раз мы познакомились с устройством одного из важных объектов разделяемой памяти, буферного кеша. Возможность потери информации из оперативной памяти — основная причина необходимости средств восстановления после сбоя. Сегодня мы поговорим про эти средства.

Журнал

Увы, чудес не бывает: чтобы пережить потерю информации в оперативной памяти, все необходимое должно быть своевременно записано на диск (или другое энергонезависимое устройство).

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

Чтобы это работало, журнальная запись в обязательном порядке должна попасть на диск до того, как туда попадет измененная страница. Отсюда и название: журнал предзаписи (write-ahead log).

Если происходит сбой, данные на диске оказываются в рассогласованном состоянии: какие-то страницы были записаны раньше, какие-то — позже. Но остается и журнал, который можно прочитать и выполнить повторно те операции, которые уже были выполнены до сбоя, но результат которых не успел дойти до диска.

Почему принудительно не записывать на диск сами страницы с данными, зачем вместо этого выполнять двойную работу? Оказывается, так эффективнее.
Во-первых, журнал — это последовательный поток данных на запись. С последовательной записью даже HDD-диски справляются неплохо. А вот запись самих данных — случайная, потому что страницы разбросаны по диску более или менее хаотично.
Во-вторых, журнальная запись может быть гораздо меньше, чем страница.
В-третьих, при записи можно не заботиться о том, чтобы в каждый произвольный момент времени данные на диске оставались согласованными (такое требование сильно усложняет жизнь).
Ну и в-четвертых, как мы потом увидим, журнал (раз уж он есть) можно использовать не только для восстановления, но и для резервного копирования и репликации.

Журналировать нужно все операции, при выполнении которых есть риск получить несогласованность на диске в случае сбоя. В частности, в журнал записываются следующие действия:

Логическое устройство

Логически журнал можно представить себе как последовательность записей различной длины. Каждая запись содержит данные о некоторой операции, предваренные стандартным заголовком. В заголовке, в числе прочего, указаны:

Физическое устройство

Журнальные записи попадают в текущий использующийся файл; когда он заканчивается — начинает использоваться следующий.

В разделяемой памяти сервера для журнала выделены специальные буферы. Размер журнального кеша задается параметром wal_buffers (значение по умолчанию подразумевает автоматическую настройку: выделяется 1/32 часть буферного кеша).

Журнальный кеш устроен наподобие буферного кеша, но работает преимущественно в режиме кольцевого буфера: записи добавляются в «голову», а записываются на диск с «хвоста».

Позиции записи («хвоста») и вставки («головы») показывают функции pg_current_wal_lsn и pg_current_wal_insert_lsn соответственно:

Для того, чтобы сослаться на определенную запись, используется тип данных pg_lsn (LSN = log sequence number) — это 64-битное число, представляющее собой байтовое смещение до записи относительно начала журнала. LSN выводится как два 32-битных числа в шестнадцатеричной системе через косую черту.

Можно узнать, в каком файле мы найдем нужную позицию, и с каким смещением от начала файла:

Имя файла состоит из двух частей. Старшие 8 шестнадцатеричных разрядов показывают номер ветви времени (она используется при восстановлении из резервной копии), остаток соответствует старшим разрядам LSN (а оставшиеся младшие разряды LSN показывают смещение).

Упреждающая запись

Посмотрим, как происходит журналирование и как обеспечивается упреждающая запись. Создадим таблицу:

Мы будем заглядывать в заголовок табличной страницы. Для этого нам понадобится уже хорошо знакомое расширение:

Начнем транзакцию и запомним позицию вставки в журнал:

Теперь выполним какую-нибудь операцию, например, обновим строку:

Это изменение было записано и в журнал, позиция вставки изменилась:

Чтобы гарантировать, что измененная страница данных не будет вытеснена на диск раньше, чем журнальная запись, в заголовке страницы сохраняется номер LSN последней журнальной записи, относящейся к этой странице:

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

Теперь завершим транзакцию.

Запись о фиксации также попадает в журнал, и позиция снова меняется:

Фиксация меняет статус транзакции в структуре, называемой XACT (мы уже говорили про нее). Статусы хранятся в файлах, но для них тоже используется свой кеш, который занимает в разделяемой памяти 128 страниц. Поэтому и для страниц XACT приходится отслеживать номер LSN последней журнальной записи. Но эта информация хранится не в самой странице, а в оперативной памяти.

В какой-то момент созданные журнальные записи будут записаны на диск. В какой именно — мы поговорим в другой раз, но в нашем случае это уже произошло:

После этого момента страницы данных и XACT могут быть вытеснены из кеша. А вот если бы потребовалось вытеснить их раньше, это было бы обнаружено и журнальные записи были бы принудительно записаны первыми.

Зная две позиции LSN, можно получить размер журнальных записей между ними (в байтах) простым вычитанием одной позиции из другой. Надо только привести позиции к типу pg_lsn:

В данном случае обновление строки и фиксация потребовали 108 байтов в журнале.

Таким же способом можно оценить, какой объем журнальных записей генерируется сервером за единицу времени при определенной нагрузке. Это важная информация, которая потребуется при настройке (о чем мы поговорим в следующий раз).

Теперь воспользуемся утилитой pg_waldump, чтобы посмотреть на созданные журнальные записи.

Утилита может работать и с диапазоном LSN (как в этом примере), и выбрать записи для указанной транзакции. Запускать ее следует от имени пользователя ОС postgres, так как ей требуется доступ к журнальным файлам на диске.

Здесь мы видим заголовки двух записей.

Первая — операция HOT_UPDATE, относящаяся к менеджеру ресурсов Heap. Имя файла и номер страницы указаны в поле blkref и совпадают с обновленной табличной страницей:

Вторая запись — COMMIT, относящаяся к менеджеру ресурсов Transaction.

Не самый удобочитаемый формат, но при необходимости разобраться можно.

Восстановление

Когда мы стартуем сервер, первым делом запускается процесс postmaster, а он, в свою очередь, запускает процесс startup, задача которого — обеспечить восстановление, если произошел сбой.

У аккуратно остановленного сервера статус будет «shut down». Если сервер не работает, а статус остался «in production», это означает, что СУБД упала и тогда автоматически будет выполнено восстановление.

Для восстановления процесс startup будет последовательно читать журнал и применять записи к страницам, если в этом есть необходимость. Необходимость можно проверить, сравнив LSN страницы на диске с LSN журнальной записи. Если LSN страницы оказался больше, то запись применять не нужно. А на самом деле — даже и нельзя, потому что записи рассчитаны на строго последовательное применение.

Есть исключения. Часть записей формируются как полный образ страницы (FPI, full page image), и понятно, что такой образ можно применить к странице в любом состоянии — он все равно сотрет все, что там было. Еще изменение статуса транзакции можно применять к любой версии страницы XACT — поэтому внутри таких страниц нет необходимости хранить LSN.

Изменение страниц при восстановлении происходит в буферном кеше, как при обычной работе — для этого postmaster запускает необходимые фоновые процессы.

Читайте также:  что делать если не будет дождя

Аналогично журнальные записи применяются и к файлам: например, если запись говорит о том, что файл должен существовать, а его нет — файл создается.

Ну и в самом конце процесса восстановления все нежурналируемые таблицы перезаписываются «пустышками» из своих init-слоев.

Это сильно упрощенное изложение алгоритма. В частности, мы пока ничего не говорили о том, с какого места надо начинать чтение журнальных записей (этот разговор придется отложить до рассмотрения контрольной точки).

И последнее уточнение. «По классике» процесс восстановления состоит из двух фаз. На первой фазе (roll forward) накатываются журнальные записи, при этом сервер повторяет всю потерянную при сбое работу. На второй (roll back) — откатываются транзакции, которые не были зафиксированы на момент сбоя. Но PostgreSQL не нуждается во второй фазе. Как мы рассматривали ранее, благодаря особенностям реализации многоверсионности транзакции не надо откатывать физически; достаточно того, что в XACT не будет установлен бит фиксации.

Источник

Что такое wal postgresql

Параметр wal_level определяет, как много информации записывается в WAL. Со значением replica (по умолчанию) в журнал записываются данные, необходимые для поддержки архивирования WAL и репликации, включая запросы только на чтение на ведомом сервере. Вариант minimal оставляет только информацию, необходимую для восстановления после сбоя или аварийного отключения. Наконец, logical добавляет информацию, требующуюся для поддержки логического декодирования. Каждый последующий уровень включает информацию, записываемую на всех уровнях ниже. Задать этот параметр можно только при запуске сервера.

На уровне minimal некоторые массовые операции могут выполняться в обход журнала без риска потери данных, и при этом они выполнятся гораздо быстрее (см. Подраздел 14.4.7). В частности, такая оптимизация возможна с операциями:

CREATE TABLE AS
CREATE INDEX
CLUSTER
COPY с таблицами, которые были созданы или опустошены в той же транзакции

Однако такой минимальный журнал не будет содержать достаточно информации для восстановления данных из базовой копии и журналов, поэтому для реализации стратегии архивации WAL (см. archive_mode) и потоковой репликации необходим уровень replica или более высокий.

Если этот параметр установлен, сервер PostgreSQL старается добиться, чтобы изменения были записаны на диск физически, выполняя системные вызовы fsync() или другими подобными методами (см. wal_sync_method). Это даёт гарантию, что кластер баз данных сможет вернуться в согласованное состояние после сбоя оборудования или операционной системы.

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

Параметр fsync можно задать только в файле postgresql.conf или в командной строке при запуске сервера. Если вы отключаете этот параметр, возможно, имеет смысл отключить также и full_page_writes. synchronous_commit ( enum )

Определяет, после завершения какого уровня обработки WAL сервер будет сообщать об успешном выполнении операции. Допустимые значения: remote_apply (применено удалённо), on (вкл., по умолчанию), remote_write (записано удалённо), local (локально) и off (выкл.).

Если значение synchronous_standby_names не пустое, параметр synchronous_commit также определяет, должен ли сервер при фиксировании транзакции ждать, пока соответствующие записи WAL будут обработаны на ведомом сервере (серверах).

Характеристики различных значений synchronous_commit сведены в Таблице 19.1.

Таблица 19.1. Режимы synchronous_commit

значение synchronous_commit гарантированная локальная фиксация гарантированная фиксация на ведомом после сбоя PG гарантированная фиксация на ведомом после сбоя ОС согласованность запросов на ведомом
remote_apply
on
remote_write
local
off

Метод, применяемый для принудительного сохранения изменений WAL на диске. Если режим fsync отключён, данный параметр не действует, так как принудительное сохранение изменений WAL не производится вовсе. Возможные значения этого параметра:

open_datasync (для сохранения файлов WAL открывать их функцией open() с параметром O_DSYNC )

fdatasync (вызывать fdatasync() при каждом фиксировании)

fsync (вызывать fsync() при каждом фиксировании)

fsync_writethrough (вызывать fsync() при каждом фиксировании, форсируя сквозную запись кеша)

open_sync (для сохранения файлов WAL открывать их функцией open() с параметром O_SYNC )

Когда этот параметр включён, сервер PostgreSQL записывает в WAL всё содержимое каждой страницы при первом изменении этой страницы после контрольной точки. Это необходимо, потому что запись страницы, прерванная при сбое операционной системы, может выполниться частично, и на диске окажется страница, содержащая смесь старых данных с новыми. При этом информации об изменениях на уровне строк, которая обычно сохраняется в WAL, будет недостаточно для получения согласованного содержимого такой страницы при восстановлении после сбоя. Сохранение образа всей страницы гарантирует, что страницу можно восстановить корректно, ценой увеличения объёма данных, которые будут записываться в WAL. (Так как воспроизведение WAL всегда начинается от контрольной точки, достаточно сделать это при первом изменении каждой страницы после контрольной точки. Таким образом, уменьшить затраты на запись полных страниц можно, увеличив интервалы контрольных точек.)

Отключение этого параметра не влияет на возможность применения архивов WAL для восстановления состояния на момент времени (см. Раздел 25.3).

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

Этот параметр позволяет без дополнительных рисков повреждения данных уменьшить объём WAL, ценой дополнительной нагрузки на процессор, связанной со сжатием данных при записи в WAL и разворачиванием их при воспроизведении WAL. wal_buffers ( integer )

Содержимое буферов WAL записывается на диск при фиксировании каждой транзакции, так что очень большие значения вряд ли принесут значительную пользу. Однако значение как минимум в несколько мегабайт может увеличить быстродействие при записи на нагруженном сервере, когда сразу множество клиентов фиксируют транзакции. Автонастройка, действующая при значении по умолчанию (-1), в большинстве случаев выбирает разумные значения. wal_writer_delay ( integer )

Определяет, как часто процесс записи WAL будет сбрасывать WAL на диск. После очередного сброса WAL он делает паузу на wal_writer_delay миллисекунд, но может быть пробуждён асинхронно фиксируемой транзакцией. Если предыдущая операция сброса имела место в последние wal_writer_delay миллисекунд и после неё было получено меньше wal_writer_flush_after байт WAL, данные WAL только передаются ОС, но не сбрасываются на диск. Значение по умолчанию — 200 миллисекунд ( 200ms ). Заметьте, что во многих системах разрешение таймера паузы составляет 10 мс; если задать в wal_writer_delay значение, не кратное 10, может быть получен тот же результат, что и со следующим за ним кратным 10. Задать этот параметр можно только в postgresql.conf или в командной строке при запуске сервера. wal_writer_flush_after ( integer )

В PostgreSQL до версии 9.3, параметр commit_delay работал по-другому и не так эффективно: он задерживал только фиксирование транзакций, а не все операции сохранения WAL, и заданная пауза выдерживалась полностью, даже если WAL удавалось сохранить быстрее. Начиная с версии 9.3, заданное время ожидает только первый процесс, готовый произвести сохранение, тогда как все последующие процессы ждут только, когда он закончит эту операцию. commit_siblings ( integer )

19.5.2. Контрольные точки

Максимальное время между автоматическими контрольными точками в WAL (в секундах). Допускаются значения от 30 секунд до одного дня. Значение по умолчанию — пять минут ( 5min ). Увеличение этого параметра может привести к увеличению времени, которое потребуется для восстановления после сбоя. Задать этот параметр можно только в postgresql.conf или в командной строке при запуске сервера. checkpoint_completion_target ( floating point )

Задаёт целевое время для завершения процедуры контрольной точки, как коэффициент для общего времени между контрольными точками. По умолчанию это значение равно 0.5. Задать этот параметр можно только в postgresql.conf или в командной строке при запуске сервера. checkpoint_flush_after ( integer )

Когда в процессе контрольной точки записывается больше чем checkpoint_flush_after байт, сервер даёт указание ОС произвести запись этих данных в нижележащее хранилище. Это ограничивает объём «грязных» данных в страничном кеше ядра и уменьшает вероятность затормаживания при выполнении fsync в конце этой контрольной точки или когда ОС сбрасывает данные на диск большими блоками в фоне. Часто это значительно уменьшает задержки транзакций, но бывают ситуации (особенно когда объём рабочей нагрузки больше shared_buffers, но меньше страничного кеша ОС), когда производительность может упасть. Этот параметр действует не на всех платформах. Он может принимать значение от 0 (при этом управление отложенной записью отключается) до 2 мегабайт ( 2MB ). Значение по умолчанию — 256kB в Linux и 0 в других ОС. (Если BLCKSZ отличен от 8 КБ, значение по умолчанию и максимум корректируются пропорционально.) Задать этот параметр можно только в postgresql.conf или в командной строке при запуске сервера. checkpoint_warning ( integer )

Пока WAL занимает на диске меньше этого объёма, старые файлы WAL в контрольных точках всегда перерабатываются, а не удаляются. Это позволяет зарезервировать достаточно места для WAL, чтобы справиться с резкими скачками использования WAL, например, при выполнении больших пакетных заданий. Значение по умолчанию — 80 МБ. Этот параметр можно установить только в postgresql.conf или в командной строке сервера.

19.5.3. Архивация

Когда параметр archive_mode включён, полные сегменты WAL передаются в хранилище архива командой archive_command. Помимо значения off (выключающего архивацию) есть ещё два: on (вкл.) и always (всегда). В обычном состоянии эти два режима не различаются, но в режиме always архивация WAL активна и во время восстановления архива, и при использовании ведомого сервера. В этом режиме все файлы, восстановленные из архива или полученные при потоковой репликации, будут архивироваться (снова). За подробностями обратитесь к Подразделу 26.2.9.

Параметры archive_mode и archive_command разделены, чтобы команду архивации ( archive_command ) можно было изменять, не отключая режим архивации. Этот параметр можно задать только при запуске сервера. Режим архивации нельзя включить, когда установлен минимальный уровень WAL ( wal_level имеет значение minimal ). archive_command ( string )

Источник

WAL в PostgreSQL: 3. Контрольная точка

Мы уже познакомились с устройством буферного кеша — одного из основных объектов в разделяемой памяти, — и поняли, что для восстановления после сбоя, когда содержимое оперативной памяти пропадает, нужно вести журнал предзаписи.

Нерешенная проблема, на которой мы остановились в прошлый раз, состоит в том, что неизвестно, с какого момента можно начинать проигрывание журнальных записей при восстановлении. Начать с начала, как советовал Король из Алисы, не получится: невозможно хранить все журнальные записи от старта сервера — это потенциально и огромный объем, и такое же огромное время восстановления. Нам нужна такая постепенно продвигающаяся вперед точка, с которой мы можем начинать восстановление (и, соответственно, можем безопасно удалять все предшествующие журнальные записи). Это и есть контрольная точка, о которой сегодня пойдет речь.

Контрольная точка

Каким свойством должна обладать контрольная точка? Мы должны быть уверены, что все журнальные записи, начиная с контрольной точки, будут применяться к страницам, записанным на диск. Если бы это было не так, при восстановлении мы могли бы прочитать с диска слишком старую версию страницы и применить к ней журнальную запись, и тем самым безвозвратно повредили бы данные.

Как получить контрольную точку? Самый простой вариант — периодически приостанавливать работу системы и сбрасывать все грязные страницы буферного и других кешей на диск. (Заметим, что страницы только записываются, но не вытесняются из кеша.) Такие точки будет удовлетворять условию, но, конечно, никто не захочет работать с системой, постоянно замирающей на неопределенное, но весьма существенное время.

Поэтому на практике все несколько сложнее: контрольная точка из точки превращается в отрезок. Сперва мы начинаем контрольную точку. После этого, не прерывая работу и по возможности не создавая пиковых нагрузок, потихоньку сбрасываем грязные буферы на диск.

Когда все буферы, которые были грязными на момент начала контрольной точки, окажутся записанными, контрольная точка считается завершенной. Теперь (но не раньше) мы можем использовать момент начала в качестве той точки, с которой можно начинать восстановление. И журнальные записи вплоть до этого момента нам больше не нужны.

Выполнением контрольной точки занимается специальный фоновый процесс checkpointer.

Продолжительность записи грязных буферов определяется значением параметра checkpoint_completion_target. Он показывает, какую часть времени между двумя соседними контрольными точками будет происходить запись. Значение по умолчанию равно 0.5 (как на рисунках выше), то есть запись занимает половину времени между контрольными точками. Обычно значение увеличивают вплоть до 1.0 для большей равномерности.

Рассмотрим подробнее, что происходит при выполнении контрольной точки.

Сначала процесс контрольной точки сбрасывает на диск буферы статуса транзакций (XACT). Поскольку их немного (всего 128), они записываются сразу же.

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

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

Помеченные буферы могут также быть записаны и серверными процессами — смотря кто доберется до буфера первым. В любом случае при записи снимается установленный ранее флаг, так что (для целей контрольной точки) буфер будет записан только один раз.

Естественно, в ходе выполнения контрольной точки страницы продолжают изменяться в буферном кеше. Но новые грязные буферы не помечены флагом и процесс контрольной точки не должен их записывать.

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

Чтобы посмотреть на работу контрольной точки, создадим какую-нибудь таблицу — ее страницы попадут в буферный кеш и будут грязными:

Запомним текущую позицию в журнале:

Теперь выполним контрольную точку вручную и убедимся, что в кеше не осталось грязных страниц (как мы говорили, новые грязные страницы могут появляться, но в нашем случае никаких изменений в процессе выполнения контрольной точки не происходило):

Посмотрим, как контрольная точка отразилась в журнале:

Здесь мы видим две записи. Последняя из них — запись о прохождении контрольной точки (CHECKPOINT_ONLINE). LSN начала контрольной точки указан после слова redo, и эта позиция соответствует журнальной записи, которая в момент начала контрольной точки была последней.

Ту же информацию мы найдем и в управляющем файле:

Восстановление

Теперь мы готовы уточнить алгоритм восстановления, намеченный в прошлой статье.

Если в работе сервера произошел сбой, то при последующем запуске процесс startup обнаруживает это, посмотрев в файл pg_control и увидев статус, отличный от «shut down». В этом случае выполняется автоматическое восстановление.

Сначала процесс восстановления прочитает из того же pg_control позицию начала контрольной точки. (Для полноты картины заметим, что, если присутствует файл backup_label, то запись о контрольной точке читается из него — это нужно для восстановления из резервных копий, но это тема для отдельного цикла.)

Далее он будет читать журнал, начиная с найденной позиции, последовательно применяя журнальные записи к страницам (если в этом есть необходимость, как мы уже обсуждали в прошлый раз).

В заключение все нежурналируемые таблицы перезаписываются с помощью образов в init-файлах.

На этом процесс startup завершает работу, а процесс checkpointer тут же выполняет контрольную точку, чтобы зафиксировать на диске восстановленное состояние.

Можно сымитировать сбой, принудительно остановив сервер в режиме immediate.

Проверим состояние кластера:

При запуске PostgreSQL понимает, что произошел сбой и требуется восстановление.

Необходимость восстановления отмечается в журнале сообщений: database system was not properly shut down; automatic recovery in progress. Затем начинается проигрывание журнальных записей с позиции, отмеченной в «redo starts at» и продолжается до тех пор, пока удается получать следующие журнальные записи. На этом восстановление завершается в позиции «redo done at» и СУБД начинает работать с клиентами (database system is ready to accept connections).

А что происходит при нормальной остановке сервера? Чтобы сбросить грязные страницы на диск, PostgreSQL отключает всех клиентов и затем выполняет финальную контрольную точку.

Запомним текущую позицию в журнале:

Теперь аккуратно останавливаем сервер:

Проверим состояние кластера:

А в журнале обнаружим единственную запись о финальной контрольной точке (CHECKPOINT_SHUTDOWN):

(Страшным фатальным сообщением pg_waldump всего-навсего хочет сказать о том, что дочитал до конца журнала.)

Снова запустим экземпляр.

Фоновая запись

Как мы выяснили, контрольная точка — один из процессов, который записывает грязные страницы из буферного кеша на диск. Но не единственный.

Если обслуживающему процессу (backend) потребуется вытеснить страницу из буфера, а страница окажется грязной, ему придется самостоятельно записать ее на диск. Это нехорошая ситуация, приводящая к ожиданиям — гораздо лучше, когда запись происходит асинхронно, в фоновом режиме.

Поэтому в дополнение к процессу контрольной точки (checkpointer) существует также процесс фоновой записи (background writer, bgwriter или просто writer). Этот процесс использует тот же самый алгоритм поиска буферов, что и механизм вытеснения. Отличий по большому счету два.

Настройка

26.05.2020 — в раздел внесены уточнения. Спасибо stegmatic, указавшему на ошибку.

Процесс контрольной точки обычно настраивается из следующих соображений.

Сначала надо определиться, какой объем журнальных файлов мы можем себе позволить сохранять между двумя последовательными контрольными точками (и какое время восстановления нас устраивает). Чем больше, тем лучше, но по понятным причинам это значение будет ограничено.

Далее мы можем посчитать, за какое время при обычной нагрузке будет генерироваться этот объем. Как это делать, мы уже рассматривали (надо запомнить позиции в журнале и вычесть одну из другой).

Это время и будет нашим обычным интервалом между контрольными точками. Записываем его в параметр checkpoint_timeout. Значение по умолчанию — 5 минут — явно слишком мало, обычно время увеличивают, скажем, до получаса. Повторюсь: чем реже можно позволить себе контрольные точки, тем лучше — это сокращает накладные расходы.

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

Сервер хранит журнальные файлы не только за прошедшую завершенную контрольную точку, но и за текущую еще не завершенную. Поэтому для получения общего объема надо умножать
объем между контрольными точками на (1 + checkpoint_completion_target). А до версии 11 — на (2 + checkpoint_completion_target), поскольку PostgreSQL хранил файлы и за позапрошлую контрольную точку тоже.

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

Важно понимать, что значение max_wal_size может быть превышено:

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

Процесс фоновой записи работает циклами максимум по bgwriter_lru_maxpages страниц, засыпая между циклами на bgwriter_delay.

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

Значения по умолчанию: bgwriter_delay = 200ms (скорее всего слишком много, за 1/5 секунды много воды утечет), bgwriter_lru_maxpages = 100, bgwriter_lru_multiplier = 2.0 (пытаемся реагировать на спрос с опережением).

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

Мониторинг

Настройку контрольной точки и фоновой записи можно и нужно корректировать, получая обратную связь от мониторинга.

Параметр checkpoint_warning выводит предупреждение, если контрольные точки, вызванные переполнением размера журнальных файлов, выполняются слишком часто. Его значение по умолчанию — 30 секунд, и его надо привести в соответствие со значением checkpoint_timeout.

Параметр log_checkpoints (выключеный по умолчанию) позволяет получать в журнале сообщений сервера информацию о выполняемых контрольных точках. Включим его.

Теперь поменяем что-нибудь в данных и выполним контрольную точку.

В журнале сообщений мы увидим примерно такую информацию:

Тут видно, сколько буферов было записано, как изменился состав журнальных файлов после контрольной точки, сколько времени заняла контрольная точка и расстояние (в байтах) между соседними контрольными точками.

Но, наверное, самая полезная информация — это статистика работы процессов контрольной точки и фоновой записи в представлении pg_stat_bgwriter. Представление одно на двоих, потому что когда-то обе задачи выполнялись одним процессом; затем их функции разделили, а представление так и осталось.

Здесь, в числе прочего, мы видим количество выполненных контрольных точек:

Важная информация о количестве записанных страниц:

Еще для настройки фоновой записи пригодится maxwritten_clean — это число показывает, сколько раз процесс фоновой записи прекращал работу из-за превышения bgwriter_lru_maxpages.

Сбросить накопленную статистику можно с помощью следующего вызова:

Источник

Читайте также:  что делать при пониженной температуре тела у взрослого при коронавирусе
Строительный портал