Big Data
Delta Lake, Iceberg, Hudi
Data Lake на S3 - это просто папка с Parquet-файлами. Никаких транзакций, никакой истории, никакого контроля схемы. В 2016-2019 годах Netflix, Uber и Databricks независимо пришли к одному выводу: нужен слой метаданных поверх файлов, который даст ACID-гарантии без переезда в классическую БД. Так появились Iceberg, Hudi и Delta Lake - три формата, которые теперь стали стандартом индустрии.
- **Netflix** использует Iceberg для 10+ петабайт данных - schema evolution позволяет изменять схемы без остановки пайплайнов
- **Uber** создал Hudi для real-time аналитики поездок - upsert-ы по trip_id с задержкой <5 минут от события до видимости в Presto
- **Databricks** включил Delta Lake в Apache Spark и Lakehouse Platform - OPTIMIZE + Z-Order снижают время аналитических запросов в 10-100x
ACID поверх Data Lake
2019 год: аналитик Uber запускает UPDATE на таблице с поездками - и получает несогласованные данные, потому что другой Job читал её в тот же момент. Data Lake на S3 не знает ни о каких транзакциях: файлы просто лежат, и никто не координирует доступ. **Delta Lake, Apache Iceberg и Apache Hudi** - это форматные слои поверх Parquet, которые добавляют ACID без замены хранилища.
Ключевая идея: вместо того чтобы редактировать файлы на месте (что невозможно в S3), система ведёт **transaction log** - журнал всех операций. Каждая запись в log-е атомарна. Читатель смотрит в log, определяет какой набор файлов актуален, и читает только их.
| Формат | Разработчик | Лог транзакций | Особенность |
|---|---|---|---|
| Delta Lake | Databricks | _delta_log/*.json | Лучшая интеграция со Spark/Databricks |
| Apache Iceberg | Netflix/Apple | metadata/*.avro | Лучший для multi-engine (Flink, Trino, Spark) |
| Apache Hudi | Uber | .hoodie/ | Оптимизирован для частых upsert-ов |
**Оптимистичный concurrency:** Delta Lake использует optimistic locking - два writer-а пишут параллельно, но при commit проверяется конфликт. Если оба меняли одни файлы - один получает ConflictException и должен повторить. Это лучше, чем пессимистичные блокировки, которые блокируют читателей.
Delta Lake обеспечивает ACID на S3 с помощью:
Time Travel
Аналитик случайно удалил 500 тысяч строк из production-таблицы. В обычном Data Lake данные потеряны. В Delta Lake через 10 минут таблица восстановлена командой из одной строки - потому что каждый commit сохранён в лог, а старые файлы не удаляются сразу.
**Time travel** работает потому, что операции DELETE и UPDATE в Delta Lake не редактируют Parquet-файлы. Они добавляют запись в лог (`remove` для старых файлов, `add` для новых). Старые файлы остаются на диске до явного `VACUUM`. Запрос с указанием версии или timestamp просто читает состояние лога на тот момент времени.
**Iceberg** хранит не лог-файлы, а snapshot-дерево: каждый commit создаёт новый snapshot-метафайл, который ссылается на manifest-list, который ссылается на manifest-файлы с путями к Parquet. Time travel = выбор нужного snapshot-а. Механизм другой, результат тот же.
После случайного `DELETE FROM sales WHERE region='EU'` данные можно восстановить потому что:
Schema Evolution
Команда решила добавить колонку `discount_percent` в таблицу заказов. Проблема: старые Parquet-файлы этой колонки не содержат. Обычный Data Lake сломается или вернёт null для старых строк без контроля. **Schema Evolution** в Delta Lake/Iceberg/Hudi решает это контролируемо: схема таблицы эволюционирует, а совместимость гарантируется.
Есть два режима: **schema merging** (автоматически добавляет новые колонки) и **schema enforcement** (отклоняет данные с неожиданной схемой). По умолчанию Delta Lake включает enforcement, что защищает от случайной порчи данных. Evolution нужно явно разрешить.
**Iceberg Column IDs:** Iceberg хранит в метаданных не имена колонок, а их числовые id. Parquet-файл написан с id=3 для колонки `price`. После переименования в `amount` - id остаётся 3. Старые файлы читаются корректно без переписи. Delta Lake до version 2.x требовал column mapping mode для такого поведения.
Iceberg лучше Delta Lake справляется с переименованием колонок потому что:
Compaction и оптимизация файлов
После месяца работы таблица с событиями выросла до 50 тысяч мелких Parquet-файлов по 1 МБ каждый. Запрос, который раньше шёл 2 секунды, теперь занимает 4 минуты: Spark тратит больше времени на открытие файлов, чем на чтение данных. Это называется **small files problem** - классическая болезнь Data Lake при потоковой записи.
**Compaction** - процесс объединения мелких файлов в крупные (оптимально 128-512 МБ для Parquet). Delta Lake называет это `OPTIMIZE`, Iceberg - `rewrite_data_files`, Hudi - `compaction`. Дополнительно можно применить **Z-Order** - многомерную сортировку, которая физически совмещает связанные данные в одних файлах.
**VACUUM** vs **OPTIMIZE** - разные операции: OPTIMIZE объединяет мелкие файлы в крупные (улучшает скорость чтения). VACUUM удаляет старые файлы, помеченные как removed в delta_log (освобождает место). VACUUM ломает time travel за пределами retention period. Рекомендуемая последовательность: OPTIMIZE ежедневно, VACUUM еженедельно с RETAIN 168 HOURS.
VACUUM удаляет ненужные дубликаты и ускоряет запросы
VACUUM только освобождает дисковое место, удаляя файлы помеченные в delta_log как removed. На скорость чтения он не влияет. Для скорости нужен OPTIMIZE.
Смешение двух операций с похожими названиями - частая ошибка. OPTIMIZE = быстрее читать. VACUUM = меньше хранить.
Z-Order ускоряет запросы за счёт:
Delta Lake, Iceberg, Hudi
- ACID поверх S3/HDFS через transaction log: каждый commit атомарен, читатели видят согласованный snapshot
- Time travel: DELETE/UPDATE не удаляют файлы физически - старые данные доступны до явного VACUUM
- Schema evolution: добавление колонок без переписи файлов; Iceberg лидирует в rename через column_id
- Small files problem решается через OPTIMIZE/compaction + Z-Order для data skipping
- Выбор формата: Delta Lake для Spark/Databricks, Iceberg для multi-engine, Hudi для частых upsert-ов
Связанные темы
Table formats надстраиваются над базовыми компонентами Big Data стека:
- Parquet и колоночное хранение — Физический формат файлов под Delta/Iceberg/Hudi
- Spark: трансформации и действия — Основной движок для OPTIMIZE, VACUUM и аналитики
- Data Warehouse vs Data Lake — Lakehouse Architecture объединяет оба подхода
Вопросы для размышления
- В каких сценариях time travel с retention 7 дней недостаточен - и как это решить без увеличения retention?
- Почему Z-Order по двум колонкам хуже, чем по одной - и как пространственные кривые Гильберта смягчают эту проблему?
- Компания переходит с Hive таблиц на Delta Lake. Какие риски несёт изменение meta.id существующих таблиц для downstream пайплайнов?