- BrainTools - https://www.braintools.ru -

Про избыточность WAL в Postgres

Про избыточность WAL в Postgres - 1

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

Я — Андрей Бородин, работаю над Postgres и Apache Cloudberry для Yandex Cloud и вообще. Поддерживаю WAL-G, SPQR, Odyssey и всякое такое. В этой статье на основе доклада для конференции Saint HighLoad++ [1] я расскажу о причинах избыточности, о действиях сообщества, а также о своей работе в рамках подсистемы WAL. Понимание работы WAL поможет вам проектировать ваши сервисы с учетом специфики этой подсистемы.

Вместо предисловия

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

Пойдём от истории самого сердца базы данных через то, как она работает сейчас, — в то, что там можно дописать.

Write Ahead Logging 

Начнём с журнала предзаписи, он же — Write Ahead Log (WAL). Иногда его называют журналом опережающей записи. Это часть системы, которая была создана примерно 25 лет назад замечательным коммит-месседжем.

Про избыточность WAL в Postgres - 2

За три буквы в коммит-месседже, наверное, сейчас бы человека лишили коммит-бита. Из 2025 года коммит Мишеля Пакье в WAL что-то чуть-чуть трогает в мониторинге. 

Про избыточность WAL в Postgres - 3

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

Про избыточность WAL в Postgres - 4

Три буквы — все же знают, о чём идет речь. На самом деле, конечно, не все знают.

Вернёмся ещё на 25 лет назад. Человечество хранит информацию на механических дисках по одной простой причине. Если вы, допустим, делаете банковскую систему и хотите записать информацию о том, сколько денег на счету, то оперативная память [2] для этой информации будет стоить столько же, сколько денег на счету лежит. Это очень дорого. А диски — это буквально вершина механического творения человечества, устройства, которые прошли много десятков лет оптимизации. Они хорошо, дёшево и надёжно хранят данные. WAL задумывался как технология, которая помогает быстро писать на диски. 

Откуда писать?

Про избыточность WAL в Postgres - 5

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

Мы называем современные блочные устройства дисками, но это просто традиция. Они все квадратные, но по-прежнему читают страничками по 4 или 8 килобайт, иногда другими страничками.

ARIES  (Algorithms for Recovery and Isolation Exploiting Semantics)

Когда диски ещё были круглыми, система, которая способна переживать сбой питания, должна была реализовывать алгоритм ARIES, предложенный Моханом в 1992 году.

Про избыточность WAL в Postgres - 6

Алгоритм состоит из трёх частей:

  1. Write-ahead logging. Как мы записываем, что собираемся изменять в виде последовательного лога. Мы делаем лог последовательным, чтобы данные о нескольких изменениях записать рядом на магнитный диск. 

  2. Repeating history during Redo. Алгоритм предполагает, что мы этот лог умеем читать, что у нас есть Redo функций, которые могут прочитать журнал и воспроизвести те изменения, которые в наши журналируемые объекты не попали.

  3. Logging changes during Undo. Есть Undo, что предполагает, что мы записали, как мы проходили crash recovery. 

Вы видели коммит-месседж Мишеля Пакье. Конечно, ничего из этого в практику Postgres не попало. Практика Postgres состоит из двух кусочков ARIES:

  • Logging changes;

  • Applying changes during replay.

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

Про избыточность WAL в Postgres - 7

Есть некая история изменения базы данных, в которую мы записываем, что происходит в определённое время. Эта история должна храниться на энергонезависимом хранилище. Иногда мы делаем checkpoint, сбрасываем состояние БД в такое же энергонезависимое хранилище, чтобы не восстанавливать базу в случае краша из далекого прошлого. 

Подозреваю, что админам понятен мем: когда ты вместо WAL говоришь xlog, вероятно, ты очень давно занимаешься базами данных.

Про избыточность WAL в Postgres - 8

Когда WAL в Postgres назывался xlog и не хватало места под базой, админы дропали лишние логи. Это было зря — база после этого не работала. Сейчас объясню, почему.

В основном БД изменяет данные в оперативной памяти. Часто упоминают in-memory базы данных и говорят, что из оперативной памяти что-то быстрее достать. В Postgres данные располагаются тоже в оперативной памяти — в основном в зоне Shared buffers. 

Про избыточность WAL в Postgres - 9

Когда мы меняем страничку, мы не меняем её на диске, а просто отмечаем изменения в Shared buffers. На пути транзакции никогда не стоит запись Shared buffers на диск, есть маленькие оговорки. Но странички всё-таки когда-нибудь должны быть записаны. 

У страниц на пути в файловую систему есть три пути: 

  1. Background Writer смотрит: что-то у нас много dirty-страничек, надо иногда их записать на диск. 

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

  3. Самый худший случай, когда бэкэнд, которому не хватает shared buffers и оперативной памяти, хочет страничку освободить себе. Он вынужден чью-то чужую записать на диск, а свою разместить в освободившемся месте.

Из этого следует важный инвариант WAL, который был принят в Postgres:

WAL должен попадать на диск всегда раньше, чем информация, которую он меняет.

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

Когда мы потрогали страничку в Shared Buffers впервые после checkpoint, она может быть в случае внезапного краша записана на файловую систему лишь частично. 

Про избыточность WAL в Postgres - 10

Например, один сектор 512 байт у нас будет от новой версии, которую мы пишем на диск, а оставшиеся 7,5 килобайт могут быть старые. Контрольная сумма не сойдётся, база данных сломается, остановится и скажет — восстанавливайся из бэкапа.

Для избежания этой ситуации у нас есть  full_page_writes. Строчка, которая меняется впервые с checkpoint, целиком попадает в WAL. Есть нюанс — WAL в основном состоит из full_page_writes, если у вас система настроена неправильно. Если checkpoints случаются слишком часто, то WAL в основном состоит из только что потроганных страниц, у которых есть базовый образ. А также  WAL record, который говорит о том, что поменялось в этой страничке. 

Если вы checkpoints делаете очень редко, в случае пропадания питания, перезагрузки, out of memory и любого другого внезапного краша система будет долго перезагружаться, так как будет повторять [3] все изменения, произошедшие с предыдущего checkpoint. Такой трейд-офф в настройке базы данных.

Из всего этого следует неочевидная вещь про WAL:

Данные пишутся не в таблицы и индексы, а в WAL. Таблицы и индексы — лишь кеш для WAL.

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

Про избыточность WAL в Postgres - 11

Я нарисовал длинную пачку байт, которая с одного конца продолжается. 

В WAL есть координаты. Это LSN (Logical Sequence Number) — просто количество байт, записанные в WAL с момента начала существования базы (int64). Когда LSN закончится, в базу больше писать нельзя. Но я никогда в жизни не видел, чтобы 64-битные LSN закончились. Кстати, такие физические ограничения встречаются в разных системах, которые на самом деле являются базами данных, в том числе, в файловых системах.

Внутри WAL состоит из маленьких записей (record) с типовым размером порядка сотни байт — зависит от нагрузки. 

Про избыточность WAL в Postgres - 12

Каждая запись состоит из заголовка (header) и payload. 

Про избыточность WAL в Postgres - 13

Заголовок в основном связывает запись с предыдущей. Кроме того, там есть контрольная сумма. 

Про избыточность WAL в Postgres - 14

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

WAL record может содержать информацию о том, что конкретно надо поменять. Обычно она зависит от так называемого ресурс-менеджера: набора функций по воспроизведению WAL-записей. Примеры ресурс-менеджеров: b-tree индекс, heap, c-log или двухфазные транзакции. Любая подсистема, которая хочет хранить что-то на файловой системе внутри базы данных и хочет, чтобы оно воспроизводилось после сбоя или было на реплике, имеет свой ресурс-менеджер. 

WAL — это последовательность байт. Чтобы было понятно, как его расположить на файловой системе, он сгруппирован в сегменты по 16 Mb. 

Про избыточность WAL в Postgres - 15

Эта настройка меняется при создании базы данных — не при компиляции, а именно при создании набора файлов, которые мы считаем БД. По умолчанию это 16 Mb, но многие, например, RDS, сейчас увеличивают эту константу до 64 Mb.

Эти сегменты копируются в геораспределённое хранилище, чтобы иметь возможность восстанавливать базу данных на точку во времени. Кусочками по 16 Mb мы нарезаем всю историю, которая происходит в базе данных, и при желании можем её проиграть не в том месте, где жила база данных, а где-нибудь ещё. 

Про избыточность WAL в Postgres - 16

Когда мы пришли в место «где-то ещё», чтобы отличать WAL, которые родились в старом месте и в новом месте, у нас есть концепция таймлайнов. Новый таймлайн выбирается каждый раз, когда вы восстанавливаете кластеры с бэкапом, либо когда вы промоутите узел высокодоступного кластера.

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

Про избыточность WAL в Postgres - 17

Внутри сегменты побиты на странички, у которых есть заголовок.

Про избыточность WAL в Postgres - 18

Это полезная информация, избежать которой нельзя. Например, XLOG_PAGE_MAGIC. Magic — это константа. Она говорит о том, что WAL был записан конкретной версией бинарников — Postgres 14.N, например, или 15.N. Изменение WAL Page Magic делает историю несовместимой с бинарником, с исполняемым файлом базы данных. 

Наличие заголовка внутри каждой странички создаёт много проблем. Размещаемые записи могут быть до гигабайта размером, потому что атрибут, который мы обновляем внутри странички, может быть таким. Очевидно, что гигабайтный record пойдёт на множество страничек 8 Kb и он должен аккуратно обрулить все заголовки — мы дописываем payload после заголовка. Заголовки страничек при этом могут быть разной длины.

Когда мы пишем WAL в бэкэнде в соединении с базой данных, мы его не пишем сразу на диск. У нас есть буферы. WAL buffers — это место, где размещается временно WAL, который нужно записать. Он защищается одним локом WAL Insert lock, который нужно захватить на момент резервации адресов.

Про избыточность WAL в Postgres - 19

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

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

Про избыточность WAL в Postgres - 20

Это адрес того места в WAL, откуда записи, применённые последовательно, переводят базу данных из корректного в корректное состояние. 

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

То есть после краша нужно выполнить crash recovery, после бэкапа — backup crash recovery, и перейти в консистентное состояние. Затем в базе можно читать индексы, даже если вы находитесь не в той точке, до которой собираетесь восстанавливаться.

Так появилась идея о жизни процесса БД внутри отказоустойчивого кластера. На Windows это будет Postgres.exe, на Mac или Linux — просто бинарник Postgres. Вы его запускаете, передаете ему папку с данными.

Цикл жизни базы:

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

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

  • Hot Standby Recovery. Либо процесс может перейти в режим Hot Standby, когда начнёт выполнять читающие запросы. 

  • Promotion. В какой-то момент вы можете сказать процессу promote — он перестаёт читать чужой WAL и начинает писать свой.

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

В итоге топология выглядит следующим образом:

Про избыточность WAL в Postgres - 21

Основной узел в кластере в виде WAL отправляет изменения на реплики, или горячий резерв, или Standby (это всё синонимы). В транзакции при выполнении коммита мы дожидаемся, когда commit record будет записан на нашу файловую систему с выполнением f-sync, либо доедет до реплики, либо будет применён репликой в зависимости от конфигурации синхронного коммита. Кроме того, мы отправляем WAL в S3 или рандомное объектное хранилище и, например, с реплики можем снимать бэкапы. Такое направление трафика. 

В случае Postgres это почти всегда система I/O bound. Она всегда ограничена производительностью блочного устройства. Если мы зайдём и посмотрим, чем занимается центральный процессор на мастере, увидим такой топ: 

Про избыточность WAL в Postgres - 22

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

Про избыточность WAL в Postgres - 23

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

Поиск решений для проблемы избыточности 

Первым решением было такое: если мы видим сжатие кодека pglz, мы переписываем кодек pglz и его декомпрессию. 

Про избыточность WAL в Postgres - 24

Сделали так, чтобы декомпрессия работала на 40% быстрее. Этот патч был закоммичен в 2019 году. Идея об улучшении чего-то понравилась, и мы продолжили работу над ней.

Про избыточность WAL в Postgres - 25

Следующая идея — Pglz можно оптимизировать бесконечно. Есть люди, которые всю жизнь занимаются кодеками. Ян Колле давно изобрёл LZ4, и он работает намного быстрее, чем pglz.

Про избыточность WAL в Postgres - 26

Pglz предложил человек от баз данных, его писал Ян Вик. Вероятнее всего, у него это было как хобби на вечер, а у Яна Колле вся жизнь про сжатие — это его фишка. 

Переход на LZ4 случился в PostgreSQL 15. Это позволило на каких-то бенчмарках в 1,5 раза увеличить производительность на ровном месте. Позже занесли ZSTD, но он не дал ничего. На 8 Kb сжатие что с LZ4, что с ZSTD работает почти одинаково. ZSTD должен разогнаться на большем объёме данных.

Тогда я зашёл на кластер и посмотрел, сколько занимает WAL-файл. Мы записали на файловую систему 16 Mb, после чего система архивации его ещё раз сжала кодеком Brotli и отправила в S3. Сжатый файл занимает 5 Mb, но сжатие не работает дважды. В теории это возможно, а на практике это означает, что в файле осталось слишком много неслучайных данных. 

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

Есть статья Яна Колле, которая описывает, что в среднем сжатие хорошо работает, если даанные больше 860 байт — такая вот константа, вычисленная на некотором корпусе. 

В основном сжатие основано на самоподобии данных — следующие байтики похожи на предыдущие, и короткие фрагменты сжимать сложно.

Источник: https://engineering.fb.com/2018/12/19/core-infra/zstandard/

Вот так мы пишем B-дерево:

Про избыточность WAL в Postgres - 28

Кстати, запись B-дерева — это тот случай, когда нарушается инвариант (речь идёт о том, что мы сначала пишем WAL, а потом пишем файлик). Здесь сначала сортируем данные, а потом в порядке, в котором загораются странички, записываем их на диск. И только после этого WAL-логируем. Если случается краш во время создания B-дерева, у нас навсегда остаются файлы, лежащие на файловой системе.

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

Кажется, что мы строим индексы редко — один раз построили и дальше их только изменяем. Это не так. Тут у меня снова шутка для бородатых админов про Репакослава:

Про избыточность WAL в Postgres - 29

В Postgres есть утилита pg_repack, которая перестраивает индексы. Она решает почти любую проблему, которую нельзя решить добавлением железа, то есть много bloat — перестраивайте индекс. 

В любой непонятной ситуации делай repack. Админы настолько любят pg_repack, что некоторые и правда могли бы называть сына Репакославом.

Это всё мы обсуждали на Hacking Session и пришли к выводу, что нам надо бы писать B-дерево по несколько страниц за раз.

Про избыточность WAL в Postgres - 30

Мы попробовали — за час не получилось. К счастью, в январе 2024 года Хейки Линакангас сделал ровно то же самое.

Про избыточность WAL в Postgres - 31

Возможно, за большее количество времени он перевёл B-дерево на последовательную запись по несколько страниц. Он сделал так, что при логировании созданного B-дерева мы пишем 16 страниц подряд. 

Посмотрим, как пишется WAL. Там довольно сложная машинерия.

Как бэкенд пишет WAL record

  • Код AM вызывает XLogRegisterData() и XLogInsert(RmgrId rmid, uint8 info)

  • Машинерия XLog

  • Набирает нужные FPI

  • Считает CRC

  • Резервирует место под глобальным локом

  • Пишет запись в WAL buffers

Мы в каком-то процессе поменяли общую структуру данных. Затем, не отпуская лог на страничку (чтобы она вдруг не оказалась на файловой системе), вызываем функцию, которая говорит XLogInsert. Ей говорим: «Запиши, пожалуйста, информацию об изменениях». 

При этом мы должны сделать много неочевидных вещей — например, чек-суммирование и сжатие FPI страниц. Только после этого мы передаём страничку в WAL buffers и берём глобальный лог. Тут мы можем обнаружить, что record больше не актуален, потому что случился checkpoint и надо заново пересжать страницу.

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

Про избыточность WAL в Postgres - 32

Патч оказался не очень инвазивным — там всего 400 строк кода, причём там минус 400 строк кода, плюс 400 строк кода.

Про избыточность WAL в Postgres - 33

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

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

Про избыточность WAL в Postgres - 34

Рассмотрим предметнее вопрос. Мы сжимаем какие-то данные, а они оказались слишком случайные. В результате у нас получилось данных больше, чем мы сжимали. Такая ситуация возникает на большинстве входов, потому что мы частотные вещи делаем короче, а того, что в природе встречается не так часто (в основном все остальные данные, около случайные) становятся чуть-чуть больше. Из-за этого машинерия, которая подсчитывает, сколько байтиков нам нужно для сжатия WAL record целиком, стала непрогнозируемой и сложной. Из-за этого патч всё ещё в ревью. 

Немного байтов в типовой нагрузке удалось сохранить за счёт того, что теперь не нужны заголовки каждого отдельного блока. У нас есть просто один заголовок целиком на WAL record.

Про избыточность WAL в Postgres - 35

Усложнилось при этом конфигурирование системы:

Про избыточность WAL в Postgres - 36

Админы любят много ручек, которые можно покрутить, но это не самая очевидная ручка типа «record какого размера нам надо сжимать». Из теории мы знаем, что больше чем 860 байт стоит сжимать. Но на каких-то нагрузках хорошо сжиматься будет и 100 байт, а на каких-то 16 байт сожмутся меньше. Это надо изучить. 

Но я провёл другое исследование. Взял стандартный индекс по случайным числам и замерил, что сжатие record целиком позволяет приблизительно на 25% меньше WAL писать в существующей системе.

Про избыточность WAL в Postgres - 37

Этот патч сейчас обсуждается. Если всё хорошо, может быть, он попадёт в PostgreSQL 19 и выйдет в сентябре 2026 года. 

Хотелось бы пойти дальше и иметь возможность сжимать один record на основании данных о предыдущем. 

Про избыточность WAL в Postgres - 38

К сожалению, то место, где мы сжимаем record, максимально параллельно.

Про избыточность WAL в Postgres - 39

Если у нас есть 100 пишущих соединений к Postgres, каждое из них сначала формирует запись, которую хочет записать, сжимает её, чек-суммирует, всю машинерию проводит, и только потом отправляет в IO-систему. В такой парадигме очень сложно создать зависимости record между друг другом.

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

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

Мне предлагают идею: зачем тебе пул, пусть у каждого бэкенда будет свой контекст!. Но при восстановлении это потребует max connections умножить на размер буфера байтиков только под разжатие. Это слишком много. На такой подход я пока не готов, поэтому придерживаюсь идеей с пулом контекстов, в которых происходит сжатие и разжатие. 

Но даже эта идея, к сожалению, встречает проблемы:

  • Всё, что смотрит внутрь записи теперь может запускаться только с CHECKPOINT

  • Логическая репликация

  • pg_waldump

После этого мы не можем начать читать WAL со случайной позиции. Сейчас если вы делаете логическое декодирование можно почти в любой LSN прийти, взять ближайший record и оттуда декодировать то, что было в WAL, преобразовывать из бинарных записей в условный JSON или другую логику [5]. Если у нас сжатые контексты — приходим в случайное место, достаем record, и откручиваемся назад до checkpoint, чтобы найти то место, откуда надо разжимать.

С тем, что у нас пропадает случайный доступ в WAL и мы всегда вынуждены начинать читать его с checkpoint, видимо, придётся жить. Но я не уверен, что эта технология будет принята в Postgres.

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

Скрытый текст

А чтобы узнать больше интересного о высоконагруженных системах и последних трендах отрасли, приходите на конференцию развития Saint HighLoad++ 2026! [6] Конференция становится больше практикумом, чем лекциями. Вас ждёт больше интерактивных форматов и нетворкинга.

Автор: x4mmm

Источник [7]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/27186

URLs in this post:

[1] Saint HighLoad++: https://highload.ru/spb/2025/abstracts/14529?utm_source=habr&utm_medium=article&utm_campaign=shl&utm_content=995820

[2] память: http://www.braintools.ru/article/4140

[3] повторять: http://www.braintools.ru/article/4012

[4] https://engineering.fb.com/2018/12/19/core-infra/zstandard/: https://engineering.fb.com/2018/12/19/core-infra/zstandard/

[5] логику: http://www.braintools.ru/article/7640

[6] Saint HighLoad++ 2026!: https://highload.ru/spb/2026?utm_source=habr&utm_medium=article&utm_campaign=shl&utm_content=995820

[7] Источник: https://habr.com/ru/companies/oleg-bunin/articles/995820/?utm_source=habrahabr&utm_medium=rss&utm_campaign=995820

www.BrainTools.ru

Rambler's Top100