Надежность и журнал упреждающей записи

В этой главе объясняется, как журнал упреждающей записи (Write Ahead Log, WAL) используется для обеспечения эффективной и надежной работы.

Надежность

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

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

Далее,кеш может быть в дисковом контроллере - это особенно распространено на RAID-контроллерах. Некоторые из этих кэшей являются сквозными, что означает, что записи отправляются на диск сразу после их поступления. У другие есть обратная запись, то есть данные отправляются на диск через некоторое время. Такие кеши могут быть угрозой надежности, поскольку память в кеше дискового контроллера может оказаться энергозависимой и теряет свое содержимое при сбое питания - качественные контроллеры имеют резервные блоки батарей (Battery Backup Unit, BBU), это означает, что в составе контроллера есть батарея, которая поддерживает питание кеша в случае потери питания системы. После восстановления питания данные будут корректно записаны на дисководы.

И, наконец, большинство дисководов имеют внутренный кеш. Некоторые из них имеют кеш со сквозной, а другие с обратной записью, и для кэшей дисков с обратной записью существуют те же проблемы, что и для дисковых кэшей контроллера. Диски IDE и SATA потребительского уровня особенно часто имеют кэши обратной записи, который не выдержат сбоя питания. Многие твердотельные накопители (SSD) также имеют энергозависимые кэши обратной записи.

Эти кэши обычно можно отключить - однако способ сделать это зависит от операционной системы и типа диска. В Linux диски IDE и SATA можно запрашивать с помощью hdparm -I. Кэширование записи включено, если рядом с Write cache есть *. hdparm -W 0 может использоваться для отключения кэширования записи. Диски SCSI могут быть запрошены с помощью sdparm. Используйте sdparm --get=WCE чтобы проверить, включен ли кэш записи, и sdparm --clear=WCE чтобы отключить его.

Диски SATA последних моделей (те, которые следуют стандарту ATAPI-6 или более новому) предлагают команду очистки кэша диска FLUSH CACHE EXT, в то время как диски SCSI уже давно поддерживают аналогичную команду SYNCHRONIZE CACHE. Эти команды не доступны напрямую для QHB, но некоторые файловые системы (например, ZFS, ext4 ) могут использовать их для сброса данных на диски на дисках с обратной записью. К сожалению, такие файловые системы ведут себя неоптимально в сочетании с дисковыми контроллерами с BBU. В таких системах команда синхронизации направляет все данные из кэша контроллера на диски, что исключает большую часть преимуществ BBU. Если QHB установлена в такую среду, преимущества BBU для производительности можно восстановить, отключив барьеры записи в файловой системе или перенастроив контроллер диска, если это возможно. Если барьеры записи отключены, убедитесь, что батарея остается работоспособной - неисправный аккумулятор может привести к потере данных.

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

Еще один риск потери данных связан с самими операциями записи на диск. Пластины механического устройства хранения, как правило, разделены на сектора, обычно по 512 байт каждый. Каждая физическая операция чтения или записи обрабатывает целый сектор. Когда на диск поступает запрос на запись, он может быть кратен 512 байтам ( QHB обычно записывает 8192 байт или 16 секторов за раз), и в процессе записи может произойти сбой из-за потери питания в любое время, что означает, что некоторые из 512-байтовых секторов были записаны, а другие нет. Чтобы защититься от таких сбоев, QHB периодически записывает полностраничные образы в постоянное хранилище WAL перед изменением фактической страницы на диске. Таким образом, во время восстановления после сбоя QHB может восстановить частично записанные страницы из WAL. Если используется файловая система, которая предотвращает частичную запись страниц (например, ZFS), вы можете отключить полностраничное представление (запись 8 КБ или 16 секторов за раз), отключив параметр full_page_writes. Дисковые контроллеры с батарейным блоком (BBU) не предотвращают частичную запись страниц, если они не гарантируют, что данные записываются в BBU как полные (8 КБ) страницы.

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

  • Каждая отдельная запись в файле WAL защищена проверкой CRC-32 (32-разрядная версия), которая позволяет нам определить правильность содержимого записи. Значение CRC устанавливается при записи каждой записи WAL и проверяется во время восстановления после сбоя, восстановления архива и репликации.

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

  • Внутренние структуры данных хранящиеся на диске, такие как pg_xact, pg_subtrans, pg_multixact, pg_serial, pg_notify, pg_stat, pg_snapshots, не проверяются при помощи контрольных сумм, а страницы не защищены полными записями страниц (по 8Кб). Однако там, где такие структуры данных являются постоянными, записываются записи WAL, которые позволяют точно выстроить заново последние изменения при восстановлении после сбоя, и эти записи WAL защищены, как обсуждалось выше.

  • Отдельные файлы состояний в pg_twophase защищены CRC-32.

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

QHB не защищает от исправляемых ошибок памяти, и предполагается, что вы будете работать с ОЗУ, которое использует отраслевой стандарт исправления ошибок (ECC) или более эффективную защиту.

Журнал упреждающей записи

Запись в журнал упреждающей записи (Write Ahead Log, WAL ) - это стандартный метод обеспечения целостности данных. Подробное описание можно найти в большинстве (если не во всех) справочных и учебных пособиях по обработке транзакций. Центральная концепция WAL заключается в том, что изменения в файлах данных (в которых находятся таблицы и индексы) должны записываться только после того, как эти изменения были зарегистрированы, то есть после того, как записи журнала, описывающие изменения, были сброшены в постоянное хранилище. Если мы следуем этой процедуре, нам не нужно сбрасывать страницы данных на диск при каждой фиксации транзакции, потому что мы знаем, что в случае сбоя мы сможем восстановить базу данных, используя журнал: любые изменения, которые не были применены на страницы данных могут быть восстановлены из записей журнала. (Это восстановление с повтором транзакций, также известно как REDO).

Заметка
Поскольку WAL восстанавливает содержимое файла базы данных после сбоя, журнальные файловые системы не нужны для надежного хранения файлов данных или файлов WAL. Фактически, издержки журналирования могут снизить производительность, особенно если журналирование часто приводит к сбросу данных файловой системы на диск. Сброс данных журнала часто может быть отключен с помощью опции монтирования файловой системы, например data=writeback в файловой системе Linux ext3. Журналированные файловые системы улучшают скорость загрузки после сбоя.

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

WAL также позволяет поддерживать оперативное резервное копирование и восстановление на определенный момент времени, как описано в разделе Выполнение восстановления на момент времени (PITR). Архивируя данные WAL, мы можем поддерживать возврат к любому моменту времени, охваченному доступными данными WAL: мы просто устанавливаем предварительную физическую резервную копию базы данных и "воспроизводим" изменения из журнала столько раз, сколько необходимо. Более того, физическое резервное копирование не должно быть мгновенным снимком состояния базы данных - если оно выполнено в течение некоторого периода времени, то повторное воспроизведение журнала за этот период устранит любые внутренние несоответствия.

Асинхронный коммит

Асинхронная фиксация (asynchronous commit) - это опция, которая позволяет транзакциям завершаться быстрее, за счет того, что самые последние транзакции могут быть потеряны в случае сбоя базы данных. Во многих приложениях это приемлемый компромисс.

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

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

Риск, связанный с использованием асинхронной фиксации транзакций, - это потеря данных, а не их повреждение. Если база данных выйдет из строя, она восстановится путем воспроизведения WAL до последней записи, которая была сохранена. Поэтому база данных будет восстановлена в самосогласованном состоянии, но любые транзакции, которые еще не были записаны на диск, не будут отражены в этом состоянии. Таким образом, минимальные последствия - потеря нескольких последних транзакций. Поскольку транзакции воспроизводятся в порядке фиксации, может быть внесено несоответствие - например, если транзакция B внесла изменения, полагаясь на изменения внесённые предыдущей транзакцией A, невозможно восстановить эффекты A, в то время как эффекты B сохранены.

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

Некоторые служебные команды, например DROP TABLE, принудительно фиксируются синхронно, независимо от значения параметра synchronous_commit. Это необходимо для обеспечения согласованности между файловой системой сервера и логическим состоянием базы данных. Команды, поддерживающие двухфазную фиксацию, такие как PREPARE TRANSACTION, также всегда являются синхронными.

Если во время окна риска между асинхронной фиксацией и записью изменений в WAL транзакции происходит сбой базы данных, изменения, сделанные во время этой транзакции, будут потеряны. Продолжительность окна риска ограничена, потому что фоновый процесс ( WAL writer) сбрасывает новые записи WAL на диск каждые миллисекунды wal_writer_delay . Фактическая максимальная продолжительность окна риска в три раза больше wal_writer_delay потому что средство записи WAL предназначено для записи целых страниц за раз в периоды нагрузки.

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

Асинхронная фиксация транзакции обеспечивает поведение, отличное от установки fsync = off. fsync - это параметр для всего сервера, который будет изменять поведение всех транзакций. Он отключает всю логику в QHB, которая пытается синхронизировать записи в различные части базы данных, и, следовательно, сбой системы (то есть сбой оборудования или операционной системы, а не сбой самого QHB) может привести к сколь угодно плохому повреждению состояния базы данных - от потери отдельных таблиц до полной непригодности. Во многих сценариях асинхронная фиксация транзакций обеспечивает значительное улучшение производительности, которое можно получить, отключив fsync, но без риска повреждения данных.

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

Конфигурация WAL

Существует несколько параметров конфигурации, связанных с WAL, которые влияют на производительность базы данных. Этот раздел объясняет их использование. Обратитесь к Главе Конфигурация сервера за общей информацией о настройке параметров конфигурации сервера.

Checkpoints это "точки" в последовательности транзакций, при которых гарантируется, что файлы данных и индекса были обновлены и сохранена вся информация, записанная до этой контрольной точки. Во время контрольной точки все грязные страницы данных сбрасываются на диск, и в файл журнала записывается специальная запись контрольной точки. (Записи изменений ранее были сброшены в файлы WAL). В случае сбоя процедура восстановления после сбоя находит последнюю запись контрольной точки, чтобы определить точку в журнале (известную как запись 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, как обсуждалось выше. Поэтому целесообразно устанавливать параметры контрольных точек достаточно высокими, чтобы контрольные точки не возникали слишком часто. В качестве простой проверки работоспособности параметров вашей контрольной точки вы можете установить параметр checkpoint_warning. Если контрольные точки расположены ближе друг к другу, чем секунды checkpoint_warning, в журнал сервера будет выведено сообщение с рекомендацией увеличить max_wal_size. Случайное появление такого сообщения не является причиной для тревоги, но если оно появляется часто, то параметры контроля контрольной точки должны быть увеличены. Массовые операции, такие как чтения больщих таблиц с помощью COPY могут вызвать появление ряда таких предупреждений, если вы не установили max_wal_size достаточно высоким.

Чтобы избежать переполнения системы ввода-вывода с помощью записи страниц, запись грязных буферов во время контрольной точки распределяется на некоторый период времени. Этот период контролируется checkpoint_completion_target, который задается как часть интервала контрольных точек. Скорость ввода-вывода регулируется таким образом, чтобы контрольная точка заканчивалась по истечении заданной доли секунды checkpoint_timeout или до превышения max_wal_size, в зависимости от того, что наступит раньше. При значении по умолчанию 0,5 QHB может завершить каждую контрольную точку примерно за половину времени до запуска следующей контрольной точки. В системе, которая очень близка к максимальной пропускной способности ввода-вывода при нормальной работе, вы можете увеличить checkpoint_completion_target чтобы уменьшить нагрузку ввода-вывода с контрольных точек. Недостатком этого является то, что продление контрольных точек влияет на время восстановления, поскольку необходимо будет хранить больше сегментов WAL для возможного использования для восстановления. Хотя 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 предполагает, что сегментов требуется мало.

Независимо от max_wal_size, wal_keep_segments + 1 самые последние файлы WAL хранятся всегда. Кроме того, если используется архивация WAL, старые сегменты не могут быть удалены или повторно использованы, пока они не будут заархивированы. Если архивация WAL не может идти одновременно со скоростью, с которой генерируется WAL, или если archive_command неоднократно завершается с ошибкой, старые файлы WAL будут накапливаться в pg_wal до тех пор, пока ситуация не разрешиться. Медленный или сбойный резервный сервер, который использует слот репликации, будет давать такой же эффект.

В режиме восстановления архива или в режиме ожидания сервер периодически выполняет точки перезапуска, которые аналогичны контрольным точкам в обычной работе: сервер переносит все свое состояние на диск, обновляет файл 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 для увеличения пропускной способности транзакций до определенного уровня. Значение, составляющее половину среднего времени, операции записи 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 определяет, как QHB будет запрашивать ядро ОС для принудительного обновления WAL на диск. Все параметры должны быть одинаковыми с точки зрения надежности, за исключением fsync_writethrough, который иногда может вызвать очистку дискового кэша, даже если другие параметры этого не делают это зависит от платформы, на которой работает QHB. Обратите внимание, что этот параметр не имеет значения, если fsync отключен.

WAL детали реализации

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

Записи WAL добавляются в журналы WAL по мере возникновения каждой новой записи. Позиция вставки описывается порядковым номером журнала (LSN), который представляет собой байтовое смещение в журналах, монотонно увеличивающееся с каждой новой записью. Значения LSN имеют тип данных pg_lsn. Значения можно сравнивать для расчета объема данных WAL, которые их разделяют, поэтому они используются для измерения объёмов и процесса репликации и восстановления.

Журналы WAL хранятся на диске в каталоге pg_wal в виде набора файлов сегментов, обычно каждый размером 16 МБ (но размер можно изменить, изменив параметр --wal-segsize qhb_bootstrap). Каждый сегмент делится на страницы, обычно по 8 кБ каждая (этот размер можно изменить с помощью параметра конфигурации --with-wal-blocksize). Cодержание записи зависит от типа регистрируемого события. Сегментным файлам присваиваются постоянно растущие числа в качестве имен, начиная с 000000010000000000000000. Числа не переносятся при переполнении, но потребуется очень и очень много времени, чтобы исчерпать доступный запас чисел.

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

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

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

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