20.1 Один журнал, три уровня детализации
wal_level определяет, насколько подробно PostgreSQL описывает
изменения в журнале. Уровней три, они вложены: каждый следующий пишет
всё, что предыдущий, плюс что-то ещё.
- minimal - пишет ровно столько, чтобы пережить сбой и восстановиться на этом же сервере. Ничего лишнего;
- replica (по умолчанию) - добавляет информацию, достаточную, чтобы другой сервер мог проиграть журнал и поддерживать копию базы, а также чтобы работало архивирование и восстановление на точку;
- logical - добавляет ещё данные, нужные, чтобы извлекать из журнала изменения в логическом виде («в таблице X обновилась строка с такими-то значениями»), а не как физические правки страниц.
Смена уровня требует перезапуска сервера - это не параметр, который можно подкрутить на лету.
20.2 minimal: быстро, но в одиночестве
На уровне minimal журнал содержит минимум для crash recovery.
Главная выгода - некоторые массовые операции могут почти не писать в
журнал. Классический пример: если в одной транзакции создать (или
опустошить через TRUNCATE) таблицу и тут же залить в неё данные
через COPY, PostgreSQL может пропустить журналирование самих
данных. Логика безопасна: если транзакция не закоммитится, таблицы
всё равно не будет, а если закоммитится - данные на диск он запишет
напрямую. Меньше журнала - быстрее массовая загрузка.
Цена высокая: minimal несовместим ни с физической репликацией, ни
с архивированием WAL, ни с восстановлением на точку. Журнал просто не
содержит данных, которые им нужны. Поэтому minimal уместен на
изолированных инсталляциях, где реплики и PITR заведомо не нужны -
например, на временной базе под разовую загрузку и аналитику.
20.3 replica: уровень по умолчанию
replica - то, на чём работает подавляющее большинство баз, и
значение по умолчанию. Журнал на этом уровне содержит достаточно,
чтобы:
- физическая репликация - реплика получает поток WAL и проигрывает его у себя, поддерживая побайтовую копию мастера (часть VIII);
- архивирование - сегменты WAL можно складывать в архив;
- восстановление на точку (PITR) - имея базовую копию и архив WAL, базу можно восстановить на любой момент в прошлом.
За это платят отказом от оптимизации minimal: массовые загрузки
журналируются полностью, потому что реплика и архив должны увидеть
все данные. Для обычной OLTP-нагрузки эта разница незаметна, а
возможность иметь реплику и бэкап с восстановлением на точку - почти
всегда обязательна.
20.4 logical: журнал, который понимает строки
Физическая репликация копирует журнал как есть - реплика становится точной побайтовой копией. Но иногда нужно другое: передать только изменения конкретных таблиц, в другую схему, в другую мажорную версию или вообще в стороннюю систему. Для этого журнал должен описывать изменения логически: не «в странице 42 байты такие-то», а «в таблице orders обновилась строка с id=7, новые значения такие».
Уровень logical добавляет в журнал именно эту информацию. Сколько
её писать для UPDATE и DELETE, зависит от REPLICA IDENTITY таблицы -
это настройка, которая говорит, как идентифицировать изменённую строку
(по первичному ключу по умолчанию, или по всей строке). На logical
работают публикации и подписки логической репликации (часть VIII).
Платят за logical дополнительным объёмом журнала. Поэтому его
включают, когда логическая репликация или декодирование действительно
нужны, а не по умолчанию.
20.5 Матрица возможностей
Сведём всё в таблицу - её удобно держать в голове:
| Возможность | minimal | replica | logical |
|---|---|---|---|
| Восстановление после сбоя | да | да | да |
| Архивирование и PITR | нет | да | да |
| Физическая репликация | нет | да | да |
| Логическая репликация | нет | нет | да |
| Объём журнала | наименьший | средний | наибольший |
Главное правило: уровень выбирают заранее, под будущие потребности.
Поднять с minimal до replica задним числом, чтобы «прямо сейчас»
сделать реплику из текущего состояния, не выйдет - нужных данных в
прошлом журнале нет. Меняют уровень с перезапуском, и только новый
журнал будет полным. Сводка по уровням и переходам - в wal-level.
20.6 Заглянуть в журнал: pg_walinspect
Журнал не обязан оставаться абстракцией. Расширение pg_walinspect
(доступно с PostgreSQL 15) показывает содержимое WAL прямо из SQL.
CREATE EXTENSION IF NOT EXISTS pg_walinspect;
-- статистика по записям в последнем отрезке журнала
SELECT "resource_manager/record_type" AS rmgr, count, record_size
FROM pg_get_wal_stats(pg_current_wal_lsn() - 100000,
pg_current_wal_lsn(), false)
ORDER BY count DESC;
В колонке ресурс-менеджера (в выводе её имя - resource_manager/record_type)
видно, какая подсистема породила записи:
Heap - изменения строк таблиц, Btree - изменения B-tree индексов,
Transaction - коммиты и аборты, XLOG - служебные записи (включая
full-page images). Так абстрактный «журнал» превращается в конкретный
перечень: вот INSERT в таблицу, вот изменение индекса, вот коммит.
Отдельные записи показывает pg_get_wal_records_info - с их LSN,
типом и размером. Это лучший способ почувствовать, во что
превращается обычный INSERT на уровне журнала.
20.7 pg_waldump: тот же взгляд из командной строки
У pg_walinspect есть старший родственник из командной строки -
утилита pg_waldump. Она читает сегменты журнала прямо с диска и
печатает записи в человекочитаемом виде, не требуя работающего
сервера.
pg_waldump 000000010000000000000001 | head
pg_waldump незаменим, когда сервер не запускается и нужно понять,
что было в журнале перед сбоем, или при отладке - какие именно записи
породила конкретная операция. pg_walinspect удобнее для живого
сервера и SQL-аналитики, pg_waldump - для офлайн-разбора сегментов.
Оба показывают один и тот же журнал с разных сторон.
20.8 Конец части: от одного сервера к нескольким
Этой главой замыкается тема журнала на одном сервере. Мы прошли путь от буферного кеша (изменения копятся в памяти) через write-ahead (журнал опережает данные) и контрольные точки (граница для восстановления) к режимам журнала (сколько в него писать).
Уровни replica и logical - это мост к следующей большой теме.
Поток WAL, который мы научились читать, можно отправить на другой
сервер: байт-в-байт (физическая репликация) или как логические
изменения строк (логическая). На этом строятся отказоустойчивость и
масштабирование чтения - но это уже часть про репликацию.
Уроки в sandbox
lab-20.1. Что пишет журнал: разбираем WAL через pg_walinspect
Заглянем внутрь журнала. Узнаем текущий wal_level, нагенерим
изменения, а потом через pg_walinspect разберём, какие записи они
породили - изменения строк, индексов, коммиты. Перед шагами предскажи,
записи какой подсистемы будут преобладать.
Узнай текущий уровень журнала:
SHOW wal_level;- предскажи, что увидишь (значение по умолчанию).Запомни стартовую позицию:
SELECT pg_current_wal_lsn();.Нагенерируй изменения: серия INSERT и UPDATE по таблице
flights.Посмотри статистику по записям:
pg_get_wal_stats(...)в отрезке от стартового LSN до текущего - найди строкуHeap.Разбери отдельные записи через
pg_get_wal_records_info(...)- найди записи типа INSERT/UPDATE.Найди в статистике записи
XLOGс full-page images послеCHECKPOINT;.
sandbox с автопроверкой - открыть в песочнице
Резюме
- `wal_level` задаёт, сколько информации писать в журнал; уровни вложены: minimal ⊂ replica ⊂ logical.
- minimal - минимум для crash recovery, позволяет некоторым массовым операциям почти не писать в журнал, но исключает репликацию, архивацию и PITR.
- replica (по умолчанию) - достаточно для физической репликации, архивирования и восстановления на точку; обычная OLTP-нагрузка платит за это незаметно.
- logical - добавляет логическое описание изменений строк (зависит от `REPLICA IDENTITY`), нужное для логической репликации и декодирования.
- Уровень выбирают заранее: поднять с minimal до replica задним числом, чтобы сделать реплику из текущего состояния, нельзя - в прошлом журнале нет данных; смена требует перезапуска.
- `pg_walinspect` (PG15+) показывает содержимое WAL из SQL (`pg_get_wal_stats`, `pg_get_wal_records_info`) по resource_manager: Heap, Btree, Transaction, XLOG.
- `pg_waldump` читает сегменты журнала из командной строки без работающего сервера - для офлайн-разбора и отладки.
Контрольные вопросы
Чем различаются три уровня wal_level и как они соотносятся?
Показать ответ
Уровни вложены.
minimalпишет минимум для восстановления после сбоя на этом же сервере.replicaдобавляет информацию для физической репликации, архивирования и восстановления на точку (PITR) - это значение по умолчанию.logicalдобавляет ещё логическое описание изменений строк, нужное для логической репликации и декодирования. Каждый следующий уровень пишет всё, что предыдущий, плюс своё; растёт и объём журнала.Почему на minimal быстрее массовая загрузка и чего за это лишаешься?
Показать ответ
На
minimalнекоторые операции могут пропустить журналирование данных- например,
COPYв таблицу, созданную или опустошённую в той же транзакции: если транзакция не закоммитится, таблицы не будет, а если закоммитится, данные запишутся на диск напрямую. Меньше журнала - быстрее загрузка. Цена:minimalнесовместим с физической репликацией, архивированием WAL и PITR, потому что журнал не содержит нужных им данных. Уместен только на изолированных базах без реплик и бэкапа на точку.
- например,
Почему нельзя поднять wal_level задним числом, чтобы сразу сделать реплику?
Показать ответ
Потому что более высокий уровень добавляет данные в журнал начиная с момента смены. Если база работала на
minimal, в её прошлом журнале просто нет информации, нужной для репликации или PITR, - задним числом она там не появится. Сменить уровень можно (с перезапуском сервера), но полным станет только журнал, записанный после смены. Поэтому уровень выбирают заранее, под будущие потребности.Что показывает resource_manager в выводе pg_walinspect?
Показать ответ
Подсистему, породившую WAL-запись.
Heap- изменения строк таблиц (вставки, обновления, удаления),Btree- изменения B-tree индексов,Transaction- коммиты и аборты транзакций,XLOG- служебные записи, включая full-page images. По распределению записей видно, во что превращается операция на уровне журнала: один INSERT в индексированную таблицу порождает и Heap-запись, и Btree-запись, а коммит - запись Transaction.Когда выбирать pg_walinspect, а когда pg_waldump?
Показать ответ
pg_walinspectработает из SQL на живом сервере - удобно для аналитики журнала запросами, фильтрации по resource_manager, интеграции с мониторингом.pg_waldump- утилита командной строки, которая читает сегменты журнала прямо с диска и не требует работающего сервера. Он незаменим, когда сервер не стартует и нужно понять содержимое журнала перед сбоем, или для офлайн-отладки. Оба показывают один журнал с разных сторон.