Data Lakehouse: Apache Iceberg, Hudi & Parquet Internals
Architectural Paradigm: The Data Lakehouse brings ACID transactional semantics, snapshot isolation, schema evolution, and fine-grained pruning directly to low-cost, multi-petabyte object storage without requiring proprietary data warehouses.
1. The Lakehouse Evolution: Beyond the Hive Metastoreโ
Traditional Hive Object Lake Modern Lakehouse (Iceberg / Hudi)
+------------------------------------+ +------------------------------------+
| Hive Metastore (RDBMS) | | ACID Open Table Metadata Tree |
| - Tracks partitions by directories| | - Tracks individual data files |
| - S3 list operations: O(N) slow | | - Atomic snapshot commits via CAS |
| - Renames are non-atomic copies! | | - Time travel, branch, and merge |
+------------------------------------+ +------------------------------------+
Traditional data lakes relied on directory path conventions (e.g., s3://bucket/table/year=2026/month=09/). Because S3 lacks atomic directory renames and charges for LIST operations, large table scans suffered severe latency and corrupted writes during pipeline crashes.
2. Apache Iceberg: Hierarchical Metadata Architectureโ
Apache Iceberg tracks table state using an immutable, hierarchical tree of metadata files:
Apache Iceberg Metadata Hierarchy:
[ Catalog Pointer (REST / Nessie / DynamoDB) ]
โ
โผ References current table version
[ v3.metadata.json ]
โโโ Schema: [ id (1), timestamp (2), amount (3) ]
โโโ Partition Spec: identity(timestamp, "month")
โโโ Snapshot Log: Snapshot ID #84920491
โ
โผ
[ snap-84920491.avro (Manifest List) ]
โโโ Manifest File 1: Partition "month=2026-08" (Stats: min_id=1, max_id=5000)
โโโ Manifest File 2: Partition "month=2026-09" (Stats: min_id=5001, max_id=12000)
โ
โผ
[ manifest-file-2.avro (Manifest File) ]
โโโ data-file-01.parquet (Record count: 50,000, Column stats, Null counts)
โโโ data-file-02.parquet (Record count: 75,000, Column stats, Null counts)
โ
โผ
[ Actual Parquet Data Files in S3 / MinIO Object Storage ]
Core Iceberg Architectural Guaranteesโ
- Snapshot Isolation & Atomic Commits: Writers create a new snapshot without locking the table. Commits execute via Compare-And-Swap (CAS) on the catalog pointer. If an optimistic concurrency collision occurs, Iceberg retries cleanly.
- Hidden Partitioning: Users query
WHERE event_time >= '2026-09-01'without knowing whether data is physically partitioned by day, month, or hash. If the partition spec changes, historical files do not need rewriting! - Column ID Tracking: Columns are identified by stable internal integer IDs rather than names. Columns can be renamed, reordered, or deleted without corrupting legacy data files.
3. Apache Hudi: High-Velocity Upserts & Streaming Ingestionโ
While Iceberg excels at general batch and analytical querying, Apache Hudi is designed for high-frequency streaming ingestion and row-level upserts:
+-----------------------------------+-----------------------------------+
| Copy-On-Write (COW) Tables | Merge-On-Read (MOR) Tables |
+-----------------------------------+-----------------------------------+
| Writes rewrite existing Parquet | Writes append updates to compact |
| files with updated records. | row-based Avro delta logs (.log). |
| Highest query scan performance. | Lowest ingestion write latency. |
| High write amplification. | Background Compaction merges logs |
| Best for: Read-heavy BI reporting | Best for: Real-time Kafka streams |
+-----------------------------------+-----------------------------------+
Hudi Pluggable Indexingโ
To avoid scanning the entire table on every upsert, Hudi utilizes high-speed indexes:
- Bloom Filter Index: Pre-checks whether an incoming record key exists in a specific Parquet file.
- Record-Level Index (RLI): Uses an internal metadata table to map record keys directly to file IDs in sub-millisecond lookups.
4. Apache Parquet File Format Internalsโ
Apache Parquet is an open-source, columnar storage format optimized for vectorized execution (SIMD):
Parquet Physical File Layout:
+-------------------------------------------------------------+
| 4-Byte Magic Header ("PAR1") |
+-------------------------------------------------------------+
| Row Group 0 (128 MB - 512 MB chunk of table rows) |
| โโโ Column Chunk 0 (User ID column: Snappy/Zstd compressed)|
| โ โโโ Data Page 0 (Dictionary Header + Bit-Packed Values|
| โ โโโ Data Page 1 |
| โโโ Column Chunk 1 (Timestamp column: Delta encoded) |
| โโโ Column Chunk N |
+-------------------------------------------------------------+
| Row Group 1 |
+-------------------------------------------------------------+
| File Footer (Thrift Metadata: Schema, Column Min/Max Stats) |
+-------------------------------------------------------------+
| 4-Byte Footer Length + 4-Byte Magic ("PAR1") |
+-------------------------------------------------------------+
1. Dremel Encoding: Definition & Repetition Levelsโ
To store arbitrary nested JSON/protobuf data efficiently without storing null pointers, Parquet implements Google's Dremel algorithm:
- Definition Level (DL): Encodes how many optional ancestors in the path are defined (handles NULL values with minimal bits).
- Repetition Level (RL): Encodes at what depth level in the schema tree a list value repeats.
2. Columnar Encoding Schemesโ
- Dictionary Encoding: Replaces repetitive text strings (e.g. state names
"CA","NY") with 1-byte integer dictionary keys. - Run-Length Encoding (RLE) & Bit-Packing: Compresses consecutive repeated integers (
1, 1, 1, 1, 2, 2(4, 1), (2, 2)). - Delta Binary Encoding: Compresses timestamps and monotonically increasing IDs by storing only the differences (deltas) between consecutive values.
3. Vectorized Engine Dictionary & Min/Max Pruningโ
When an engine (Trino, ClickHouse, DuckDB) reads Parquet files from S3:
- It downloads only the small Thrift footer to read Row Group min/max statistics.
- If
query: WHERE age > 65and Row Group 0 reportsmax_age = 42, the engine skips downloading that 256 MB Row Group entirely! - Remaining columns are decoded directly into CPU L1/L2 caches using vectorized SIMD registers.