Delta Kernel, UniForm и экосистема
Delta Lake — это протокол, а не движок. Но протокол полезен только если его поддерживают множество движков. В первые годы жизни Delta Lake каждый коннектор (delta-rs, Trino delta connector, Flink connector) реализовывал protocol spec самостоятельно. С ростом сложности протокола (Deletion Vectors, V2 Checkpoints, Type Widening) это стало неустойчивым.
Этот урок — о том, как Delta Lake решает проблему экосистемной фрагментации: Delta Kernel, UniForm, Delta Sharing, и матрица совместимости движков.
Delta Kernel
Delta Kernel — набор библиотек, которые абстрагируют детали протокола от connector-разработчиков. Вместо реализации spec побайтово, разработчик реализует Engine trait (набор интерфейсов для чтения JSON/Parquet и работы с файловой системой), а Kernel берёт на себя log replay, conflict resolution, data skipping и protocol features.
Движок (DuckDB, DataFusion, ClickHouse, Trino, …)
Движок (DuckDB, DataFusion, Polars, ClickHouse, Trino и др.) хочет читать/писать Delta-таблицу. Вместо реализации протокола самостоятельно, он использует Delta Kernel.Delta Table (S3 / ADLS / GCS / Local FS)
Delta-таблица на storage (S3, ADLS, GCS, локальная FS). Kernel абстрагирует детали протокола — движок работает через высокоуровневый API (Scan/Transaction), не зная о protocol versions, deletion vectors, или checkpoint formats.Два Kernel — Rust и Java
Delta Kernel существует в двух реализациях:
| delta-kernel-rs (Rust) | Delta Kernel Java | |
|---|---|---|
| Язык | Rust + C FFI | Java |
| Целевые движки | DuckDB, DataFusion, Polars, ClickHouse, C/C++ | Spark, Trino, Flink, JVM-based |
| In-memory формат | Arrow | Heap-based vectors |
| Статус | Experimental (v0.20.0) — reads + writes (blind append) | Experimental — reads + writes |
| DefaultEngine | Arrow + Tokio (async) | Встроенный |
| Репозиторий | delta-io/delta-kernel-rs | delta-io/delta-kernel |
// Пример: чтение Delta-таблицы через delta-kernel-rs (Rust)
use delta_kernel::engine::default::DefaultEngine;
use delta_kernel::Table;
let engine = DefaultEngine::try_new(
&url::Url::parse("file:///path/to/table").unwrap(),
std::collections::HashMap::new(),
)?;
let table = Table::try_from_uri("file:///path/to/table")?;
let snapshot = table.snapshot(&engine, None)?;
let scan = snapshot.into_scan_builder().build()?;
// Scan возвращает ScanResult — итератор файлов с данными
for result in scan.execute(&engine)? {
let scan_result = result?;
// scan_result.raw_data — данные в Arrow формате
// scan_result.mask — selection vector (deletion vectors)
}
Delta Kernel не заменяет delta-rs (Python deltalake library). delta-rs — полноценная реализация Delta Lake на Rust с высокоуровневым API. Delta Kernel — низкоуровневый фундамент, на котором строятся коннекторы. delta-rs уже начал интеграцию с delta-kernel-rs для protocol handling.
Зачем Kernel?
Проблема без Kernel: каждый коннектор реализует protocol spec самостоятельно. При добавлении новой protocol feature (например, Deletion Vectors) все коннекторы должны обновиться. На практике коннекторы отстают на месяцы-годы, что фрагментирует экосистему.
С Kernel: новая protocol feature реализуется один раз в Kernel. Все коннекторы, использующие Kernel, получают поддержку автоматически при обновлении зависимости.
UniForm: Universal Format
UniForm — механизм автоматической генерации Iceberg-метаданных (и опционально Hudi) при каждой записи в Delta-таблицу. Одна копия Parquet-файлов — несколько форматов метаданных:
Запись в Delta-таблицу (Spark, delta-rs, Flink)
Запись в Delta-таблицу через любой Delta-writer (Spark, delta-rs, Flink). UniForm включён как table property.Delta readers + Iceberg readers + Hudi readers → одни данные
Один набор Parquet-файлов читается через Delta-клиенты (Spark, DataFusion, Polars), Iceberg-клиенты (Snowflake, Trino, BigQuery, Athena), и опционально Hudi-клиенты. Без дублирования данных.Включение UniForm
-- При создании таблицы (Delta Lake 3.1+)
CREATE TABLE orders (
order_id BIGINT,
city STRING,
amount DECIMAL(10, 2)
) TBLPROPERTIES (
'delta.enableIcebergCompatV2' = 'true',
'delta.universalFormat.enabledFormats' = 'iceberg'
);
-- Для существующей таблицы (Delta Lake 3.2+)
REORG TABLE orders APPLY (UPGRADE UNIFORM(ICEBERG_COMPAT_VERSION=2));
Ограничения UniForm
- UniForm — read-only для Iceberg/Hudi клиентов. Запись через Iceberg-клиент может повредить Delta-таблицу
- Требует column mapping (minReaderVersion ≥ 2, minWriterVersion ≥ 7)
- Не совместим с Deletion Vectors
- Iceberg-версии не совпадают с Delta-версиями (metadata generation — асинхронная)
- Требует Hive Metastore (HMS) или Unity Catalog как Iceberg catalog
UniForm — однонаправленный. Delta Lake пишет, Iceberg/Hudi клиенты только читают. Запись через Iceberg-клиент в UniForm-таблицу может выполнить garbage collection, о котором Delta не знает — и уничтожить данные.
Delta Sharing
Delta Sharing — открытый протокол для безопасного обмена данными без копирования:
Ключевые принципы:
- Данные не копируются — recipient получает pre-signed URLs для чтения Parquet-файлов напрямую из storage provider-а
- REST API — стандартный HTTP протокол, клиент может быть на любом языке
- Recipient tokens — авторизация через bearer tokens с expiration
- Table versioning — recipient может указать version или timestamp для time travel
# Delta Sharing: чтение shared таблицы
import delta_sharing
# Profile файл содержит endpoint + bearer token
profile = delta_sharing.SharingProfile.read("./provider.share")
# Листинг доступных таблиц
client = delta_sharing.SharingClient(profile)
tables = client.list_all_tables()
# Чтение таблицы в pandas
table_url = f"{profile}#share_name.schema_name.table_name"
df = delta_sharing.load_as_pandas(table_url)
Catalog-Managed Tables
Delta Lake 4.1 вводит концепцию Catalog-Managed Tables — каталог (Unity Catalog, Hive Metastore) становится source of truth для состояния таблицы:
- Каталог управляет storage location, metadata caching, и garbage collection
- Автоматический VACUUM — каталог запускает cleanup без ручного вмешательства
- Автоматический OPTIMIZE — clustering on write, adaptive file sizing
- Credential vending — временные учётные данные для доступа к storage
Это отличается от традиционной модели, где таблица — самодостаточная (всё состояние в _delta_log/), а каталог — опциональный discovery layer.
Матрица совместимости движков
Для Python-first стека без Spark рекомендуется библиотека deltalake (delta-rs) — нативная Rust-реализация с Python bindings через PyO3. Нет зависимости на JVM, нет Spark runtime, работает с PyArrow, pandas, Polars. pip install deltalake — и готово.
Когда использовать Delta Lake
Delta Lake — сильный выбор когда:
| Сценарий | Delta Lake | Альтернатива |
|---|---|---|
| Streaming + batch на одной таблице | + Streaming reads, CDF, exactly-once | Iceberg (поддерживает, но менее зрелый streaming) |
| Databricks/Spark экосистема | + Нативная поддержка, все features | Iceberg (нативный в Snowflake) |
| Python-first стек без JVM | + delta-rs, deltalake library | Iceberg (PyIceberg) |
| Multi-engine reads (Snowflake + Spark) | + UniForm → Iceberg клиенты | Iceberg (нативно multi-engine) |
| Очень большие таблицы (PB scale) | + Liquid Clustering, OPTIMIZE | Iceberg (более зрелый metadata pruning) |
| Строгий multi-engine write | UniForm read-only | Iceberg (REST Catalog) |
Детальное сравнение Delta Lake, Iceberg, Hudi и Paimon — в Модуле 17: Выбор формата на практике.
Итоги модуля
За 6 уроков мы разобрали Delta Lake побайтово — от JSON-коммитов в _delta_log/ до Liquid Clustering и UniForm:
- Transaction Log — JSON actions, protocol versions, checkpoints
- ACID-транзакции — OCC, conflict resolution, Coordinated Commits
- Time Travel + VACUUM — version/timestamp access, retention, log replay
- Оптимизация размещения — data skipping, OPTIMIZE, Z-ORDER, Liquid Clustering
- Change Data Feed — incremental ETL, streaming reads, medallion architecture
- Kernel + UniForm + экосистема — connector foundation, multi-format reads
Продолжение — Модуль 12: Apache Iceberg Deep-Dive, где мы разберём альтернативный table format с другой архитектурой метаданных.