Буферный кэш и журнал в Postgresql
Буферный кэш
Буферный кэш используется для сглаживания скорости работы оперативной памяти и дисков
Буферный кэш состоит из массива буферов, которые содержат страницы данных и дополнительную информацию ( имя файла, положение страницы в этом файле и др. )
Размер страницы по умолчанию 8 Кбайт, изменить можно только при сборке
Любая работа со страницами данных проходит через буферный кэш. Сначала процесс обращается к кэшу. Если в буфере страницы нет, процесс обращается к операционной системе с просьбой прочитать страницу из собственного кэша или диска и добавить ее в буферный кэш
К странице в буферном кэше можно обращаться повторно без накладных расходов на вызовы ОС
Если процесс изменил данные на странице, соответствующий буфер становится грязным. Измененная страница подлежит записи на диск, по соображениям производительности запись происходит асинхронно и может откладываться
Буферный кеш, как и другие структуры общей памяти, защищен блокировками для управления одновременным доступом. Хотя блокировки и реализованы эффективно, доступ к буферному кешу далеко не так быстр, как простое обращение к оперативной памяти. Поэтому в общем случае чем меньше данных читает и изменяет запрос, тем быстрее он будет работать
Размер буферного кэша при первичной настройке следует устанавливать примерно 1/4 от общего размера оперативной памяти
Вытеснение редко используемых страниц
Естественно вся база в кэше не поместится. Его ограничивают доступная оперативная память и возрастающие при увеличении кэша накладные расходы.
Когда место в буферном кэше заканчивается применяется вытеснение страниц
Алгоритм вытеснения выбирает в буферном кэше страницу, которая использовалась реже других. Если страница окажется грязной, тогда страница записывается на диск
В кэше сохраняются только активные страницы, горячие данные
При достаточном объеме буферного кэша получается существенно сократить количество обращений к ОС
shared_buffers Значение по умолчанию слишком мало; в любой реальной системе его требуется увеличить сразу после установки сервера (изменение требует перезапуска)
После перезапуска сервера содержимое буферного кэша сбросится
postgres=# create database test_wal;
CREATE DATABASE
postgres=#
postgres=# \c test_wal
You are now connected to database "test_wal" as user "postgres".
test_wal=#
test_wal=# CREATE TABLE t(n integer);
CREATE TABLE
test_wal=#
test_wal=# INSERT INTO t SELECT id FROM generate_series(1, 10000) AS id;
INSERT 0 10000
test_wal=#
test_wal=# --Размер буферного кэша показывает параметр shared_buffers:
test_wal=#
test_wal=# SHOW shared_buffers;
shared_buffers
----------------
128MB
(1 row)
test_wal=#
test_wal=# --Команда EXPLAIN ANALYZE выполняет запрос, выводит план выполнения и дополнительную информацию:
test_wal=#
test_wal=# EXPLAIN (analyze, buffers, costs off, timing off)
test_wal-# SELECT * FROM t;
QUERY PLAN
-------------------------------------------
Seq Scan on t (actual rows=10000 loops=1)
Buffers: shared hit=45
Planning:
Buffers: shared hit=4 dirtied=1
Planning Time: 0.176 ms
Execution Time: 1.939 ms
(6 rows)
test_wal=# -- EXPLAIN ANALYZE последовательно читает таблицу
test_wal=# -- hit — количество буферов из буфера, в котором нашлись нужные для запроса страницы
test_wal=#
test_wal=# -- read — количество буферов, в которые пришлось прочитать страницы с диска
test_wal=#
test_wal=# EXPLAIN (analyze, buffers, costs off, timing off)
SELECT * FROM t;
QUERY PLAN
-------------------------------------------
Seq Scan on t (actual rows=10000 loops=1)
Buffers: shared hit=45
Planning Time: 0.071 ms
Execution Time: 2.027 ms
(4 rows)
test_wal=#
Журнал предзаписи wal
Журнал предзаписи защищает объекты, работа с которыми ведется в оперативной памяти ( таблицы, индексы, др. )
При сбое теряются данные из оперативной памяти, не записанные на диск
Журнал - поток информации о выполняемых действиях, позволяющий повторно выполнить потерянные при сбое операции
Журнал защищает страницы таблиц, индексов и других объектов
Журнал не защищает временные и нежурналируемые таблицы
Наличие буферного кэша увеличивается производительность, но уменьшает надежность
Запись в журнал должна попасть на диск ( постоянно устройство хранения ) раньше, чем будут записаны изменяемые операцией данные, поэтому журнал называется журнал предзаписи
Файлы журнала располагаются в каталоге PGDATA/pg_wal
Восстановление данных из журнала называется восстановлением с воспроизведением или REDO
Результатом использования WAL является значительное уменьшение количества запросов записи на диск, потому что для гарантии, что транзакция подтверждена, в записи на диск нуждается только файл WAL, а не каждый файл данных, изменённый в результате транзакции
Логически журнал можно представить в виде непрерывного потока записей. Каждая запись имеет номер, называемый LSN (Log Sequence Number). Это 64-разрядное число — смещение записи в байтах относительно начала журнала.
Текущую позицию показывает функция pg_current_wal_lsn:
postgres=# SELECT pg_current_wal_lsn();
pg_current_wal_lsn
--------------------
0/122B5FB8
(1 row)
testbase=# UPDATE t SET s = 'test';
UPDATE 1
testbase=# SELECT pg_current_wal_lsn();
pg_current_wal_lsn
--------------------
0/122B61A0
(1 row)
-- На файлы можно взглянуть не только средствами файловой системы, но и с помощью функции:
testbase=# SELECT * FROM pg_ls_waldir() ORDER BY name LIMIT 10;
name | size | modification
--------------------------+----------+------------------------
000000010000000000000012 | 16777216 | 2024-08-25 01:45:56+03
000000010000000000000013 | 16777216 | 2024-08-03 15:39:05+03
000000010000000000000014 | 16777216 | 2024-08-03 15:39:22+03
(3 rows)
Записи из журнала могут попасть в кэш операционной системы, postgres полагается, что есть вызов операционной системы, который гарантирует, что операционная система не будет держать данные журнала у себя в кэше и будут сразу записаны на диск
Каждый commit записывает журнальные данные на диск. Соответственно большое количество транзакций будет влиять на производительность
Поэтому существует асинхронная запись, когда доступ к таблице возвращается сразу после фиксации, а данные из журнала записываются на диск чуть погодя
Фоновый процесс walwriter через определенное время проверяет наличие журнальных записей и при необходимости синхронизирует их на диск
Переодический сброс всех грязных буферов на диск гарантирует попадание на диск всех изменений до контрольной точки
Восстановление при сбое начинается с последней контрольной точки
Когда сервер запускается после сбоя, он входит в режим восстановления
Чтобы восстановить согласованность, PostgreSQL читает WAL и после-довательно проигрывает каждую его запись, если соответствующее изменение не попало на диск. Таким образом восстанавливается работа всех транзакций. Транзакции, запись о фиксации которых не успела попасть в журнал, считаются оборванными.
Объем журнала за время работы сервера мог бы достигнуть гигантских размеров. Хранить его целиком и просматривать при сбое совершенно не реально. Поэтому СУБД периодически выполняет контрольную точку (КТ): принудительно сбрасывает на диск все грязные буферы (включая буферы clog, хранящие состояние транзакций)
Собственно «точка» — это момент начала записи буферов, которые были грязными на этот момент. Но точка считается выполненной только после того, как все такие буферы записаны. Это гарантирует, что все изменения, сделанные до момента КТ, находятся на диске
Журнальные записи долгой транзакции будут записываться асинхронно (чтобы освободить буферы WAL). А если при сбросе страницы данных окажется, что соответствующая журнальная запись еще не на диске, она тут же будет записана в синхронном режиме.
Процесс walwriter - занимается асинхронной записью журнала на диск.
При синхронном режиме записью журнала занимается тот процесс, который выполняет фиксацию транзакции
Процесс контрольной точки checkpointer периодечески сбрасывает все грязные буферы на диск
Процесс фоновой записи background writer (или bgwriter) похож на процесс контрольной точки, записывает только часть грязных буферов, которые с большой вероятностью будут вытеснены в ближайшее время
Обслуживающие процессы, читающие данныев буферный кеш. Если, несмотря на работу процессов контрольной точки и фоновой записи, вытесняемый буфер окажется грязным, обслуживающий процесс самостоятельно запишет его на диск
Буферный кэш ускоряет работу, уменьшая число дисковых операций. Надежность обеспечивается журналированием. Размер журнала ограничен благодаря контрольным точкам.
Журнал используется для восстановления после сбоя, резервного копирования, репликации между серверами
Уровни журнала
Объем данных, который попадает в журнал, регулируется параметром wal_level
Minimal - гарантия восстановления после сбоя
Replica - резервное копирование, репликация, передача и проигрование данных на другом сервере. На данном уровне в журнал добавляется информация, позволяющая использовать его для создания резервных копий и репликации. При репликации журнальные записи передаются на другой сервер и применяются там, таким образом создается точная копия ( реплика ) основго сервера
Logical - логическая репликация, информация об изменении, удалении, добавлении табличных строк. На данном уровне в журнал добавляется информация, позволяющая декодировать журнальные(физические) записи и сформировать из них логические записи о добавлении, изменении, удалении табличных строк
Немного практики
Процесс postmaster можно узнать из файла /var/lib/postgresql/14/main/postmaster.pid
-- Найдем все процессы, поражденные процессом postmaster
~$ sudo ps -o pid,command --ppid 1065
PID COMMAND
1078 postgres: 14/main: checkpointer
1079 postgres: 14/main: background writer
1080 postgres: 14/main: walwriter
1082 postgres: 14/main: autovacuum launcher
1083 postgres: 14/main: stats collector
1084 postgres: 14/main: logical replication launcher
-- Остановка в режиме immediate
sudo pg_ctlcluster 16 main stop -m immediate --skip-systemctl-redirect
--Перед тем, как начать принимать соединения, СУБД выполнила восстановление (automatic recovery in progress)
Источники
Связанные темы
Системный каталог в Postgresql
Табличные пространства в Postgresql
Определение данных в Postgresql
Основные команды psql и sql Postgresql
Агрегирование и группировка в Postgresql
Основные понятия реляционной модели
Базовые понятие о настройках и безопасности в сети
Создание и управление кластером postgresql
Системные каталоги в Postgresql
Этапы запроса и получения результата в postgresql
Оптимизация производительности Postgresql