
Традиционные форматы хранения данных постепенно перестают удовлетворять требованиям современных распределенных вычислений и аналитики больших данных. Каскадные обновления метаданных, проблемы консистентности и высокая стоимость поддержки вынуждают искать альтернативы. Ответом на запросы стало появление формата Iceberg, который предложил новую парадигму организации структурированных данных, позволяющую эффективно управлять петабайтами информации даже в распределенных средах.
Привет, Хабр. Меня зовут Алексей Белозерский. Я руководитель профессионального сервиса VK Data Platform, VK Tech. В этой статье я расскажу, что стало предпосылкой появления нового формата данных и что скрывает Iceberg «под толщей воды».
Предпосылки появления Lakehouse: проблемы стека DWH + Data Lake
Большинство компаний используют для работы с данными довольно типовой стек, в основе которого два решения:
Data Warehouse (DWH) — централизованное хранилище агрегированных и нормализованных данных, собранных из различных источников и подготовленных для дальнейшего анализа и отчетности. Оно ориентировано на конкретные потребности бизнеса и чаще всего используется для целей BI-отчетности и оперативного анализа.
Data Lake — хранилище для любых видов данных (структурные, полуструктурные, неструктурированные). Применяется для долгосрочного хранения данных и дальнейшего использования в целях глубокого анализа, ML и научных исследований.

Но подобная конфигурация имеет несколько проблем.
Деление компетенций. Организация вынуждена содержать две разные команды, обслуживающие Data Warehouse и Data Lake, что формирует разрыв в практиках, технологиях и релизных циклах.
Постоянное перемещение данных и задержки. Значительные усилия и ресурсы расходуются на постоянное перемещение больших объемов данных между разными системами хранения и обработки, снижая общую продуктивность. Помимо прочего, это приводит к задержкам: временные рамки доставки свежих данных расширяются, что снижает их ценность и затрудняет принятие эффективных решений.
Причем чем больше объем обрабатываемых данных и сложнее ИТ-инфраструктура, тем значительнее издержки.
В связи с этим у компаний возник запрос на решение, которое позволит:
использовать общий, удобный для всех формат;
хранить все данные в одном месте, причем хранить удобно — как в базе данных.
Помимо этого, был запрос на то, чтобы дешево хранить и гибко масштабировать объемы хранения (например, подойдет s3).
Ответом на эти запросы стало появление концепции Data Lakehouse и формата Iceberg, который комбинирует нужные свойства и впоследствии стал основой для построения Lakehouse. Но чтобы понять, как именно устроен формат, надо погрузиться в детали.
Lakehouse и Iceberg: детали технической реализации
Обычно специалисты уровня Junior воспринимают Lakehouse как реализацию, при которой данные лежат в S3-совместимом объектном хранилище, причем сами данные, как правило, имеют любой файловый формат, вплоть до JSON или CSV. Такой подход интуитивно понятен, ведь кажется логичным положить данные в JSON, упаковать в архив и назвать это Lakehouse.
Но в действительности подобная реализация имеет довольно много ограничений и недотягивает до статуса Data Lakehouse. Чтобы понять, чего недостаточно для построения настоящего Lakehouse, пошагово разберем все аспекты.
Шаг 1. Выбор общего формата данных
В первую очередь нужно выбрать колоночный формат хранения данных, чтобы избежать перебора всех данных для каждой задачи и внести дополнительную логику на уровне самого хранилища.
Самым простым и эффективным шагом является переход на Parquet — колоночный формат хранения данных, используемый в системах больших данных.
У Parquet есть ряд важных преимуществ и особенностей.
Колоночное хранение. Parquet предназначен для эффективного хранения больших объемов данных. Один файл обычно весит около 1 Гб. Ключевая особенность формата — колоночная организация. В отличие от обычных реляционных баз данных (row-oriented), где записи расположены построчно, в Parquet данные сгруппированы по столбцам. Это значит, что при выполнении запросов выбираются только интересующие поля, что резко снижает количество считываемых данных и повышает скорость выполнения запросов.
Описание схемы данных и контрольные суммы. Каждый файл Parquet содержит подробную схему данных (metadata), которая описывает типы данных, порядок столбцов и их имена. Эта схема позволяет приложениям сразу понять структуру данных, не дожидаясь чтения самих данных. Помимо этого, файлы снабжены контрольными суммами, что гарантирует целостность данных при их перемещении или хранении в ��енадежных сетях.
Сжатие и кодирование данных по словарю. Parquet использует различные методы сжатия и кодирования данных, направленные на значительное уменьшение объема информации и повышение производительности. Среди них метод Dictionary Encoding (позволяет заменять повторяющиеся значения индексами), Run-Length Encoding (применяется для замены длинных серий одинаковых значений на значение и счетчик повторений) и Bit Packing (позволяет компактно представлять числа различной разрядности).
Адаптированность для хранения в S3: Write-Once, Read-Many, Range Get. Parquet идеально приспособлен для работы с облачными хранилищами. Особенность формата заключается в том, что данные чаще всего записываются один раз и многократно считываются (Write Once, Read Many). Так как S3 рассчитан на подобные сценарии, Parquet идеально вписывается в данную концепцию. Дополнительно, благодаря колоночной структуре и наличию метаданных, Parquet поддерживает частичное чтение файлов (Range Get), что позволяет получать только нужную область данных, не передавая весь файл целиком.

Таким образом, Parquet:
подходит для хранения в S3, HDFS: WORM;
позволяет отдавать только тот row chunk, который нужно по range get;
предоставляет статистику и индексы (min/max, page index, словари/опц. bloom-filters), которые движки используют для predicate pushdown (пропуск лишних данных).
Вместе с тем он:
не позволяет удалять из себя часть строк — надо только полностью переписывать файл;
не поддерживает эволюцию схемы — даже ��зменение порядка колонок и их переименование.
Таким образом, Parquet — очень продвинутый формат хранения данных в файле, но это все еще просто файл. И для построения Lakehouse нужен какой-то более высокоуровневый движок, который приблизит файл к таблице.
Шаг 2. Добавление файла с метадатой
Для «прокачки» Parquet требовалась некоторая «надстройка», которая позволит не только читать и дописывать данные chunks (append), но и выполнять операции DELETE (WHERE), UPDATE, MERGE INTO.
Чтобы добиться этого, рядом с parquet можно разместить еще один файл (тоже parquet) с информацией о том, что именно читать не надо. В этом так называемом Delete file (который может быть как позиционный, так и логический) можно отметить для читателя, что огромный основной файл с миллионом строк содержит несколько строк, которые вообще не нужны при чтении.
Подобная практика используется в различных форматах данных и известна как «дельта-формат»: основное хранилище дополняется небольшим набором метаданных, позволяющих точечно вносить изменения, исправлять или добавлять элементы.
Работает это довольно просто:
если видим, что файл parquet исключается полностью, то сразу меняем old_parquet на new_parquet и перезаписываем полностью данные (Copy on Write, COW);
если видим, что исключение только частичное, то дописываем рядом, что отдельную часть из исходного файла читать не надо, а на этапе чтения склеиваем одно с другим (Merge on Read, MOR).
Чтобы обеспечить понимание, к какому множеству data файлов относится какой delete файл, оптимально каждому файлу данных Parquet и каждому файлу удаления назначить уникальный порядковый номер. Например, Delete file с номером 100 будет относиться ко всем файлам с номерами ниже своего, то есть seq_no(delta) больше, чем seq_no(data). Благодаря этому формируется упорядоченная цепочка файлов.
Таким образом, мы начали с формата CSV, далее перешли к более продвинутому формату Parquet, а теперь продвинулись еще дальше: создали технологичный delta-формат, который, несмотря на возросшую сложность, значительно расширил возможности.
Шаг 3. Внедрение табличного движка
Следующая задача: как обновить тысячи файлов в распределенном хранилище, сохранив консистентность? Проблема особенно актуальна при выполнении массовых изменений — например, при удалении всех следов конкретного пользователя за долгий период.
В таких кейсах решение силами одиночного воркера невозможно — требуется кластерная обработка. Но при работе множества узлов возрастает риск сбоя, приводящего к неполноценному обновлению данных. Чтение таких файлов приведет к ошибкам, поскольку данные станут несогласованными.
Кроме того, операции расширения схемы (float → double, short → long) требуют особого подхода: изменение типов должно выполняться одновременно над всеми файлами, иначе чтение станет невозможным.
Таким образом, необходима поддержка атомарности и принципов ACID, обеспечивающих целостность данных даже при масштабных изменениях.
Для ответа на подобные запросы требуется табличный движок, который должен:
поддерживать атомарность изменений или ACID, даже если нужно изменить тысячи файлов;
держать в уме свою схему данных и уметь ее менять, не меняя нижележащие parquet-файлы;
разобраться в data, delete, в том, что к чему относится, и уметь показать чтецам правильную согласованную картину;
уметь эффективно работать с S3, его возможностями и особенностями.
И здесь мы переходим к следующему шагу.
Шаг 4. Предпосылки появления формата Iceberg
Чтобы достичь атомарности изменений, следует переходить от одного целостного состояния таблицы к другому, исключив промежуточные положения. Классический путь реализации этой концепции — превращение таблицы в лог транзакций, где каждое изменение фиксируется последовательно, формируя серию снапшотов, каждый из которых является самостоятельным состоянием всей таблицы.
Однако S3 лишен поддержки атомарной работы со множеством объектов одновременно: нельзя одновременно ни переименовать тысячу файлов, ни гарантированно записать их единым действием. Простые команды, доступные в S3 («загрузить файл», «получить файл», «удалить файл»), ограничивают гибкость операций.
Для обхода ограничений специалисты предложили ввести слой абстракции в виде единого файла метаданных, представляющего собой корневой элемент дерева, ведущего к нижестоящим объектам. То есть, меняя этот единственный верхний файл, мы обеспечиваем плавный переход из одного целостного состояния в другое, поддерживая консистентность данных.
Эта концепция нашла воплощение в формате Iceberg. Рассмотрим подробнее его реализацию.

Iceberg применяет трехуровневую систему метаданных. Основой служит специальный snapshot-файл, реализуемый в виде центрального JSON-документа (metadata.json), содержащего полную информацию о структуре данных и правилах их чтения.
Далее следуют манифесты — наборы файлов, включающие сами данные, информацию об удалениях и дополнительные метаданные. Их необходимость обусловлена многопоточностью среды: одновременно записывают данные многочисленные клиенты, будь то Spark-кластеры или Kafka-брокеры. Чтобы поддержать организованность множества файлов, вводится понятие манифеста, отражающее логическое объединение элементов.
Так как манифестов бывает много, они формируют список. Несколько таких списков образуют снапшот, сводя всю сложную структуру в единую точку входа — центральный JSON-файл метаданных. Замена этого файла гарантирует последовательный и безопасный переход от одной целостной версии данных к следующей.
При этом процесс записи в Iceberg реализован довольно просто. Предположим, требуется изменить тысячу parquet-файлов. Вместо прямого редактирования существующих данных создается новый набор файлов с внесенными изменениями. Parquet-файлы и манифесты неизменяемы, поэтому новые версии сохраняются отдельно от оригинала.
Только после полной подготовки набора измененных файлов, формирования необходимых ссылок и проверки целостности производится замена основного JSON-файла метаданных. Фактически меняется ссылка на актуальную версию данных, обеспечивая атомарность перехода между версиями.
Благодаря такому подходу, основанному на многослойной организации метаданных, таблица в Iceberg демонстрирует поведение, сходное с классической базой данных. Важнейший аспект — изолированность пользователей: каждый получает доступ к своей копии JSON-метаданных, соответствующей конкретной точке в истории данных. Это дает возможность организовать транзакционные операции и исключить конфликты при длительном доступе к данным.
Именно благодаря решению этих вопросов Iceberg приобрел популярность: он позволяет воссоздать характеристики полноценной СУБД в среде Data Lake, используя объекты S3, сохраняя консистентность и атомарность операций.
Шаг 5. Каталог
Поддержав консистентность на уровне отдельных файлов, предстоит разобраться с конфликтами, возникающими при попытке одновременного изменения таблицы несколькими пользователями. Решением здесь становится механизм MVCC (Multiversion Concurrency Control), позаимствованный из мира реляционных баз данных.
Идея проста: поместим указатели на главные JSON-файлы в отдельную транзакционную базу данных, которая будет содержать информацию о связях таблиц с соответствующими актуальными версиями метаданных. Такой подход позволяет каждому пользователю получать собственную копию метаданных, устраняя конкуренцию.
При помощи MVCC конфликты разрешаются автоматически: быстрые транзакции применяются первыми, более поздние адаптируются к изменениям или откатываются обратно. В результате возможна ситуация неуспешного коммита, когда непримененные данные остаются в S3 и пользователям придется начать заново. Таким образом, несмотря на специфику S3, Iceberg имитирует полноценное поведение базы данных с контролем версий.
Минимальная реализация каталога Iceberg представлена компактной базой PostgreSQL, хранящей ссылки на актуальные JSON-файлы.
При этом наличие каталога открывает две дополнительные возможности:
Time Travel. Сохраняя историю состояний таблицы наряду с актуальным снапшотом, можно мгновенно увидеть, как выглядели данные ранее — минуту, час или неделю назад. Подобная механика полезна для восстановления случайных потерь данных и устраняет потребность в громоздких резервных копиях.
Версионирование данных (Git-style). Каталоги позволяют ветвить и сливать версии данных, создавая отдельные ветви для экспериментов и исследований. Например, дата-сайентисты могут оценить влияние новых данных на старую модель.
Шаг 6. Ложка дегтя
Несмотря на высокую технологичность Data Lakehouse, в ходе эксплуатации образуется значительное количество неиспользуемых файлов — своеобразный цифровой мусор: избыточные куски данных, устаревшие версии файлов и манифестов, неуспешные коммиты.
Возникает необходимость регулярной уборки хранилища.
Для этого можно использовать разные процедуры, в том числе:
rewrite_data_files — сливает несколько data файлов в один, пересортировывает;
rewrite_delete_files / rewrite_position_delete_files — сливает delete-файлы в один;
rewrite_manifests — сливает manifests;
expire_snapshots — удаляет неактуальные snapshots и физически чистит недостижимые файлы и manifests;
remove_orphan_files — удаляет файлы, на которые не ссылается ни один snapshot и manifest (например, что-то недописанное, остатки неудачных коммитов и прочее).
К чему пришли
Таким образом, пройдя весь путь «эволюции», мы приходим к ситуации, когда с Data Lakehouse не просто можем хранить файлы в S3, а:
пользуемся всеми преимуществами parquet;
умеем эффективно модифицировать строки, частично обновлять и удалять;
поддерживаем эволюционирование схемы;
можем использовать ACID и прозрачный COMMIT (лучше напишем данные в файлы, которые окажутся никому не видны, чем потеряем консистентность данных);
поддерживаем MVCC, где писатели не конфликтуют с чтецами (даже умеем в Serializable);
пользуемся каталогом, где можем попробовать реализовать продвинутые техники управления данными.
Вместе с тем есть и некоторые слабые стороны. Например:
оставляем много мусора, который потом когда-то надо убирать, но при этом уборка мусора может конфликтовать с работой с данными (привет, MVCC);
используем много метаданных, которые надо читать на этапе планирования запроса (тут можем что-то кешировать на движке чтеца, такого как Trino или Spark);
процедура как записи, так и чтения данных довольно многослойная и непростая.
Влияние Data Lakehouse и Iceberg на изменение подходов к работе с данными
Путь к Data Lakehouse был эволюционным:
Использование DWH и Data Lake для реализации сложных сценариев обработки данных создавало много ограничений.
Постепенно стала очевидной и важность разделения процессов вычислений и хранения, которое упрощает администрирование и экономит средства.
Параллельно улучшился доступ к технологиям виртуализации: Kubernetes стал стандартом корпоративной инфраструктуры, позволив легко разворачивать контейнеры для аналитической нагрузки.
Вычислительные движки также адаптировались к новым условиям: Spark и Flink успешно работают в Kubernetes, хотя изначально создавались для экосистемы Hadoop.
То есть эволюция шла с обеих сторон: создание форматов хранения данных, таких как Iceberg, позволило эффективнее управлять информацией, а интеграция контейнеров сделала возможным быстрое развертывание систем в любой инфраструктуре.
В результате появился Data Lakehouse — гибридное решение, объединившее лучшие черты Data Lake и классического хранилища данных, а также комбинирующее эффективные форматы хранения и легкую масштабируемость вычислений.

В Data Lakehouse Iceberg функционирует по принципу «многие ко многим»: вычислительные движки (Trino, Spark, ClickHouse, Flink и другие) могут обращаться к нескольким каталогам одновременно, а один каталог способен обслуживать разные типы нагрузки. Iceberg становится универсальным языком обмена данными. В результате формат находит применение как в Open-Source-проектах, так и в коммерческом ПО.

При этом Iceberg ликвидирует разрыв между Data Lake и традиционными хранилищами данных, позволяя интегрировать их технологически и организационно. Это ускоряет доставку данных, снимает искусственные ограничения и упрощает работу с ними.

Что в итоге
Безусловно, Iceberg — сложный формат, который скрывает «под водой» за��утанную комбинацию технологий и решений. Но в действительности для полноценного использования Iceberg совсем необязательно понимать, что происходит «под капотом»: разобраться с технологией и начать успешно ее применять для построения Data Lakehouse можно и без этого. Тем более что многие облачные провайдеры предоставляют уже готовые и преднастроенные решения «из коробки» (например, VK Data Lakehouse от VK Cloud), позволяя бизнесу просто использовать передовые решения и не уводя фокус с основных бизнес-задач.
Подписывайтесь на мой канал Архитектор Данных и на канал Данные на стероидах. Там очень много про данные и облака.