Apache Iceberg & Data Warehousingхранилища данных

Fast-revision cheatsheet for Data Engineering interviews. Tailored for Senior/Lead DE. Шпаргалка для быстрого повторения перед Data Engineering интервью. Заточена под Senior/Lead DE.
DE INTERVIEW PREPПОДГОТОВКА К DE-ИНТЕРВЬЮ
Honesty line to lead with: "I've run Hive, Snowflake and BigQuery as the table/warehouse layer in production — not Iceberg itself — but I understand its design and the exact problems it solves." Then show the depth below so the gap reads as "new tool, same fundamentals." Честно начинать с: «Я работал с Hive, Snowflake и BigQuery как с табличным слоем/хранилищем в проде — сам Iceberg не использовал — но понимаю его устройство и какие именно проблемы он решает.» Потом показать глубину ниже, чтобы пробел читался как «новый инструмент, те же основы».
🟢 BeginnerНовичок 🔴 AdvancedПродвинутый

TL;DR — the 12 lines— 12 строк

  • Table format = metadata + ACID over data files. NOT a file format, NOT a storage engine.
  • Layers: catalog → metadata.json → manifest list → manifests → data files.
  • Atomicity = catalog compare-and-swap pointer; isolation = snapshot isolation; writers = optimistic concurrency.
  • Schema evolution = by field ID (add/drop/rename/reorder/widen, metadata-only, no rewrite).
  • Hidden partitioning: query the raw column, Iceberg prunes via a stored transform. No derived date column footgun.
  • Partition evolution: change the spec without rewriting old data.
  • Snapshots → time travel + rollback; expire_snapshots to reclaim space & truly delete.
  • CoW (read-fast / write-heavy) vs MoR (write-fast / read-merge) + compaction (rewrite_data_files).
  • Planning = metadata pruning (manifest-list → manifest stats → Parquet footers). No object-store LIST.
  • Iceberg (neutral, partition evolution) vs Delta (Spark/Databricks, txn log) vs Hudi (upsert/CDC).
  • Lakehouse = warehouse guarantees + lake economics + engine neutrality.
  • Why at scale: billions of events/day, many engines (Spark/Flink/Trino), one open copy of data.
  • Табличный формат = метаданные + ACID поверх файлов данных. НЕ формат файла, НЕ движок хранения.
  • Слои: catalog → metadata.json → manifest list → manifests → data files.
  • Атомарность = compare-and-swap указателя в каталоге; изоляция = snapshot isolation; писатели = оптимистичная конкуренция.
  • Эволюция схемы = по field ID (add/drop/rename/reorder/widen, только метаданные, без перезаписи).
  • Скрытое партиционирование: запрос идёт по исходному столбцу, Iceberg прунит через сохранённое преобразование. Никаких производных date-столбцов с ошибками.
  • Эволюция партиционирования: изменить спецификацию без перезаписи старых данных.
  • Снапшоты → time travel + rollback; expire_snapshots для освобождения места и настоящего удаления.
  • CoW (быстрое чтение / тяжёлая запись) vs MoR (быстрая запись / чтение с мёржем) + компакция (rewrite_data_files).
  • Планирование = прунинг метаданных (manifest-list → статистики manifest → footers Parquet). Никакого LIST в объектном хранилище.
  • Iceberg (нейтральный, эволюция партиций) vs Delta (Spark/Databricks, txn log) vs Hudi (upsert/CDC).
  • Lakehouse = гарантии хранилища + экономика озера + нейтральность движков.
  • Зачем на масштабе: миллиарды событий/день, множество движков (Spark/Flink/Trino), одна открытая копия данных.

What is a table format (and why)Что такое табличный формат (и зачем)

A table format is a spec + metadata layer that turns a pile of files in object storage into a real, transactional table: schema, snapshots, partitioning, ACID commits.

Табличный формат — это спецификация + метаданные, превращающие кучу файлов в объектном хранилище в настоящую транзакционную таблицу: схема, снапшоты, партиционирование, ACID-коммиты.

LayerExampleResponsibility
Query engineSpark, Flink, Trino, SnowflakePlan & execute SQL
Table formatIceberg, Delta, HudiSchema, snapshots, ACID, partitioning, metadata
File formatParquet, ORC, AvroBytes inside one file (encoding, stats)
Object storageS3, GCS, HDFSDurable bytes
СлойПримерОтветственность
Движок запросовSpark, Flink, Trino, SnowflakeПланирование и выполнение SQL
Табличный форматIceberg, Delta, HudiСхема, снапшоты, ACID, партиционирование, метаданные
Формат файлаParquet, ORC, AvroБайты внутри одного файла (кодирование, статистики)
Объектное хранилищеS3, GCS, HDFSНадёжные байты

It exists to fix the Hive table problem: a "table" was just a directory of files with partition info in a metastore — no atomic commits, expensive LIST on object stores, unsafe concurrent writes, fragile schema/partition changes.

Существует, чтобы решить проблему таблиц Hive: «таблица» была просто папкой файлов с информацией о партициях в метасторе — никаких атомарных коммитов, дорогой LIST в объектных хранилищах, небезопасные параллельные записи, хрупкие изменения схемы/партиций.

Anchor — Amal "I've lived the Hive pain: directory partitioning, metastore drift, slow listings on object stores. Iceberg is the metadata layer that makes those tables behave like a warehouse — the open-format version of what Snowflake/BigQuery gave me as managed engines."
Якорь — Amal «Я знаю боль Hive: партиционирование по папкам, рассинхрон метастора, медленные листинги в объектных хранилищах. Iceberg — это метаданные, которые заставляют таблицы вести себя как хранилище — open-source версия того, что дали мне Snowflake/BigQuery как управляемые движки.»

Metadata layers — read & write pathСлои метаданных — путь чтения и записи

CATALOG (Hive / Glue / JDBC / REST / Nessie) — atomic pointer + compare-and-swap │ points to current ▼ metadata.json (vN) schema(s) · partition spec(s) · sort orders · snapshot list · current snapshot │ ▼ (one per snapshot) manifest list lists manifests + per-manifest PARTITION RANGE summaries ──┐ prune whole manifests │ │ ▼ ▼ manifest files list DATA files + per-file COLUMN STATS (min/max/nulls) ── prune individual files │ ▼ data files Parquet / ORC / Avro (Parquet footers → row-group skipping)
CATALOG (Hive / Glue / JDBC / REST / Nessie) — атомарный указатель + compare-and-swap │ указывает на текущий ▼ metadata.json (vN) схема(ы) · спецификация партиций · порядок сортировки · список снапшотов · текущий снапшот │ ▼ (один на снапшот) manifest list перечисляет манифесты + сводки ДИАПАЗОНОВ ПАРТИЦИЙ по манифестам ──┐ прунит целые манифесты │ │ ▼ ▼ manifest files перечисляют ФАЙЛЫ ДАННЫХ + СТАТИСТИКИ СТОЛБЦОВ на файл (min/max/nulls) ── прунит отдельные файлы │ ▼ data files Parquet / ORC / Avro (футеры Parquet → пропуск row-group)

On read: catalog → current metadata → pick snapshot → manifest-list prune → manifest stats prune → Parquet row-group prune. No directory LIST; planning scales to millions of files.

При чтении: catalog → текущие метаданные → выбрать снапшот → прунить manifest-list → прунить статистики manifest → прунить row-group Parquet. Никакого LIST папок; планирование масштабируется на миллионы файлов.

On write (commit): write new data files + manifests + manifest list + new metadata.json, then atomically swap the catalog pointer using optimistic concurrency (retry if someone committed first).

При записи (коммит): записать новые файлы данных + манифесты + manifest list + новый metadata.json, затем атомарно заменить указатель в каталоге через оптимистичную конкуренцию (ретрай, если кто-то закоммитил первым).

Interviewer will probe "How is a commit atomic on S3, which has no atomic rename?" → Atomicity lives in the catalog's compare-and-swap on the metadata pointer, not in file renames. (Delta does it differently — an ordered transaction log of JSON files.)
О чём спросит интервьюер «Как коммит атомарен на S3, где нет атомарного rename?» → Атомарность живёт в compare-and-swap каталога для указателя метаданных, а не в переименованиях файлов. (Delta делает иначе — упорядоченный транзакционный лог из JSON-файлов.)

Schema & partition evolution + hidden partitioningЭволюция схемы и партиционирования + скрытое партиционирование

Schema evolution — by field IDЭволюция схемы — по field ID

Iceberg tracks every column by a unique field ID, not by name or position. So you can add, drop, rename, reorder, widen columns as a metadata-only change — no data rewrite.

Iceberg отслеживает каждый столбец по уникальному field ID, а не по имени или позиции. Поэтому можно добавлять, удалять, переименовывать, переупорядочивать, расширять столбцы как изменение только метаданных — без перезаписи данных.

  • Add → old files return NULL for the new column.
  • Rename → ID unchanged, only the name mapping changes (safe).
  • Drop → ID no longer projected.
  • Добавление → старые файлы возвращают NULL для нового столбца.
  • Переименование → ID не меняется, меняется только маппинг имени (безопасно).
  • Удаление → ID больше не проецируется.
Gotcha Hive/plain-Parquet resolve columns by position or name → a rename/reorder can silently read the wrong column. Field IDs make Iceberg correct. Also: drop-then-re-add the same name = a new ID; old data won't resurface.
Подвох Hive/обычный Parquet разрешают столбцы по позиции или имени → переименование/переупорядочивание может молча читать не тот столбец. Field ID делают Iceberg корректным. Также: удалить-потом-вернуть то же имя = новый ID; старые данные не всплывут.
Hidden partitioning — the footgun killerСкрытое партиционирование — убийца ошибок

You declare a partition transform on a real column; Iceberg derives and stores the partition value. Users query the raw column and pruning happens automatically.

Вы объявляете партиционное преобразование на реальный столбец; Iceberg вычисляет и сохраняет значение партиции. Пользователи запрашивают исходный столбец, а прунинг происходит автоматически.

CREATE TABLE events (
  event_time timestamp, user_id bigint, payload string
) PARTITIONED BY (days(event_time), bucket(16, user_id));

-- analyst queries the RAW column; Iceberg prunes partitions for them:
SELECT * FROM events WHERE event_time >= '2026-06-01';
CREATE TABLE events (
  event_time timestamp, user_id bigint, payload string
) PARTITIONED BY (days(event_time), bucket(16, user_id));

-- аналитик запрашивает ИСХОДНЫЙ столбец; Iceberg прунит партиции за него:
SELECT * FROM events WHERE event_time >= '2026-06-01';

Transforms:Преобразования: years/months/days/hours, bucket(N,col), truncate(N,col), identity.

Anchor — Amal "In Hive/Snowflake/BigQuery I had to maintain a derived date column and teach analysts to filter on it. Hidden partitioning removes that whole class of mistakes."
Якорь — Amal «В Hive/Snowflake/BigQuery мне приходилось поддерживать производный date-столбец и учить аналитиков фильтровать по нему. Скрытое партиционирование убирает весь этот класс ошибок.»
Partition evolution — change granularity, no rewriteЭволюция партиций — смена гранулярности без перезаписи

Change the partition spec over time (e.g. days(ts)hours(ts)) without rewriting old data. Old files keep their old spec; new files use the new one; manifests record which spec each file used, so planning handles the mix.

Изменить спецификацию партиций со временем (напр., days(ts)hours(ts)) без перезаписи старых данных. Старые файлы сохраняют старую спецификацию; новые используют новую; манифесты записывают, какую спецификацию использовал каждый файл, так что планировщик обрабатывает смесь.

Gotcha Hive partition = a physical directory column → repartitioning means a full table rewrite, and queries must filter on the derived column or do a full scan.
Подвох Партиция Hive = физический столбец-папка → перепартиционирование означает полную перезапись таблицы, а запросы должны фильтровать по производному столбцу или делать full scan.

Snapshots, time travel & ACIDСнапшоты, time travel и ACID

Every write creates an immutable snapshot (a manifest list + reachable data files). History is kept in metadata.json.

Каждая запись создаёт неизменный снапшот (manifest list + достижимые файлы данных). История хранится в metadata.json.

-- time travel
SELECT * FROM t FOR SYSTEM_VERSION AS OF 8675309;     -- snapshot id
SELECT * FROM t FOR SYSTEM_TIME AS OF '2026-06-10 00:00:00';

-- rollback = your incident button (metadata-only, cheap)
CALL catalog.system.rollback_to_snapshot('db.t', 8675309);

-- reclaim storage + truly delete old data
CALL catalog.system.expire_snapshots('db.t', TIMESTAMP '2026-06-01 00:00:00');
-- time travel
SELECT * FROM t FOR SYSTEM_VERSION AS OF 8675309;     -- snapshot id
SELECT * FROM t FOR SYSTEM_TIME AS OF '2026-06-10 00:00:00';

-- rollback = кнопка инцидента (только метаданные, дёшево)
CALL catalog.system.rollback_to_snapshot('db.t', 8675309);

-- освободить хранилище + действительно удалить старые данные
CALL catalog.system.expire_snapshots('db.t', TIMESTAMP '2026-06-01 00:00:00');
ACID propertyHow Iceberg delivers it
AtomicityOne commit = one atomic catalog pointer swap; all-or-nothing.
ConsistencyReaders always see a complete snapshot, never half-written files.
IsolationSnapshot isolation: reader pinned to snap N unaffected by writer making N+1. Writers use optimistic concurrency.
DurabilityFiles + metadata persisted in object storage.
Свойство ACIDКак Iceberg его обеспечивает
АтомарностьОдин коммит = одна атомарная замена указателя каталога; всё или ничего.
СогласованностьЧитатели всегда видят полный снапшот, никогда не наполовину записанные файлы.
ИзоляцияИзоляция снапшотами: читатель, прикреплённый к снапшоту N, не затрагивается писателем, создающим N+1. Писатели используют оптимистичную конкуренцию.
НадёжностьФайлы + метаданные сохранены в объектном хранилище.
Interviewer will probe "Two jobs write concurrently?" → Both stage files; first to commit wins; the second sees the pointer moved and re-validates / retries. Appends are usually conflict-free; overwrites/deletes on the same partitions can genuinely conflict.
О чём спросит интервьюер «Две джобы пишут одновременно?» → Обе готовят файлы; первая, кто закоммитит, выигрывает; вторая видит сдвинутый указатель и переподтверждает / делает ретрай. Дозаписи обычно бесконфликтны; перезаписи/удаления в одних и тех же партициях могут реально конфликтовать.
GDPR gotcha A DELETE removes rows from current reads, but the bytes survive in old snapshots until expire_snapshots + remove_orphan_files. True erasure needs snapshot expiry, not just the DELETE.
Подвох GDPR DELETE удаляет строки из текущих чтений, но байты выживают в старых снапшотах, пока не запустить expire_snapshots + remove_orphan_files. Настоящее стирание требует истечения снапшотов, а не только DELETE.

Copy-on-write vs Merge-on-read + compactionCopy-on-write vs Merge-on-read + компакция

Copy-on-write (CoW)Merge-on-read (MoR)
Update/deleteRewrite affected data files entirelyWrite small delete files (position / equality)
Write costHighLow
Read costLow (no merge)Higher (merge data + delete files)
Best forRead-heavy, infrequent updatesStreaming upserts / frequent CDC
Copy-on-write (CoW)Merge-on-read (MoR)
Update/deleteПерезапись затронутых файлов данных целикомЗапись маленьких delete files (position / equality)
Цена записиВысокаяНизкая
Цена чтенияНизкая (нет мёржа)Выше (мёрж данных + delete files)
Лучше дляRead-heavy, редкие обновленияПотоковые upsert / частый CDC

Delete file types (MoR): position deletes = "row X in file Y is gone"; equality deletes = "rows where id=123 are gone".

Типы delete files (MoR): position deletes = «строка X в файле Y удалена»; equality deletes = «строки, где id=123, удалены».

Compaction (rewrite_data_files) merges small files into ~128–512 MB files, applies MoR deletes, and can re-sort/cluster for tighter stats. It runs as its own atomic commit; readers keep using the old snapshot until it lands.

Компакция (rewrite_data_files) мержит мелкие файлы в ~128–512 MB файлы, применяет MoR-удаления, может пересортировать/кластеризовать для более точных статистик. Запускается как собственный атомарный коммит; читатели продолжают использовать старый снапшот, пока не приземлится.

Companion maintenance:Сопутствующее обслуживание: rewrite_manifests (compact metadata)(компакция метаданных), expire_snapshots, remove_orphan_files. Schedule them off the hot write path (e.g. Airflow).Запускать вне горячего write path (напр., Airflow).

Anchor — Amal "The small-files problem is one I know cold from Spark/Hive output — same pathology, and compaction is the same fix, now formalized as an Iceberg maintenance action."
Якорь — Amal «Проблему мелких файлов я знаю досконально по выводу Spark/Hive — та же патология, и компакция — то же самое лечение, теперь формализованное как действие обслуживания Iceberg.»

Iceberg vs Delta vs Hudi vs Hive

DimensionIcebergDelta LakeHudi
OriginNetflix → ApacheDatabricksUber → Apache
Metadata modelSnapshot tree (metadata → manifest list → manifests)Transaction log (_delta_log JSON + checkpoints)Timeline of commits + indexed file groups
Engine neutralityStrongest (Spark/Flink/Trino/Snowflake/BigQuery)Best on Spark/DatabricksSpark-centric (+Flink)
Partition evolutionNativeLimited (liquid clustering)Limited
Hidden partitioningYesNoNo
Update modelCoW + MoR (v2)CoW + deletion vectorsCoW & MoR first-class
Sweet spotMulti-engine, evolving large tablesSpark/Databricks BI+MLUpsert / CDC-heavy ingestion
ИзмерениеIcebergDelta LakeHudi
ПроисхождениеNetflix → ApacheDatabricksUber → Apache
Модель метаданныхДерево снапшотов (metadata → manifest list → manifests)Транзакционный лог (_delta_log JSON + checkpoints)Timeline коммитов + индексированные группы файлов
Нейтральность движковСильнейшая (Spark/Flink/Trino/Snowflake/BigQuery)Лучше на Spark/DatabricksSpark-центричный (+Flink)
Эволюция партицийВстроеннаяОграниченная (liquid clustering)Ограниченная
Скрытое партиционированиеДаНетНет
Модель обновленияCoW + MoR (v2)CoW + deletion vectorsCoW & MoR первого класса
Сильная сторонаМульти-движки, эволюционирующие большие таблицыSpark/Databricks BI+MLUpsert / тяжёлый CDC ingestion

One-liners: Iceberg for neutrality + clean evolution at scale. Delta if all-in on Spark/Databricks. Hudi for record-level upserts / incremental CDC.

Одной строкой: Iceberg для нейтральности + чистая эволюция на масштабе. Delta, если all-in на Spark/Databricks. Hudi для upsert на уровне записей / инкрементальный CDC.


Iceberg vs plain Hive tables — the concrete winsIceberg vs обычные таблицы Hive — конкретные победы

  • Atomic commits + snapshot isolation (Hive: none, dirty reads possible).
  • Metadata planning (Hive: expensive directory LIST).
  • Schema evolution by field ID (Hive: positional/name pitfalls).
  • Hidden partitioning + partition evolution (Hive: physical dirs, full rewrite to change).
  • Time travel + rollback (Hive: none).
  • Engine-neutral spec (Hive metastore is its own coupling).
  • Атомарные коммиты + изоляция снапшотами (Hive: нет, возможны грязные чтения).
  • Планирование по метаданным (Hive: дорогой LIST папок).
  • Эволюция схемы по field ID (Hive: подводные камни позиции/имени).
  • Скрытое партиционирование + эволюция партиций (Hive: физические папки, полная перезапись для изменения).
  • Time travel + rollback (Hive: нет).
  • Нейтральная к движкам спецификация (метастор Hive — собственная связанность).

File formats — Parquet / ORC / AvroФорматы файлов — Parquet / ORC / Avro

FormatLayoutBest forNotes
ParquetColumnarAnalytics (the default)Row groups → column chunks → pages; broadest ecosystem; rich nested types
ORCColumnarHive/Tez worldStripes + lightweight indexes + bloom filters; slightly better compression sometimes
AvroRow-basedStreaming / serializationIceberg uses it for its own manifest files; bad for wide scans
ФорматРаскладкаЛучше дляЗаметки
ParquetСтолбцовыйАналитика (по умолчанию)Row groups → column chunks → pages; широчайшая экосистема; богатые вложенные типы
ORCСтолбцовыйМир Hive/TezStripes + лёгкие индексы + bloom filters; иногда чуть лучше сжатие
AvroСтроковыйСтриминг / сериализацияIceberg использует его для собственных manifest files; плох для широких сканов

Columnar = read only needed columns, compress better (similar values adjacent), embed stats for pushdown. Columnar-vs-row (Parquet vs Avro) matters far more than Parquet-vs-ORC for analytics. For new Iceberg tables: Parquet is the safe default.

Столбцовый = читать только нужные столбцы, лучше сжимается (похожие значения рядом), встроенные статистики для pushdown. Столбцовый-vs-строковый (Parquet vs Avro) важнее, чем Parquet-vs-ORC, для аналитики. Для новых таблиц Iceberg: Parquet — безопасный дефолт.

Predicate pushdown end-to-endPredicate pushdown от конца до конца

predicate ─▶ partition prune (manifest list) ─▶ file prune (manifest min/max/nulls) ─▶ row-group skip (Parquet footer stats) ─▶ page skip / dictionary filter each layer reads strictly less than the one above
предикат ─▶ прунинг партиций (manifest list) ─▶ прунинг файлов (manifest min/max/nulls) ─▶ пропуск row-group (статистики футера Parquet) ─▶ пропуск страниц / фильтр словаря каждый слой читает строго меньше, чем верхний

Lakehouse architectureАрхитектура Lakehouse

Data lakeData warehouseLakehouse
StorageOpen files, object storeProprietary, coupledOpen files + table format on object store
ACID / schemaWeakStrongStrong
CostLowHighLow (lake economics)
Engine accessManyOne (vendor)Many, neutral
Risk"Data swamp"Lock-inNeeds maintenance discipline
Data lakeData warehouseLakehouse
ХранениеОткрытые файлы, объектное хранилищеПроприетарное, связанноеОткрытые файлы + табличный формат на объектном хранилище
ACID / схемаСлабыеСильныеСильные
СтоимостьНизкаяВысокаяНизкая (экономика озера)
Доступ движковМногоОдин (вендор)Много, нейтрально
Риск«Data swamp»ПривязкаНужна дисциплина обслуживания

Lakehouse = warehouse guarantees (ACID, schema, time travel) + lake economics + engine neutrality. One copy of data, many engines, no storage lock-in.

Lakehouse = гарантии хранилища (ACID, схема, time travel) + экономика озера + нейтральность движков. Одна копия данных, множество движков, нет привязки к хранилищу.

Reference pipeline (the design-round answer)Эталонный пайплайн (ответ на design-раунде)

Kafka ─▶ Flink (dedup/enrich, exactly-once via checkpoints↔commits) │ ▼ Flink Iceberg sink (MoR, hidden-partitioned by hours(event_time)) Iceberg tables on S3/GCS │ ▲ ├─▶ Trino/Presto interactive │ Airflow maintenance: ├─▶ Spark batch / dbt models │ rewrite_data_files (compaction) └─▶ Snowflake/BigQuery ext. │ expire_snapshots / rewrite_manifests │ remove_orphan_files
Kafka ─▶ Flink (дедуп/обогащение, exactly-once через checkpoints↔коммиты) │ ▼ Flink Iceberg sink (MoR, скрыто партиционирован по hours(event_time)) Таблицы Iceberg на S3/GCS │ ▲ ├─▶ Trino/Presto интерактив │ Обслуживание Airflow: ├─▶ Spark batch / dbt models │ rewrite_data_files (компакция) └─▶ Snowflake/BigQuery внеш. │ expire_snapshots / rewrite_manifests │ remove_orphan_files
Failure modes to volunteer Kafka lag → backpressure + scale consumers · duplicate delivery → idempotent keys + snapshot-level exactly-once · bad batch → rollback to prior snapshot · small files → compaction · late events → watermarks + late-tolerant partitioning.
Режимы сбоев (рассказать добровольно) Лаг Kafka → backpressure + масштабировать консьюмеры · дублированная доставка → идемпотентные ключи + exactly-once на уровне снапшота · плохой батч → rollback к предыдущему снапшоту · мелкие файлы → компакция · поздние события → watermarks + партиционирование, терпимое к опозданиям.
Anchor — Amal "I built Kafka ingestion at university scale (IU Group), a Scala/Spark pipeline on Hadoop (Front Tier), and migrated orchestration to Airflow (McMakler). This is the same shape — I'd land it in Iceberg with Flink exactly-once and scheduled compaction."
Якорь — Amal «Я строил Kafka ingestion в университетском масштабе (IU Group), Scala/Spark пайплайн на Hadoop (Front Tier), мигрировал оркестрацию на Airflow (McMakler). Это та же форма — я бы высадил это в Iceberg с Flink exactly-once и запланированной компакцией.»

Self-quiz — tap a card to flipСамопроверка — тап для переворота

Where does Iceberg's commit atomicity actually live?Где реально живёт атомарность коммита Iceberg?
tap to revealтап чтобы показать
answerответ
In the catalog's compare-and-swap on the metadata pointer — not in file renames. That's how it's atomic even on S3. В compare-and-swap каталога для указателя метаданных — не в переименованиях файлов. Поэтому атомарность есть даже на S3.
Why can Iceberg rename a column with no data rewrite?Почему Iceberg может переименовать столбец без перезаписи данных?
tap to revealтап чтобы показать
answerответ
Columns are tracked by a unique field ID, not name/position. Rename only changes the name→ID mapping; data files are untouched. Столбцы отслеживаются по уникальному field ID, а не по имени/позиции. Переименование меняет только маппинг имя→ID; файлы данных не трогаются.
CoW vs MoR — which is write-cheap, which is read-cheap?CoW vs MoR — что дёшево для записи, что для чтения?
tap to revealтап чтобы показать
answerответ
MoR = cheap writes (delete files), costlier reads (merge). CoW = cheap reads, costly writes (rewrite files). Compaction restores MoR read speed. MoR = дешёвая запись (delete files), дороже чтение (мёрж). CoW = дешёвое чтение, дорогая запись (перезапись файлов). Компакция восстанавливает скорость чтения MoR.
How does planning avoid listing millions of files?Как планирование избегает листинга миллионов файлов?
tap to revealтап чтобы показать
answerответ
Two-level metadata pruning: manifest-list partition ranges skip whole manifests, then manifest column stats (min/max/null) skip individual files. Then Parquet footers skip row groups. No LIST. Двухуровневый прунинг метаданных: диапазоны партиций manifest-list пропускают целые манифесты, затем статистики столбцов manifest (min/max/null) пропускают отдельные файлы. Затем футеры Parquet пропускают row groups. Никакого LIST.
What's hidden partitioning in one sentence?Что такое скрытое партиционирование одним предложением?
tap to revealтап чтобы показать
answerответ
You declare a transform (e.g. days(ts)); Iceberg stores the derived partition value so analysts query the raw column and still get pruning — no derived date column. Вы объявляете преобразование (напр., days(ts)); Iceberg сохраняет производное значение партиции, чтобы аналитики запрашивали исходный столбец и всё равно получали прунинг — никакого производного date-столбца.
When Iceberg vs Delta vs Hudi?Когда Iceberg vs Delta vs Hudi?
tap to revealтап чтобы показать
answerответ
Iceberg: engine-neutral, partition evolution, large evolving tables. Delta: Spark/Databricks shops. Hudi: upsert/CDC-heavy ingestion. Iceberg: нейтральность движков, эволюция партиций, большие эволюционирующие таблицы. Delta: магазины Spark/Databricks. Hudi: тяжёлый upsert/CDC ingestion.
Why doesn't a DELETE satisfy GDPR erasure on its own?Почему DELETE сам по себе не удовлетворяет требованиям стирания GDPR?
tap to revealтап чтобы показать
answerответ
Bytes persist in old snapshots. You must expire_snapshots + remove_orphan_files for true physical erasure. Байты выживают в старых снапшотах. Нужно expire_snapshots + remove_orphan_files для настоящего физического стирания.
Table format vs file format?Табличный формат vs формат файла?
tap to revealтап чтобы показать
answerответ
File format (Parquet) = bytes in one file. Table format (Iceberg) = many files → one transactional table (schema, snapshots, ACID). Формат файла (Parquet) = байты в одном файле. Табличный формат (Iceberg) = много файлов → одна транзакционная таблица (схема, снапшоты, ACID).

Operational gotchas — the depth probesОперационные подвохи — глубинные вопросы

  • No snapshot expiration → unbounded metadata + storage growth, slower planning. Schedule expire_snapshots.
  • No compaction on streaming tables → small-file explosion → slow reads.
  • Catalog choice matters — atomicity depends on the catalog's CAS; a naive file/HDFS catalog can break it under concurrency. Prefer REST/Glue/Nessie.
  • Wrong partition transform → tiny partitions or skew. Use bucket() for high-cardinality keys, days/hours for time.
  • MoR read amplification if delete files accumulate without compaction.
  • Orphan files after failed writes → remove_orphan_files (respect in-flight writers).
  • Field-ID reuse — drop-then-re-add a name = new ID; old data won't reappear.
  • Нет истечения снапшотов → неограниченный рост метаданных + хранилища, медленнее планирование. Запланировать expire_snapshots.
  • Нет компакции на потоковых таблицах → взрыв мелких файлов → медленное чтение.
  • Выбор каталога важен — атомарность зависит от CAS каталога; наивный file/HDFS каталог может сломать её при конкуренции. Предпочесть REST/Glue/Nessie.
  • Неправильное преобразование партиций → крошечные партиции или скос. Использовать bucket() для высококардинальных ключей, days/hours для времени.
  • Усиление чтения MoR, если delete files накапливаются без компакции.
  • Orphan files после упавших записей → remove_orphan_files (уважать активных писателей).
  • Переиспользование field-ID — удалить-потом-вернуть имя = новый ID; старые данные не всплывут.

Bonus depth: branching / write-audit-publishБонусная глубина: ветвление / write-audit-publish

Iceberg supports branches (independent snapshot lines) and tags (immutable snapshot refs). WAP: write to a branch → run DQ checks → fast-forward main. Tag a snapshot for reproducible ML training or audit.

Iceberg поддерживает ветки (независимые линии снапшотов) и теги (неизменяемые ссылки на снапшот). WAP: записать в ветку → запустить DQ-проверки → fast-forward main. Тегировать снапшот для воспроизводимого ML-обучения или аудита.

Anchor — Amal "WAP is the formalized version of my DQ-monitor + validate-against-loaders discipline at Meta — testing built into the commit lifecycle."
Якорь — Amal «WAP — это формализованная версия моей дисциплины DQ-мониторинга + валидации против загрузчиков в Meta — тестирование, встроенное в жизненный цикл коммита.»