Журналирование
Контрольная точка
16
Авторские права
© Postgres Professional, 2016–2025
Авторы: Егор Рогов, Павел Лузанов, Илья Баштанов, Игорь Гнатюк
Фото: Олег Бартунов (монастырь Пху и пик Бхрикути, Непал)
Использование материалов курса
Некоммерческое использование материалов курса (презентации,
демонстрации) разрешается без ограничений. Коммерческое
использование возможно только с письменного разрешения компании
Postgres Professional. Запрещается внесение изменений в материалы
курса.
Обратная связь
Отзывы, замечания и предложения направляйте по адресу:
Отказ от ответственности
Компания Postgres Professional не несет никакой ответственности за
любые повреждения и убытки, включая потерю дохода, нанесенные
прямым или непрямым, специальным или случайным использованием
материалов курса. Компания Postgres Professional не предоставляет
каких-либо гарантий на материалы курса. Материалы курса
предоставляются на основе принципа «как есть» и компания Postgres
Professional не обязана предоставлять сопровождение, поддержку,
обновления, расширения и изменения.
2
Темы
Процесс контрольной точки
Процесс фоновой записи
Мониторинг
3
Контрольная точка
Необходимость контрольной точки
Процесс выполнения контрольной точки
Алгоритм восстановления после сбоя
Настройка
4
Необходимость
Размер хранимых журнальных записей
с какого сегмента начинать применять журнальные записи
при восстановлении?
активно использующаяся страница может не вытесняться из кеша
Время восстановления
сколько времени займет восстановление после сбоя?
Если не предпринять специальных мер, то активно использующаяся
страница, попав в буферный кеш, может никогда не вытесняться.
Это означает, что при восстановлении после сбоя нам придется
просматривать все журнальные записи, созданные с момента запуска
сервера.
На практике это, конечно, недопустимо. Во-первых, файлы занимают
много места — их все придется хранить на сервере. Во-вторых, время
восстановления будет запредельно большим — придется просмотреть
множество журнальных записей.
Поэтому существует процедура контрольной точки, которая
выполняет сброс всех грязных страниц на диск, но не вытесняет их
из кеша. Специальный фоновый процесс checkpointer периодически
выполняет контрольную точку. После того как контрольная точка
завершена, журнальные записи, предшествующие ее началу, больше
не нужны для восстановления.
5
Процесс контрольной точки
записываются грязные буферы CLOG
CLOG
Рассмотрим подробнее, что происходит при выполнении контрольной
точки.
Во-первых, помимо буферного кеша, в оперативной памяти
располагаются и другие структуры, содержимое которых нужно
сохранять на диске.
В частности, контрольная точка сбрасывает на диск буферы статуса
транзакций (CLOG). Поскольку количество таких буферов невелико
(их 128 штук), они записываются сразу же.
6
Процесс контрольной точки
31 12
1 0
помечаются измененные страницы в буферном кеше
Во-вторых, основная работа контрольной точки — сбросить на диск все
страницы из буферного кеша, которые были грязными на момент
начала контрольной точки.
Поскольку размер буферного кеша может быть очень велик,
сбрасывать сразу все страницы плохо — это приостановит нормальную
работу сервера и создаст большую нагрузку на дисковую подсистему.
Поэтому контрольная точка растягивается во времени и фактически
превращается в отрезок.
Сначала все измененные на текущий момент страницы помечаются
в заголовке буфера специальным флагом...
7
Процесс контрольной точки
31 12
1 0
помеченные страницы постепенно записываются,
пометка убирается из заголовка буфера
checkpoint_completion_target = 0.9
стал
грязным
после начала
контрольной
точки
...а затем процесс контрольной точки постепенно проходит по всем
буферам и сбрасывает помеченные страницы на диск. Еще раз
отметим, что страницы не вытесняются из кеша, а только
записываются. Поэтому контрольная точка не обращает внимания на
число обращений к буферу и признак закрепленности.
Помеченные буферы могут также быть записаны и обслуживающими
процессами — смотря кто доберется до буфера первым. В любом
случае при записи снимается установленный ранее флаг, так что буфер
будет записан только один раз.
В процессе работы контрольной точки страницы продолжают
изменяться в буферном кеше. Но новые грязные буферы уже не
рассматриваются процессом контрольной точки, так как на момент
начала работы они не были грязными.
Активность записи грязных буферов определяется значением
параметра checkpoint_completion_target. Он показывает, какую часть
времени между двумя соседними контрольными точками следует
использовать для записи страниц. Со значением 0.9, заданным
по умолчанию, можно ожидать, что PostgreSQL завершит процедуру
контрольной точки незадолго до следующей запланированной.
Значения выше умолчательного 0.9 использовать не рекомендуется,
поскольку фактически процесс может занять несколько больше
времени, чем указано в параметре.
8
Процесс контрольной точки
в журнале создается запись о завершении контрольной точки
с указанием момента ее начала
в файл pg_control записывается LSN контрольной точки
WAL
Latest checkpoint location: 0/1BA0CD8
PGDATA/global/pg_control
в этот
момент началась
контрольная
точка
запись
о завершении
контрольной
точки
Latest checkpoint's REDO location: 0/1BA0CA0
В конце работы процесс создает журнальную запись об окончании
контрольной точки. В этой записи содержится LSN момента начала
работы контрольной точки. Поскольку контрольная точка ничего не
записывает в журнал в начале своей работы, по этому LSN может
находиться любая журнальная запись.
Кроме того, в специальный файл PGDATA/global/pg_control
записывается указание на созданную журнальную запись. Таким
образом можно быстро выяснить последнюю пройденную контрольную
точку.
10
Восстановление
При старте сервера после сбоя
1. найти LSN
0
начала последней завершенной контрольной точки
2. применить каждую запись журнала, начиная с LSN
0
,
если LSN записи больше, чем LSN страницы
3. оборвать начатые, но незафиксированные транзакции
4. перезаписать нежурналируемые таблицы init-файлами
5. выполнить контрольную точку
xid
контрольная точка
контрольная точка сбой
необходимые файлы журнала
начало
восстановления
Если в работе сервера произошел сбой, то при последующем запуске
процесс startup обнаруживает это (в файле pg_control статус отличен
от «shut down») и выполняет автоматическое восстановление.
Сначала процесс читает из того же файла LSN записи о последней
завершенной контрольной точке. Из этой записи процесс узнает
позицию LSN
0
начала этой контрольной точки.
(Для полноты картины заметим: если присутствует файл backup_label,
запись о контрольной точке читается из него — это нужно для
восстановления из резервных копий. Подробнее см. курс DBA3.)
Далее процесс startup читает журнал вперед от найденной позиции,
последовательно применяя записи к страницам, если в этом есть
необходимость (что можно проверить, сравнив LSN страницы на диске
с LSN журнальной записи). Изменение страниц происходит в буферном
кеше, как при обычной работе.
Записи, относящиеся к страницам CLOG, восстанавливают статус
транзакций. Транзакции, не зафиксированные к концу восстановления,
считаются оборванными; их изменения не видны в снимках данных.
Аналогично записи применяются и к файлам: например, если запись
говорит, что файл должен быть создан, а его нет — файл создается.
В конце процесса все нежурналируемые таблицы перезаписываются
с помощью образов в init-файлах. На этом процесс startup завершает
работу, после чего процесс checkpointer выполняет контрольную точку,
чтобы зафиксировать восстановленное состояние.
12
Частота контрольных точек
объем WAL
checkpoint_timeout
max_wal_size
время
checkpoint_timeout = 5min
max_wal_size = 1GB
между
контрольными
точками
с начала текущей
контрольной точки
Обычно контрольная точка настраивается из следующих соображений.
Сначала надо определиться, какая частота срабатываний нас
устраивает (исходя из допустимого времени восстановления и объема
журнальных файлов за это время при стандартной нагрузке). Чем реже
можно позволить себе контрольные точки, тем лучше — это сокращает
накладные расходы.
Устраивающая частота записывается в параметр checkpoint_timeout
(значение по умолчанию — 5 минут — слишком мало, часто время
увеличивают до получаса).
Однако возможна ситуация, когда нагрузка станет выше расчетной
и за указанное время будет сгенерирован слишком большой объем
журнальных записей. Для этого в параметре max_wal_size указывают
общий допустимый объем журнальных записей.
Для восстановления после сбоя сервер должен хранить файлы
с момента начала последней завершенной контрольной точки
до начала текущей (объем между контрольными точками) плюс файлы,
накопившиеся во время работы текущей контрольной точки. Поэтому
общий объем можно оценить как
(1 + checkpoint_completion_target) * объем-между-контр-точками.
Таким образом большая часть контрольных точек происходит
по расписанию, раз в checkpoint_timeout единиц времени. Но при
повышенной нагрузке контрольная точка вызывается чаще, чтобы
постараться уложиться в объем max_wal_size.
13
Объем файлов журнала
Сервер хранит журнальные файлы
необходимые для восстановления (обычно < max_wal_size)
еще не прочитанные через слоты репликации
еще не записанные в архив, если настроена непрерывная архивация
не превышающие по объему wal_keep_size
не превышающие по объему min_wal_size (при переиспользовании)
Настройки
max_wal_size = 1GB
wal_keep_size = 0
wal_recycle = on
min_wal_size = 80MB
Надо понимать, что объем, указанный в параметре max_wal_size,
может быть превышен. Это не жесткое ограничение, а ориентир для
процесса checkpointer, влияющий на активность записи грязных
буферов.
Кроме того, сервер не имеет права стереть журнальные файлы, еще
не переданные через слоты репликации, и файлы, еще не записанные
в архив при непрерывном архивировании. Это может привести
к перерасходу места, так что если этот функционал используется,
необходим постоянный мониторинг.
Можно на случай отставания реплики параметром wal_keep_size
установить минимальный объем файлов журнала, остающихся после
контрольной точки. Это не гарантирует, что журнальная запись
сохранится до момента, когда она понадобится реплике, но все же
позволяет работать без слота репликации.
По умолчанию журнальные файлы могут не удаляться, а просто
переименовываться и использоваться заново. Параметр min_wal_size
задает минимальный неудаляемый объем. Это позволяет сэкономить
на постоянном создании и удалении файлов. Однако для файловых
систем с copy-on-write быстрее создать новый файл, поэтому для них
рекомендуется отключить переиспользование, установив
wal_recycle=off.
15
Фоновая запись
Процесс фоновой записи
Настройка
16
Процесс фоновой записи
31 1
следующая
жертва
3
может быть
вытеснен, надо
записать
1 0
следующий
на запись
Когда обслуживающий процесс собирается вытеснить страницу из
буфера, он может обнаружить, что буфер грязный, и ему придется
записывать эту страницу на диск. Чтобы снизить вероятность таких
ситуаций, в дополнение к процессу контрольной точки (checkpointer)
существует также процесс фоновой записи (background writer, bgwriter
или просто writer).
Процесс фоновой записи использует тот же самый алгоритм поиска
буферов для вытеснения, что и обслуживающие процессы, только
использует свой указатель. Он может опережать указатель на «жертву»,
но никогда не отстает от него.
Записываются буферы, которые одновременно:
содержат измененные данные (грязные),
не закреплены (pin count = 0),
имеют нулевое число обращений (usage count = 0).
Таким образом, фоновый процесс записи, «забегая вперед», находит
те буферы, которые с большой вероятностью вскоре потребуется
вытеснить. За счет этого обслуживающий процесс скорее всего
обнаружит, что выбранный им буфер не является грязным.
17
Процесс фоновой записи
Алгоритм
уснуть на bgwriter_delay
если в среднем за цикл запрашивается N буферов, то записать
N * bgwriter_lru_multiplier bgwriter_lru_maxpages
грязных буферов
Настройки
bgwriter_delay = 200ms
bgwriter_lru_maxpages = 100
bgwriter_lru_multiplier = 2.0
bgwriter_flush_after = 512kB
Процесс фоновой записи работает циклами максимум по
bgwriter_lru_maxpages страниц, засыпая между циклами на время
bgwriter_delay.
аким образом, если установить параметр bgwriter_lru_maxpages
в ноль, процесс фактически не будет работать.)
Точное число буферов для записи определяется по среднему
количеству буферов, которые запрашивались обслуживающими
процессами с прошлого цикла (используется скользящее среднее,
чтобы сгладить неравномерность между циклами, но при этом не
зависеть от давней истории). Вычисленное количество буферов
умножается на коэффициент bgwriter_lru_multiplier.
Если процесс совсем не обнаружил грязных буферов (то есть в системе
ничего не происходит), он «впадает в спячку», из которой его выводит
обращение серверного процесса за буфером. После этого процесс
просыпается и опять работает обычным образом.
При необходимости записи большого количества данных сервер даёт
указание ОС произвести промежуточный сброс данных в хранилище
(fsync) по достижении объема, задаваемого параметром
bgwriter_flush_after. Это уменьшает задержки фиксации транзакций
и выполнение синхронизации в конце контрольной точки.
Процесс фоновой записи имеет смысл настраивать после того, как
настроена контрольная точка. Совместно с контрольной точкой эти
процессы должны успевать записывать грязные буферы до того, как
они потребуются обслуживающим процессам.
18
Мониторинг
Контрольные точки
checkpoint_warning = 30s
log_checkpoints = on
статусы процессов startup, checkpointer
Запись грязных буферов процессами
представления pg_stat_bgwriter, pg_stat_io
Параметр checkpoint_warning позволяет выводить в журнал
предупреждение, если интервал между контрольными точками меньше,
чем значение параметра. Если это происходит регулярно, следует
подумать об увеличении max_wal_size или уменьшении интервала
между контрольными точками checkpoint_timeout.
Включенный по умолчанию параметр log_checkpoints выводит в журнал
подробную информацию о каждой выполненной контрольной точке.
Когда сервер находится в режиме восстановления, можно следить за
статусом процессов startup и checkpointer средствами операционной
системы, например с помощью утилиты ps.
Статистику работы процессов, записывающих грязные буферы
(контрольной точки, фоновой записи и обслуживающих процессов),
показывает представление pg_stat_bgwriter, а начиная с версии 16 —
представление pg_stat_io.
В 17-ой версии PostgreSQL появится новое представление
pg_stat_checkpointer, в которое из pg_stat_bgwriter будет перенесена
информация о статистике процесса контрольной точки.
20
Итоги
Процесс контрольной точки ограничивает размер хранимых
журнальных файлов и сокращает время восстановления
Контрольная точка и фоновая запись сбрасывают на диск
грязные буферы
Обслуживающие процессы могут сбрасывать грязные
буферы, но не должны этим заниматься
21
Практика
1. Настройте выполнение контрольной точки раз в 30 секунд.
Установите параметры min_wal_size и max_wal_size в 16 МБ.
2. Несколько минут c помощью утилиты pgbench подавайте
нагрузку 100 транзакций/сек.
3. Измерьте, какой объем журнальных файлов был
сгенерирован за это время.
4. Проверьте данные статистики и оцените, какой объем
приходится в среднем на одну контрольную точку.
Все ли контрольные точки выполнялись по расписанию?
Как можно объяснить полученный результат?
5. Сбросьте настройки к значениям по умолчанию.