Learning Platform
Глоссарий Troubleshooting
Урок 19.03 · 45 мин
Продвинутый
StorageParquetORCDelta LakeIcebergHudiEncodingCompressionPartitioningLakehouse

Проектирование Storage Layer

Второй deliverable — выбор форматов хранения для каждого слоя. Это ядро capstone-проекта: здесь сходятся знания из 14 модулей. Каждое решение должно быть привязано к workload и обосновано ссылкой на конкретный материал курса.

Архитектура из обзора проекта: три слоя (bronze → silver → gold), каждый с разным workload:

Workloads по слоям

Bronze

Bronze layer workload: write-heavy, append-only. 10K events/sec steady → файлы каждые 30 сек. Никогда не обновляется. Основная операция: append. Чтение: редко (reprocessing, debugging). Schema evolution: частая (upstream DDL changes).
Workload: Streaming/CDCАрхетип из Модуля 17: streaming ingestion. Ключевые метрики: write throughput, compression ratio (storage cost), schema evolution support. Read performance — вторична (bronze читается только при reprocessing).

Silver

Silver layer workload: merge-heavy. SCD Type 2, upserts, deduplication. Каждый batch: read existing + merge new → write updated. Balance между read и write performance. Schema стабильная (мы контролируем silver schema).
Workload: Mixed R/WАрхетип: OLTP-like с аналитическим уклоном. Ключевые метрики: merge latency (upsert speed), read for merge (point lookup by PK), write throughput (after merge). CoW vs MoR — критичный выбор.

Gold

Gold layer workload: read-heavy. Pre-aggregated materialized views. Обновление: раз в час или реже. Чтение: постоянное (BI, ML, ad-hoc). Оптимизация: scan speed, predicate pushdown, partition pruning.
Workload: OLAP/AnalyticsАрхетип из Модуля 17: OLAP analytics. Ключевые метрики: scan speed, predicate pushdown effectiveness, compression ratio (storage cost). Write performance не критична — обновление редкое и batch.

File Format: Parquet vs ORC

Первый выбор — columnar file format. Для нашего сценария два реалистичных кандидата: Parquet и ORC.

File Format Decision per Layer

Bronze: File Format

Bronze: append-only, write throughput важен. Parquet: row group model позволяет streaming write (flush per row group). ORC: stripe model аналогичен. Разница: Parquet row groups чуть проще для append (нет ORC stripe footer с bloom filters). Но разница минимальна.
Рекомендация: ParquetParquet для bronze: (1) нативная поддержка всеми table formats (Delta, Iceberg, Hudi). (2) Spark write path оптимизирован для Parquet. (3) Schema embedding в footer — полезно для debugging raw data. (4) Нет overhead от ORC bloom filters / indexes на write.

Silver: File Format

Silver: merge-heavy. Для merge нужно: (1) быстрый lookup по PK (для matching existing rows), (2) эффективный write обновлённых файлов. Parquet: нет нативных bloom filters (добавлены в v2, но не все engines поддерживают). ORC: нативные bloom filters, row-level indexes.
Рекомендация: ParquetParquet и для silver: (1) Table format (Iceberg/Delta) берёт на себя metadata management, компенсируя отсутствие нативных bloom filters. (2) Iceberg manifest files + partition pruning = эффективный lookup. (3) Единый file format bronze/silver упрощает операции.

Gold: File Format

Gold: read-heavy analytics. Columnar scan speed — ключевая метрика. Parquet и ORC оба columnar, но: Parquet page-level statistics → column chunk pruning. ORC stripe-level statistics + bloom filters → более точный pruning при point queries.
Рекомендация: ParquetParquet для gold: (1) Trino/DuckDB/Spark — все оптимизированы под Parquet vectorized reads. (2) Page-level column statistics достаточны для analytics scan (min/max pruning). (3) Единый file format на все слои — operational simplicity перевешивает marginal ORC advantage в bloom filters.
WARNING

Мы выбираем Parquet для всех трёх слоёв. Это не “один формат на всё” — ошибка из обзора. Parquet — единый file format, но encoding, compression, row group size, sort order различаются по слоям. Дифференциация — на уровне настроек, а не формата.

Table Format: Delta Lake vs Iceberg vs Hudi

Table format — это метаданные и ACID поверх файлов. Три кандидата: Delta Lake, Iceberg, Hudi.

Table Format Comparison для capstone

Delta Lake

Delta Lake: log-based transaction protocol. Commit log в _delta_log/. Checkpoint каждые 10 коммитов. ACID через optimistic concurrency. Tight integration с Spark (от Databricks). Open-source + managed (Databricks).
Преимущества(1) Spark integration — нативная, zero-config. (2) MERGE command — один statement для upsert. (3) Change Data Feed — CDC из Delta (полезно для silver → gold). (4) OPTIMIZE + Z-ORDER — встроенная compaction. (5) Vacuum — автоочистка.
Недостатки(1) Vendor lock: максимальный feature set — только на Databricks. Open-source Delta — subset. (2) Catalog: Unity Catalog (Databricks) vs Hive Metastore (oss). (3) Multi-engine: Trino/Flink support улучшился, но не native. (4) Partition evolution: нет (schema evolution — да, partition — нет).

Apache Iceberg

Apache Iceberg: tree-based metadata. Manifest list → manifest files → data files. Snapshot isolation. Engine-agnostic by design. Open governance (Apache Foundation). Adopted by Netflix, Apple, AWS.
Преимущества(1) Engine-agnostic: Spark, Trino, Flink, DuckDB — все first-class. (2) Partition evolution: меняйте partitioning без rewrite. (3) Hidden partitioning: partition transform в metadata, не в path. (4) Schema evolution: safe, tracked. (5) Open governance: Apache, не vendor.
Недостатки(1) MERGE: поддерживается, но не так оптимизирован как Delta на Spark (Copy-on-Write по умолчанию). (2) Нет built-in Change Data Feed (row-level deltas через incremental reads). (3) Compaction: external (Spark/Flink jobs), не built-in command. (4) Operational tooling менее зрелое чем Delta.

Apache Hudi

Apache Hudi: record-level index для fast upsert. MoR (Merge-on-Read) — default. Log files для real-time updates. Optimized для streaming ingestion + CDC. Uber-originated.
Преимущества(1) Record-level index: fast upsert без full-file rewrite. (2) MoR native: real-time view (log + base) + read-optimized view (compacted). (3) Incremental queries: built-in CDC-like capability. (4) Streaming ingestion: DeltaStreamer — purpose-built consumer.
Недостатки(1) Complexity: MoR + log files + compaction — больше moving parts. (2) Multi-engine: Spark primary, Trino/Flink — second-class. (3) Community: меньше чем Delta/Iceberg. (4) Operational overhead: inline compaction, cleaning, clustering — требуют tuning.

Рекомендация: Iceberg

Decision: Apache Iceberg для capstone

Решение: Apache Iceberg

Apache Iceberg — рекомендация для capstone-платформы. Engine-agnostic design позволяет использовать Spark для ETL, Trino для ad-hoc, DuckDB для local analytics — без vendor lock. Partition evolution — critical для evolving data platform.
Multi-EngineНаш сценарий использует Spark (ETL), Trino (ad-hoc SQL), DuckDB (local analytics), Flink (streaming). Iceberg — единственный table format с first-class support для всех четырёх engines. Delta — Spark primary. Hudi — Spark primary.
Partition EvolutionE-commerce платформа растёт. Сегодня партиционирование по date достаточно. Через год — может понадобиться по date + region. Iceberg: ALTER TABLE ... SET PARTITION → без rewrite. Delta/Hudi: полный rewrite данных.
Hidden PartitioningIceberg hidden partitioning: пользователь пишет WHERE order_date = '2024-01-15', Iceberg автоматически pruning по partition transform (days(order_date)). Нет ошибок из-за неправильного partition filter. Delta: пользователь должен знать partition layout.
Open GovernanceApache Foundation governance = никакой vendor не контролирует roadmap. Delta — Databricks driven (хотя open source). Hudi — AWS/Uber influenced. Для компании, которая не хочет vendor lock — Iceberg наиболее neutral.
TIP

Hudi мог бы быть лучшим выбором если бы наш primary workload был high-frequency upsert (тысячи upserts/sec на одной таблице). Record-level index Hudi оптимизирован именно для этого. Но наш silver layer — batch merge раз в 30 сек, что Iceberg обрабатывает достаточно эффективно. См. Hudi index types для details.

Encoding Strategy per Layer

Encoding — как значения закодированы внутри column chunks. Выбор зависит от типа данных и access pattern:

Encoding Strategy

Bronze: Default

Bronze encoding: default Parquet encoding. Spark writer автоматически выбирает: PLAIN для strings с высокой кардинальностью, DICTIONARY для low-cardinality, DELTA_BINARY_PACKED для integers. Не оптимизируем вручную — bronze write speed важнее.
СтратегияМинимальная настройка: Spark default Parquet writer делает разумные автоматические выборы. Dictionary encoding включается автоматически для колонок с кардинальностью < парога (default: 200 distinct values per page). Manual tuning не оправдан — bronze write throughput важнее read optimization.

Silver: Targeted

Silver encoding: более аккуратное. Знаем schema, знаем кардинальность. Словарные кодировки для status, region, category. Delta encoding для timestamps. RLE для sorted columns.
СтратегияExplicit encoding per column type: (1) status/region/category → DICTIONARY (кардинальность < 100, [Модуль 08](/storage-formats/08-encoding/02-dictionary-encoding/)). (2) timestamps → DELTA_BINARY_PACKED ([Модуль 08](/storage-formats/08-encoding/03-integer-encodings/)). (3) prices → PLAIN (floating point, dictionary не эффективен). (4) IDs → DELTA_BINARY_PACKED.

Gold: Optimized

Gold encoding: максимальная оптимизация для read. Pre-aggregated данные: много integers (counts, sums), low-cardinality dimensions. Dictionary + RLE on sorted columns = максимальная compression + scan speed.
СтратегияAggressive optimization: (1) Sorted по primary dimension (date, region) → RLE encoding для sorted column ([Модуль 08](/storage-formats/08-encoding/04-string-encodings/)). (2) Dictionary для всех categorical. (3) DELTA для metrics (counts, sums — monotonic). (4) Smaller row group size для point queries (от аналитиков, конкретный region + date).
NOTE

Подробный разбор каждого encoding — в Модуле 08. Здесь мы применяем эти знания к конкретным колонкам нашей платформы. Ключевое правило: encoding выбирается по кардинальности и типу данных, а не по слою.

Compression Strategy per Layer

Compression — последний уровень оптимизации. Trade-off: compression ratio vs CPU overhead:

Compression per Layer

Bronze: Snappy

Bronze: balance между write speed и storage cost. Snappy: быстрый (fast compress + decompress), moderate ratio (~2-3x). Zstd: лучше ratio (~4-5x), но медленнее compress. Для streaming ingestion — Snappy safe default.
ОбоснованиеWrite throughput = приоритет. Snappy: compress ~500 MB/s, decompress ~1500 MB/s. Zstd level 1: compress ~400 MB/s, decompress ~1200 MB/s. Разница 20-25% на write — при 10K events/sec это matters. Storage cost: Snappy ~2.5x vs Zstd ~4x — но bronze retention 3 года, archive to cheaper storage tier.

Silver: Zstd (level 3)

Silver: balance. Merge операции = read + write. Zstd level 3 — золотая середина: лучше ratio чем Snappy при сопоставимой decompress speed. Compress медленнее, но silver write = batch (не streaming).
ОбоснованиеSilver merge: read existing files (decompress) + write new files (compress). Zstd level 3: decompress ~1200 MB/s (close to Snappy), compress ~200 MB/s (2.5x slower), ratio ~4x (1.5x better). Batch merge каждые 30 сек — compress speed менее критична. Better ratio = fewer files = faster future reads.

Gold: Zstd (level 6)

Gold: read-optimized. Zstd level 6+: максимальная compression ratio, decompress всё ещё быстрый (~1000 MB/s). Gold обновляется редко (раз в час) — compress speed не важна. Меньше данных = быстрее scan = лучше BI response time.
ОбоснованиеGold = read-heavy. Zstd level 6: decompress ~1000 MB/s, compress ~100 MB/s (медленно, но gold обновляется раз в час), ratio ~5x. Меньше данных на диске = меньше I/O = быстрее scan. BI SLA (p95 < 5s) → каждый байт уменьшения помогает. См. [compression tuning](/storage-formats/09-compression/02-compression-tuning/).
TIP

Подробный разбор trade-offs Snappy vs Zstd vs LZ4 — в Модуле 09, Урок 02. Для capstone: Snappy для write-heavy, Zstd с возрастающим level для read-heavy — стандартный паттерн в production data platforms.

Partitioning и Sort Order

Partitioning определяет directory layout. Sort order определяет порядок строк внутри файлов. Оба влияют на query performance:

Partitioning Strategy

Bronze: ingestion_date

Bronze partitioning: по ingestion_date. Простая, предсказуемая. Каждый день — отдельная партиция. ~500 GB/день → manageable size. Partition pruning: queries по дате отсекают 99%+ данных.
Layouts3://lakehouse/bronze/orders/ingestion_date=2024-01-15/. Iceberg hidden partitioning: days(ingestion_timestamp) → partition transform. Пользователь пишет WHERE ingestion_timestamp > '2024-01-15', Iceberg автоматически pruning.

Silver: order_date, region

Silver partitioning: по order_date + region (для orders таблицы). Двойная партиция: аналитики фильтруют по date (всегда) и часто по region. Iceberg partition evolution позволяет добавить region позже без rewrite.
LayoutIceberg partition spec: days(order_date), identity(region). Hidden partitioning — пользователь не знает layout. Sort within partition: по user_id (для merge joins). Partition evolution: начать с days(order_date), добавить region через ALTER TABLE.

Gold: report_date

Gold partitioning: по report_date. Одна партиция = один batch rebuild. Sort order: по primary dimension (region, category). Z-ordering для multi-dimensional queries если engine поддерживает (Iceberg v2 sort order).
LayoutGold таблицы pre-aggregated: одна партиция per day. Sort order: region, category (most common GROUP BY columns). Sorted data + dictionary encoding = RLE compression → минимальный размер. Iceberg sort order spec в table metadata.

CoW vs MoR для Silver Layer

Ключевое решение для silver layer: Copy-on-Write vs Merge-on-Read:

CoW vs MoR для Silver Merge

Copy-on-Write (CoW)

Copy-on-Write: каждый merge перезаписывает весь affected file. Новая версия файла содержит merged результат. Старая версия — garbage collected. Read: всегда быстрый (файлы уже merged). Write: медленный (full file rewrite).
Для нашего silverCoW подходит если: (1) merge batch size умеренный (300K events / 30 sec = manageable), (2) read performance важнее write (downstream gold layer и аналитики читают silver часто), (3) simplicity — нет log files, нет compaction scheduling.

Merge-on-Read (MoR)

Merge-on-Read: write записывает delta files (только изменения). Read: merge на лету (base + deltas). Периодическая compaction объединяет deltas в base. Write: быстрый. Read: медленнее (merge overhead). Complexity: выше.
Для нашего silverMoR подходит если: (1) write throughput критичен (high-frequency upsert), (2) read допускает overhead (merge на лету), (3) есть ресурсы на compaction scheduling. Для нашего batch merge каждые 30 сек — MoR overhead не оправдан.

Рекомендация: CoW для silver layer:

  • Merge batch: ~300K events / 30 sec — CoW file rewrite manageable
  • Downstream reads (gold rebuild, analytics) — всегда быстрые
  • Operational simplicity — нет compaction jobs
  • Iceberg CoW merge: MERGE INTO silver USING staging ON silver.id = staging.id ...
NOTE

Если бы наш merge был high-frequency (continuous per-record, а не micro-batch), MoR был бы обязателен. Hudi MoR с record-level index — оптимальный для этого сценария. Но наш batch merge каждые 30 сек — CoW territory. Подробнее: CoW vs MoR, Hudi MoR.

Row Group и Target File Size

Последний уровень настроек — физический размер файлов и row groups:

File и Row Group Sizing
BronzeTarget file size: 128 MB (Spark default). Row group size: 128 MB (match file size — один row group per file для streaming writes). Rationale: streaming append создаёт файлы каждые 30 сек. При 300K events × ~500 bytes = ~150 MB — close to target.
SilverTarget file size: 256 MB. Row group size: 128 MB (2 row groups per file). Rationale: merge rewrite создаёт файлы из merged results. Larger files = fewer files = faster metadata operations. Two row groups — balance между scan granularity и metadata overhead.
GoldTarget file size: 512 MB. Row group size: 64 MB (8 row groups per file). Rationale: gold tables pre-aggregated — fewer rows per file, but important to have multiple row groups for column statistics pruning. Smaller row groups = more precise min/max statistics = better predicate pushdown.

Сводка решений

Storage Layer Design — полная сводка
ПараметрСтроки таблицы: параметры storage layer. Колонки: значения для каждого слоя (bronze, silver, gold). Каждое решение привязано к workload и обосновано материалом курса.
BronzeBronze: write-optimized. Append-only ingestion. Schema evolution частая. Read — только для reprocessing.
SilverSilver: merge-optimized. CoW upsert каждые 30 сек. Read для gold rebuild и аналитики.
GoldGold: read-optimized. Pre-aggregated materialized views. BI SLA p95 < 5 сек.
File FormatParquet для всех слоёв. Universal engine support (Spark, Trino, DuckDB, Flink). Дифференциация через encoding/compression settings.
ParquetBronze Parquet: streaming append, default encoding. [Модуль 02](/storage-formats/02-parquet/01-row-groups/).
ParquetSilver Parquet: CoW merge rewrite. Dictionary encoding для categorical. [Модуль 02](/storage-formats/02-parquet/01-row-groups/).
ParquetGold Parquet: read-optimized, sorted, aggressive compression. [Модуль 02](/storage-formats/02-parquet/01-row-groups/).
Table FormatIceberg для всех слоёв. Partition evolution, hidden partitioning, engine-agnostic. [Модуль 12](/storage-formats/12-iceberg/01-catalog-architecture-metadata/).
IcebergBronze Iceberg: append-only, schema evolution tracked в metadata. Partition by days(ingestion_timestamp).
IcebergSilver Iceberg: CoW merge, partition evolution ready. Sort order by user_id within partition.
IcebergGold Iceberg: read-optimized, sort order by dimensions (region, category). Partition by days(report_date).
CompressionSnappy → Zstd progression. Write-heavy: fast compress. Read-heavy: high ratio. [Модуль 09](/storage-formats/09-compression/01-compression-internals/).
SnappyBronze Snappy: ~500 MB/s compress, ~2.5x ratio. Priority: write throughput.
Zstd 3Silver Zstd 3: ~200 MB/s compress, ~4x ratio. Balance read/write.
Zstd 6Gold Zstd 6: ~100 MB/s compress, ~5x ratio. Priority: read speed + storage.
Row GroupRow group size varies: larger for streaming (fewer file operations), smaller for analytics (better statistics). [Модуль 02, урок 02](/storage-formats/02-parquet/02-column-chunks/).
128 MBBronze 128 MB: one row group per file. Match Spark default. Simple for streaming append.
128 MBSilver 128 MB: two row groups per 256 MB file. Balance scan granularity and metadata.
64 MBGold 64 MB: eight row groups per 512 MB file. Better statistics for predicate pushdown.

Упражнение: ваш Storage Layer Design

Ваша задача — описать storage layer для capstone-платформы. Наши рекомендации выше — один из возможных вариантов. Вы можете согласиться, модифицировать, или предложить полностью другую архитектуру. Ключ — обоснование:

Checklist: Storage Design
1. File FormatОдин file format на все слои или разные? Parquet или ORC? Почему? Ссылки на [Модуль 02](/storage-formats/02-parquet/01-row-groups/) и [Модуль 03](/storage-formats/03-orc/01-stripes/).
2. Table FormatОдин table format или разные? Delta/Iceberg/Hudi? Какой CoW/MoR для silver? Ссылки на [M11-M14](/storage-formats/11-delta-lake/01-transaction-log-architecture/).
3. EncodingEncoding strategy per column type. Dictionary для чего? Delta для чего? RLE? Ссылки на [Модуль 08](/storage-formats/08-encoding/01-information-theory/).
4. CompressionCodec per layer. Snappy vs Zstd vs LZ4? Level? Ссылки на [Модуль 09](/storage-formats/09-compression/01-compression-internals/).
5. PartitioningPartition columns per layer. Partition evolution plan? Sort order? Ссылки на [Iceberg partitioning](/storage-formats/12-iceberg/03-hidden-partitioning-evolution/).
6. OperationsCompaction strategy? Vacuum/expire snapshots? Monitoring? Ссылки на [migration strategies](/storage-formats/17-practical-choice/04-migration-strategies/).
WARNING

Обоснование — не формальность. “Parquet because it’s popular” — не обоснование. “Parquet для bronze потому что: (1) Iceberg нативно работает с Parquet (Модуль 12), (2) Spark Structured Streaming write path оптимизирован для Parquet, (3) streaming append не использует ORC advantages (bloom filters, indexes)” — обоснование.

В следующем уроке вы проверите свои решения на практике: запустите Docker lab, соберёте бенчмарки, и сравните результаты с ожиданиями.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Lakehouse архитектура: bronze (raw CDC) → silver (curated) → gold (aggregated). Почему bronze, silver и gold слои требуют разных format optimizations?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4