Куратор раздела

Немного об этой главе
Многие компания начинают сейчас переходить на Iceberg и концепцию Lakehouse. Так что знакомство с данным форматом данных позволит держать руку на пульсе.
Приятного изучения.
Apache Iceberg
Введение
Данные стали ключевым активом для организаций: они необходимы для анализа тенденций, построения прогнозов и поддержки принятия решений. Рост объёмов и скорости генерации данных потребовал появления новых архитектур хранения и обработки.
Раньше использовались:
- Хранилища данных (Data Warehouse) — надёжные, но дорогие и ограниченные только структурированными данными.
- Озёра данных (Data Lake) — гибкие и дешёвые, но без гарантий ACID и полноценной работы с транзакциями.
Появился запрос на архитектуру, которая сочетает гибкость озёр данных и надёжность хранилищ.
Что такое Apache Iceberg?
Apache Iceberg — это открытый табличный формат для озёр данных, который:
- Абстрагирует физическое хранение файлов.
- Обеспечивает транзакционность (ACID) и управление версиями (snapshots).
- Поддерживает эволюцию схем и секционирования без миграции данных.
- Делает возможной эффективную SQL-аналитику прямо в Data Lake.
Ключевые преимущества
- Гибкость: хранение любых форматов данных (Parquet, ORC, Avro).
- Транзакции: безопасные вставки, обновления, удаления.
- Time Travel: доступ к состоянию таблицы в прошлом.
- Совместимость: интеграция с Apache Spark, Flink, Trino, Dremio и другими движками.
- Масштабируемость: изначально разработан для работы с петабайтами данных (Netflix).
Архитектура Apache Iceberg
Apache Iceberg построен по многоуровневой архитектуре, которая разделяет данные, метаданные и каталог. Такой подход обеспечивает масштабируемость, гибкость и поддержку транзакций ACID в озёрах данных.

1. Слой данных (Data Layer)
- Хранит фактические данные таблицы.
- Элементы:
- Файлы данных (Parquet, ORC, Avro) — содержат строки таблицы.
- Файлы удаления — описывают строки или файлы, которые были удалены
(
DELETE,MERGE).
- Данные обычно размещаются в распределённых файловых системах (HDFS) или объектных хранилищах (Amazon S3, ADLS, GCS).
- Слой независим от вычислительного движка, что делает его универсальным.
2. Слой метаданных (Metadata Layer)
- Центральная часть Iceberg, отвечающая за структуру и историю таблицы.
- Состоит из:
- Файлов манифеста — список файлов данных и статистика по ним (кол-во строк, min/max значения).
- Списков манифестов — объединяют манифесты в один снимок (snapshot).
- Файлов метаданных — определяют схему, секционирование, список снимков.
- Puffin-файлов — хранят расширенную статистику и метрики.
- Метаданные образуют дерево, что позволяет эффективно планировать запросы, используя partition pruning и статистику.
3. Каталог (Catalog Layer)
- Управляет именами таблиц и указывает на актуальные файлы метаданных.
- Вместо хранения путей к директориям (как в Hive) Iceberg работает с ссылкой на последний мета-файл.
- Поддерживаемые реализации:
- Hive Metastore
- AWS Glue
- Project Nessie
- JDBC/REST-каталоги
- Каталог обеспечивает согласованность между различными движками (Spark, Flink, Trino и др.).
Ключевые особенности архитектуры
- ACID-транзакции без централизованной СУБД.
- Эволюция схемы и секционирования без миграции данных.
- Time travel — возможность читать таблицу в прошлом состоянии.
- Масштабируемость — изначально спроектирован для работы с петабайтами данных.
Файлы удаления и стратегии записи (MOR vs COW)
В Apache Iceberg операции DELETE и UPDATE реализуются через специальные
файлы удаления (delete files). Они позволяют эффективно управлять изменениями,
не переписывая сразу все данные.
Типы файлов удаления
-
Position Deletes
- Содержат ссылки на конкретные строки в файле данных по смещению (row position).
- Подходят для точечных обновлений и удалений.
-
Equality Deletes
- Хранят условие удаления по значениям столбцов (например:
user_id=12345). - Удобны для массовых удалений или обновлений по ключу.
- Хранят условие удаления по значениям столбцов (например:
Стратегии записи
1. Copy-on-Write (COW)
- При обновлениях или удалениях Iceberg переписывает целый файл данных, исключая ненужные строки.
- Плюсы:
- Простая модель — при чтении не требуется дополнительная обработка.
- Быстрое и лёгкое чтение.
- Минусы:
- Запись дороже по времени и ресурсам (особенно при малых изменениях).
- Когда использовать:
- Таблицы с редкими изменениями.
- Сценарии, где приоритет — скорость чтения.
2. Merge-on-Read (MOR)
- Изменения фиксируются во файлах удаления, а переписывание файлов откладывается.
- При чтении движок объединяет (merge) данные и delete-файлы.
- Плюсы:
- Быстрая запись, минимальные накладные расходы на обновления.
- Подходит для потоковой загрузки (streaming).
- Минусы:
- Более тяжёлое чтение (нужно применять delete-файлы поверх данных).
- Когда использовать:
- Таблицы с частыми обновлениями.
- Real-time аналитика, где важна скорость записи.
Сравнение COW и MOR
| Характеристика | Copy-on-Write (COW) | Merge-on-Read (MOR) |
|---|---|---|
| Скорость записи | Медленная (переписывание) | Быстрая (delete files) |
| Скорость чтения | Быстрая | Медленнее (merge при чтении) |
| Простота модели | Простая | Более сложная |
| Использование | Batch-аналитика | Streaming и частые апдейты |
Примеры работы с таблицами(отличные от обычного SQL)
#запуск spark-сессии с iceberg
from pyspark.sql import SparkSession
spark = (
SparkSession.builder
.appName("IcebergExample")
.config("spark.sql.catalog.my_catalog", "org.apache.iceberg.spark.SparkCatalog")
.config("spark.sql.catalog.my_catalog.type", "hive")
.config("spark.sql.catalog.my_catalog.uri", "thrift://localhost:9083")
.getOrCreate()
)
# Создание таблицы
spark.sql("""
CREATE TABLE my_catalog.db.orders (
order_id BIGINT,
customer_id BIGINT,
amount DECIMAL(10,2),
created_at TIMESTAMP
)
USING iceberg
PARTITIONED BY (days(created_at))
""")
# Time travel (по snapshot-id)
spark.sql("""
SELECT * FROM my_catalog.db.orders VERSION AS OF 918273645
""").show()
# Time travel (по времени)
spark.sql("""
SELECT * FROM my_catalog.db.orders TIMESTAMP AS OF '2025-09-28 14:00:00'
""").show()
# Компактизация файлов
spark.sql("""
CALL my_catalog.system.rewrite_data_files('db.orders')
""")
# Очистка старых снапшотов
spark.sql("""
CALL my_catalog.system.expire_snapshots('db.orders')
WHERE committed_at < TIMESTAMP '2025-09-01 00:00:00'
""")
# Удаление delete-файлов
spark.sql("""
CALL my_catalog.system.remove_orphan_files('db.orders')
""")