Heap умер? Или как IOT вместо heap ускорил PostgreSQL в 2Х

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Привет, Хабр! На связи Михаил Семёнов, владелец продукта СУБД Platform V Pangolin DB.

Высокая нагрузка OLTP? VACUUM необходим, но нагружает базу? Непрерывный bloat и отстающая реплика? Мы привыкли списывать это на характер нагрузки, но давайте критически посмотрим на классический heap и поддержание целостности и многозначности данных.

В статье разберу альтернативу — индекс‑организованное хранение (IOT). Покажу, как IOT решает эти проблемы, ускоряет работу с данными, не меняя интерфейса (прозрачно для клиента).

В Pangolin мы добавили новый вариант хранения (индекс-организованный), который, помимо оптимизации хранения, более чем вдвое ускорил работу с данными без изменения интерфейса PostgreSQL.

Статья будет полезна DBA, тимлидам, СТО и архитекторам Enterprise-компаний и поможет решить проблемы масштабируемости PostgreSQL без смены стека технологий и эффективно использовать бюджет на инфраструктуру.

Что не так с классическим heap?

Классический механизм хранения (heap) создавали десятилетия назад. Сегодня приложения работают на многопроцессорном оборудовании под высокой конкурентной нагрузкой, и начинают проявляться пределы масштабируемости. При интенсивных операциях записи таблицы часто бесконтрольно растут из-за накопления мёртвых версий строк, индексы могут занимать больше места, чем сами данные, а фоновый процесс очистки потребляет IOPS и время администраторов. Отсюда — непредсказуемые задержки при выполнении запросов.

Мы искали способ устранить эти узкие места архитектурно, не отказываясь от привычного SQL-стека.

Решение проблем с heap: переход на таблицы с индекс-организованным хранением

Мы рассмотрели архитектурные ограничения классического heap на современном железе и остановились на подходе с использованием нового метода доступа к таблицам. Он основан на поддержке индекс-ориентированного хранения: данные хранятся в виде B+-дерева, которое объединяет в себе таблицу, физический слой хранения и первичный индекс. Это избавляет от необходимости в отдельной структуре heap при поиске по первичному ключу. Внутренние узлы дерева — корневые и промежуточные страницы — содержат только ключи и указатели на дочерние ветви для маршрутизации поиска. Полные версии строк физически располагаются исключительно в «листовых» страницах, упорядоченных по значению первичного ключа.

На схеме показан пример поиска строки по первичному ключу (SELECT * FROM table1 WHERE id = 42;). Видно различие в организации хранения данных между heap и индекс-организованной таблицей.

UNDO-лог

На страницах B+-дерева в индекс-организованной таблице находятся только актуальные версии строк. При обновлении или удалении записи новая версия пишется на место старой, а данные для отката (предыдущее состояние строки) уходят в журнал отмены — UNDO.

Прямые ссылки вместо buffer mapping

В индекс-организованной таблице страницы данных в оперативной памяти связываются с узлами индексной структуры через прямые указатели. Поэтому не нужно искать страницы в глобальной таблице соответствий буферов (buffer mapping) и использовать связанные с ней механизмы синхронизации. Если страницы нет в памяти, то она считывается с диска в буферный пул. После этого узел дерева обновляется, сохраняя прямую ссылку. Далее обращения используют уже установленный указатель без повторного поиска.

Copy-on-Write для контрольных точек

При создании контрольных точек индекс-организованная таблица использует механизм Copy-on-Write. При изменении данных страницы B+-дерева записываются в новое свободное пространство хранилища, а не поверх существующих на диске.

Одновременно создаются новые версии всех родительских узлов по пути от изменённой страницы до корня дерева, а предыдущая версия дерева остаётся на диске неизменной. После записи атомарно обновляется единственная корневая ссылка таблицы — она начинает указывать на новую версию дерева.

Логический строчный WAL

Индекс-организованные таблицы меняют работу WAL: журналирование происходит на уровне строк, а не блоков данных. В журнал предзаписи попадают логические изменения строк, включая значения первичного ключа и TOAST-данные при необходимости.

Пользовательские данные лежат непосредственно в листьях первичного B-дерева, поэтому вторичные индексы можно восстановить по изменениям первичного ключа. И изменения вторичных индексов не журналируются отдельно, а это сокращает объём записываемых данных.

Сжатие данных на уровне блоков

В индекс-организованной таблице можно использовать встроенную библиотеку ZSTD для сжатия на уровне блоков. Перед сбросом на диск содержимое страницы целиком упаковывается, и в файл записывается уже результирующий поток байтов.

В отличие от heap, где страница занимает фиксированные 8 КБ, даже если заполнена наполовину, индекс-организованная таблица записывает на диск уже сжатый блок. Его размер определяется только результатом работы алгоритма сжатия.

Размещение в файловой системе

При создании индекс-организованной таблицы СУБД регистрирует отношение в системных каталогах и назначает ему идентификатор relfilenode. На его основе в каталоге базы данных создаётся пустой файловый объект. Это лишь служебный файл, он обеспечивает совместимость с внутренними механизмами ядра СУБД, остаётся пустым и не используется для хранения пользовательских данных. Фактически данные хранятся в собственном файловом пространстве индекс-организованной таблицы с использованием собственного формата.

Функциональность доступна только в редакциях Platform V Pangolin DB Enterprise.

Преимущества нового подхода

Физическое упорядочивание данных. Строки хранятся в листьях B+-дерева по первичному ключу. Данные можно читать напрямую, без обращения к отдельному heap-хранилищу.

Отсутствие bloat. Неактуальные версии строк живут в журнале UNDO. Таблицы не раздуваются и снижается потребность в VACUUM и VACUUM FULL для основных данных.

Эффективность на многопроцессорных системах. Прямые ссылки на страницы памяти вместо глобальной таблицы buffer mapping уменьшают накладные расходы на синхронизацию.

Мгновенные снимки и бэкапы. Механизм Copy-on-Write позволяет быстро создавать физически согласованные снимки данных — они сразу готовы для резервного копирования или репликации.

Легкий WAL и быстрое восстановление. Строчное журналирование сокращает объём записи на диск и ускоряет параллельное восстановление после сбоя, а также применение изменений на репликах без ущерба для устойчивости.

Экономия дискового пространства. Сжатие страниц и запись блоков переменной длины уменьшают размер файлов БД и снижают нагрузку на подсистему ввода-вывода.

Результаты тестирования

Мы прогнали тесты на pgbench и go-tpc в условиях дефицита ресурсов (ограниченная память, высокие задержки дисков) на матрицах конфигураций от 4 до 8 ядер. Так выглядела картина нагрузки:

  • Дефицит IOPS. Когда системе тесно (низкая пропускная способность дисковой подсистемы), отсутствие bloat и эффективный WAL дают прирост TPS до +90% (кластерный pgbench с синхронной репликацией).

  • Сбалансированные production-системы. На кластерном pgbench с синхронной репликацией без ограничений железа мы видим стабильные плюс 15-20% к TPS. Для тестов TPC-C (go-tpc) этот показатель составляет +5-10% tpmC, в зависимости от конкурентности соединений.

  • Занимаемое место на диске (без сжатия). До х2 экономии достигается только в специфических сценариях с массовыми UPDATE-запросами за счёт отсутствия дублирования heap и PK. При массированной вставке размер данных примерно одинаков.

  • Занимаемое место на диске (со сжатием ZSTD). Экономия достигает восьми раз на первом уровне сжатия.

Важное уточнение: числа сильно зависят от сценария использования. Архитектура undo-журналов даёт улучшение именно на write-intensive нагрузках, как показывают результаты go-tpc с ограничением IOPS — до +250%. Но для тяжёлых аналитических запросов (OLAP) или массового чтения больших таблиц старый добрый heap может оказаться эффективнее из-за особенностей работы страничного кеша ОС.

Миграция без остановки бизнеса: возможность совместного использования heap и индекс-организованных таблиц

Одна из ключевых особенностей решения, упрощающих начало работы, — возможность плавного перехода. Благодаря интерфейсу методов доступа (Table Access Method API) в одной базе данных могут одновременно сосуществовать таблицы на классическом heap и новые индекс-организованные таблицы.

Для миграции не нужна доработка приложения. Вы можете переносить таблицы одну за другой простым пересозданием: CREATE TABLE … USING orioledb AS SELECT * FROM old_table;.

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

Настройка самого движка тоже занимает пару минут: установка пакета, добавление orioledb в shared_preload_libraries и выполнение CREATE EXTENSION.

Если вы хотите целиком перевести базу на новую архитектуру, то достаточно выставить параметр default_table_access_method = 'orioledb'.

Важное ограничение: глобальная установка метода доступа по умолчанию не рекомендуется для систем со сторонними расширениями. Многие расширения создают свои служебные таблицы, явно рассчитывая на классическую heap-архитектуру и наличие скрытых системных столбцов (ctid, xmin). Использование индекс-организованных таблиц для таких объектов может привести к ошибкам при создании таблиц или снижению производительности из-за эмуляции отсутствующих механизмов. Для миграции существующих данных используйте точечный перенос через CREATE TABLE ... USING orioledb.

Итоги

Индекс-организованные таблицы позволили нам решить ряд архитектурных проблем open source PostgreSQL. При этом экосистема, гибкость SQL и весь накопленный стек расширений остались на месте.

Главное, что мы получили:

  • Предсказуемая производительность. Мы устранили проблему распухания таблиц (bloat) и зависимость от фоновых процессов очистки. База данных сохраняет время отклика даже при интенсивных операциях записи.

  • Эффективное использование бюджета на инфраструктуру. Более эффективное использование бюджета на инфраструктуру хранения за счёт устранения распухания файлов таблиц данных и поддержки эффективного сжатия данных ZSTD.

  • Сохранение инвестиций в стек. Технология полностью совместима с SQL-диалектом Postgres и экосистемой расширений. Это позволяет масштабировать существующие системы без дорогостоящего рефакторинга приложений.

Спасибо!

Источник: https://habr.com/ru/companies/sberbank/articles/1094296/


Интересные статьи

Интересные статьи

Выбор VPS для размещения сайта на 1С-Битрикс – задача не менее важная, чем разработка самого сайта.  Битрикс известен своей ресурсоёмкостью: без оптимального хостинга даже хорошо написанный сайт ...
В начале января 2024 года в Лас-Вегасе прошла выставка Consumer Electronics Show, CES. На ней собрались производители, дистрибьюторы, ритейлеры и потребители со всего мира, чтобы продемонстрировать ...
Сейчас на рынке импортных товаров творится полнейшее безумие. И касается это не только санкционной продукции. Любой импорт сейчас дороже и причин тому масса. Из-за нестабильного курса доллара поставщи...
Возможность интеграции с «1С» — это ключевое преимущество «1С-Битрикс» для всех, кто профессионально занимается продажами в интернете, особенно для масштабных интернет-магазинов.
Как обновить ядро 1С-Битрикс без единой секунды простоя и с гарантией работоспособности платформы? Если вы не можете закрыть сайт на техобслуживание, и не хотите экстренно разворачивать сайт из бэкапа...