Apache Iceberg Chapter 1: lakehouse không phải tự nhiên sinh ra thêm một lớp mới

Apache Iceberg Chapter 1: lakehouse không phải tự nhiên sinh ra thêm một lớp mới

Chapter 1 của Apache Iceberg: The Definitive Guide đi từ data warehouse → data lake → data lakehouse, rồi dùng Hive và Iceberg để giải thích vì sao lakehouse cần một lớp table format riêng.

Điểm mình muốn giữ lại: warehouse, lake, lakehouse không phải ba thế giới hoàn toàn khác nhau. Về cơ bản chúng đều cần storage, file/table layout, catalog, metadata, statistics, transaction/snapshot state và compute engine để biến bytes thành table có thể query. Khác nhau chủ yếu là các thành phần đó được đóng gói chung hay tách ra thành các lớp mở.

Warehouse: mọi thứ nằm trong một hệ thống thống nhất

Trong bản dịch:

Data warehouse sở hữu tất cả các thành phần kỹ thuật trong một hệ thống duy nhất. Nói cách khác, toàn bộ dữ liệu được lưu trữ bằng các file format và table format độc quyền của nó trên storage system độc quyền của chính nó. Sau đó, dữ liệu này được quản lý hoàn toàn bởi storage engine của data warehouse, được đăng ký trong catalog của nó, và chỉ người dùng hoặc các analytical engine mới có thể truy cập dữ liệu thông qua compute engine của data warehouse.

Đây là đoạn quan trọng vì nó nói thẳng: warehouse cũng có file format, table format, storage engine, catalog, compute engine. Chỉ là các thành phần đó nằm bên trong một product boundary.

Data warehouse
  storage system nội bộ
  file format nội bộ
  table format / metadata nội bộ
  storage engine
  catalog
  compute engine

User không cần biết table format nội bộ của warehouse là gì. Khi query:

SELECT * FROM orders
WHERE order_date >= '2024-01-01'

warehouse tự xử lý table metadata, statistics, transaction state, optimizer, pruning, recovery… bên trong black box của nó.

Nên khi nói Iceberg là table format, không có nghĩa warehouse trước đó “không có table format”. Warehouse có, nhưng không mở nó ra như một shared contract cho nhiều engine bên ngoài cùng dùng.

Data lake: mở storage và file format ra, nhưng mất nhiều semantics

Data lake xuất hiện vì warehouse có một số giới hạn:

Data warehouse chỉ có thể lưu trữ dữ liệu có cấu trúc. Storage trong data warehouse nhìn chung đắt hơn cluster Hadoop on-premises hoặc cloud object storage. Storage và compute trong data warehouse on-premises truyền thống thường được kết hợp với nhau, do đó không thể được mở rộng riêng biệt.

Data lake kéo storage ra ngoài:

HDFS / object storage
  + open file formats như Parquet, ORC, Avro
  + nhiều compute engines cùng đọc

Điểm mạnh:

  • storage rẻ hơn;
  • lưu được nhiều loại dữ liệu hơn;
  • storage/compute có thể tách rời hơn;
  • open file formats giúp nhiều engines cùng đọc được dữ liệu.

Nhưng nếu chỉ có object storage + file format thì vẫn thiếu một lớp trả lời câu hỏi ở cấp table:

Table hiện tại gồm những file nào?
File nào là current, file nào là historical?
Commit nào vừa thêm/xóa file nào?
Schema hiện tại là gì?
Partition spec nào áp dụng cho file nào?
Query muốn đọc snapshot cũ thì trỏ tới đâu?

Parquet rất mạnh ở cấp file, nhưng Parquet không phải table-level contract.

file format:
  inside one file
  rows, columns, encoding, compression, row groups, file-level stats

table format:
  across many files
  snapshots, manifests, schema, partition specs, commits, table-level metadata

Lakehouse: giữ open storage, thêm lại warehouse-like semantics

Bản dịch mô tả data lakehouse như nỗ lực dung hòa hai phía:

Trong khi việc sử dụng data warehouse đem lại cho chúng ta hiệu năng và sự dễ dùng, analytics trên data lake lại đem đến chi phí thấp hơn, sự linh hoạt nhờ sử dụng open format, khả năng dùng dữ liệu phi cấu trúc, và nhiều lợi ích khác. Mong muốn dung hòa hai phía này dẫn đến những bước tiến và đổi mới lớn, từ đó tạo ra thứ mà ngày nay chúng ta gọi là data lakehouse.

Và đoạn quan trọng nhất:

Table format tạo ra một abstraction layer nằm trên file storage, cho phép consistency, performance và ACID guarantee tốt hơn khi làm việc trực tiếp với dữ liệu trên data lake storage.

Mình hiểu đoạn này như sau:

Warehouse:
  one closed system owns everything

Data lake:
  storage + file format được mở ra
  nhưng table-level semantics yếu hơn

Lakehouse:
  giữ open storage/file format
  thêm open table format + metadata/snapshot/transaction layer

Lakehouse không phải phủ nhận warehouse. Nó là thử nghiệm tách những năng lực cốt lõi của warehouse thành các open components có thể chạy trên data lake.

Hive: bước trung gian quan trọng

Hive ra đời để làm analytics trên Hadoop dễ hơn. Thay vì viết MapReduce Java job trực tiếp, user có thể viết SQL.

Từ bản dịch:

Hive framework sẽ nhận các câu lệnh SQL rồi chuyển đổi chúng thành MapReduce job có thể được thực thi. Để viết câu lệnh SQL, cần có một cơ chế để hiểu dữ liệu nào trên Hadoop storage của bạn đại diện cho một bảng duy nhất, và Hive table format cùng Hive Metastore để theo dõi các bảng này đã ra đời.

Hive giải bài toán rất thực tế:

file trên Hadoop/object storage
  → Hive table format + Hive Metastore
  → SQL table abstraction

Hive table format định nghĩa table bằng location/directory:

Hive table format chọn cách định nghĩa một bảng là tất cả các file nằm trong một thư mục được chỉ định — hoặc các prefix đối với object storage. Các partition của những bảng đó sẽ là các thư mục con.

Mental model:

Hive table
  location: /table/
  partition: /table/event_year=2024/event_month=01/event_day=15/
  files: *.parquet / *.orc / *.csv

Đây là một thiết kế hợp lý ở thời điểm đó. Nó:

  • cho phép SQL trên Hadoop;
  • hỗ trợ partitioning/bucketing để tránh full scan;
  • file format agnostic, nên có thể dùng Parquet/Avro/CSV/TSV;
  • dùng Hive Metastore làm điểm thống nhất để nhiều tools tìm dữ liệu;
  • trở thành de facto standard cho câu hỏi “dữ liệu nào nằm trong bảng này?”.

Nhưng Hive table format có vấn đề gì?

Vấn đề gốc: Hive định nghĩa table dựa trên directory và subdirectory, không phải từng data file như một entity có metadata rõ ràng.

Bản dịch nói rất rõ:

Netflix ... kết luận rằng nhiều vấn đề của Hive format bắt nguồn từ một khiếm khuyết đơn giản nhưng nền tảng: mỗi bảng được theo dõi dưới dạng directory và subdirectory, giới hạn độ granular cần thiết để cung cấp consistency guarantee, concurrency tốt hơn, và một số tính năng thường có trong data warehouse.

1. File-level change không hiệu quả

Các thay đổi ở file level không hiệu quả, vì không có cơ chế để atomically swap một file theo cùng cách Hive Metastore có thể được dùng để swap một partition directory.

Hive có thể atomic swap ở partition directory, nhưng nếu chỉ muốn thay một file/record nhỏ hơn thì granularity không đủ tốt.

Hive atomic unit dễ làm hơn:
  partition directory

Cần granular hơn:
  data file / set of data files / snapshot

2. Multi-partition update không atomic

Mặc dù bạn có thể atomically swap một partition, không có cơ chế để atomically update nhiều partition như một transaction duy nhất.

Nếu job update nhiều partition:

partition A updated
partition B chưa updated
partition C đang dở

reader có thể thấy table ở trạng thái nửa cũ nửa mới.

Đó là lý do Iceberg đặt mục tiêu Consistency:

End user nhìn thấy dữ liệu hoặc trước update, hoặc sau update, chứ không phải ở trạng thái ở giữa.

3. Concurrent update khó an toàn

Thực sự không có các cơ chế tốt để cho phép các concurrent simultaneous update, đặc biệt là với những công cụ ngoài chính Hive.

Khi nhiều engines cùng ghi, cần biết writer nào dựa trên table version nào, commit nào thắng, conflict nào cần fail/retry. Nếu table chỉ là folder/files thì thiếu một commit contract đủ mạnh.

4. File/directory listing làm query planning chậm

Việc một engine list file và directory tốn thời gian và làm chậm truy vấn. Phải đọc và list các file và directory có thể không cần scan trong truy vấn kết quả là một việc có chi phí.

Ở scale lớn, query có thể tốn thời gian chỉ để biết cần scan file nào.

Iceberg đặt mục tiêu Performance:

Table nên cung cấp metadata và tránh việc list file quá mức, để query planning không chỉ có thể trở thành một quá trình nhanh hơn, mà các plan kết quả cũng có thể được thực thi nhanh hơn vì chúng chỉ scan những file cần thiết để đáp ứng query.

5. Partition layout bị leak lên user query

Partition column thường được derive từ các column khác, chẳng hạn như derive một column tháng từ timestamp. Partitioning chỉ hữu ích nếu bạn filter theo partition column, và một người có filter trên timestamp column có thể không trực giác biết rằng cũng cần filter trên derived month column, dẫn đến full table scan vì partitioning không được tận dụng.

Ví dụ user query tự nhiên:

WHERE event_timestamp >= DATE_SUB(CURRENT_DATE, INTERVAL 90 DAY)

Nhưng Hive layout có thể cần:

WHERE event_year = 2024
  AND event_month >= 10

Tức là physical partition layout leak lên logical query.

6. Table statistics dễ stale hoặc thiếu

Table statistic thường được thu thập thông qua các job bất đồng bộ, thường dẫn đến stale table statistic, nếu có statistic nào. Điều này khiến query engine khó tối ưu truy vấn hơn nữa.

Nếu stats không nằm trong metadata flow chính của table, optimizer không có đủ thông tin đáng tin cậy để prune/plan tốt.

7. Object storage prefix bottleneck

Vì object storage thường throttle request đối với cùng một prefix ... các truy vấn trên bảng có số lượng file lớn trong một partition duy nhất ... có thể gặp vấn đề về hiệu năng.

Hive-style partition directory/prefix có thể tạo hotspot khi quá nhiều file nằm trong cùng prefix.

Modern table format giải quyết bằng cách đổi định nghĩa “table là gì”

Bản dịch của section Modern Data Lake Table Formats là phần cốt lõi:

Những người tạo ra các modern table format nhận ra rằng khiếm khuyết dẫn đến các thách thức với Hive table format là định nghĩa của bảng dựa trên nội dung của các directory, chứ không dựa trên từng datafile riêng lẻ. Các modern table format như Apache Iceberg, Apache Hudi và Delta Lake đều chọn cách tiếp cận định nghĩa bảng như một danh sách canonical các file, cung cấp metadata cho engine để cho biết file nào tạo nên bảng, chứ không phải directory nào.

Đây là cú đổi source of truth:

Hive:
  table = directory contents

Modern table format:
  table = canonical list of data files in metadata

Khi table được định nghĩa bằng canonical file list + metadata, các feature bắt đầu khả thi hơn:

  • ACID transaction;
  • safe multi-writer transaction;
  • time travel;
  • better table statistics/metadata;
  • query planning scan ít file hơn;
  • schema/partition evolution.

Iceberg giải cụ thể bằng metadata tree

Iceberg vẫn dùng open storage và open file format. Data files có thể vẫn là Parquet/ORC/Avro. Điểm khác là Iceberg thêm table metadata layer phía trên.

Catalog
  → latest metadata file
    → snapshots
      → manifest lists
        → manifest files
          → data files

Catalog

Catalog theo dõi vị trí của table, nhưng thay vì map table name tới tập directory, nó map table name tới metadata file mới nhất của table.

orders → metadata-v42.json

Commit mới publish metadata mới:

orders → metadata-v43.json

Catalog pointer này là một phần quan trọng của commit/correctness model.

Metadata file

Metadata file định nghĩa cấu trúc table:

  • schema;
  • partitioning scheme;
  • danh sách snapshots.

Manifest list

Manifest list định nghĩa một snapshot duy nhất của table dưới dạng danh sách manifest files, cùng statistics trên manifest đó để giúp tạo execution plan hiệu quả hơn.

Manifest file

Manifest file mô tả data files ở cấp file:

file_path
file_format
partition_spec_id
partition_values
record_count
file_size
lower_bounds / upper_bounds
null counts

Nó giúp planner biết file nào thuộc table/snapshot, file đó dùng partition spec nào, stats gì, và có nên scan không — trước khi mở data file thật.

Vì sao Iceberg lấy lại được warehouse-like features?

Nếu warehouse có các năng lực này bên trong black box, Iceberg cố externalize chúng thành open table metadata contract.

Consistency

Vì table state là snapshot metadata, reader có thể thấy snapshot cũ hoặc snapshot mới, không thấy trạng thái ở giữa.

Performance

Vì planner đọc metadata/manifest thay vì list directory vô tội vạ, nó có thể prune manifest/file tốt hơn trước khi scan data.

Evolvability

Vì schema và partition specs nằm trong metadata, Iceberg có thể evolve chúng an toàn hơn. Ví dụ partition evolution cho phép file cũ giữ spec cũ, file mới dùng spec mới.

Hidden partitioning

Vì partition transform nằm trong metadata, user query theo column tự nhiên vẫn có thể hưởng partition pruning. User không cần biết physical partition columns.

Time travel và rollback

Vì table state được version bằng snapshots, query có thể trỏ tới snapshot cũ; rollback có thể chuyển current table state về snapshot trước đó.

Mental model chính của Chapter 1

Mình muốn giữ lại chapter này như sau:

Warehouse:
  có đủ storage + metadata + catalog + table format + compute
  nhưng các lớp này thường đóng, tightly coupled, proprietary

Data lake:
  mở storage và file format ra
  nhưng thiếu một table-level contract đủ mạnh

Lakehouse / Iceberg:
  giữ open storage/file format
  thêm open table format + metadata/snapshot/transaction layer
  để lấy lại warehouse-like semantics trên data lake

Nên về bản chất, warehouse và lakehouse không khác nhau vì một bên “có table format” còn bên kia “không có”. Cả hai đều cần table metadata. Khác biệt chính là:

warehouse = table machinery nằm bên trong một hệ thống đóng
lakehouse = table machinery được tách ra thành open/interoperable layers

Đây cũng là lý do Iceberg quan trọng: nó không chỉ là một library hay một file format, mà là một shared contract để nhiều compute engines cùng hiểu một table trên open storage.

My Summary

Điểm hay nhất của Chapter 1 với mình là cách nó nối lại một thứ tưởng như mới với thứ warehouse đã có từ lâu.

Warehouse đã luôn có catalog, metadata, table layout, transaction, optimizer statistics, snapshot/recovery… Chỉ là chúng nằm trong một black box. Data lake mở storage và file format ra, nhưng ban đầu làm mất nhiều semantics đó. Lakehouse cố đưa các semantics ấy trở lại bằng những layer mở hơn.

Hive là bước trung gian rất quan trọng: nó cho data lake một SQL/table abstraction. Nhưng Hive vẫn lấy directory layout làm source of truth chính, nên khi scale lớn và multi-engine/multi-writer workload xuất hiện, nó thiếu granularity để làm consistency, concurrency, planning, evolution tốt.

Iceberg externalize phần “table brain” ra khỏi warehouse engine và đặt nó lên open storage: snapshot, manifest, metadata file, catalog pointer, canonical file list. Nhờ đó Spark/Trino/Flink/Dremio... có thể cùng đọc/ghi dựa trên một metadata contract.

Nhưng trade-off là khi các lớp được tách ra, integration và operational responsibility cũng lộ ra ngoài. Warehouse che nhiều thứ cho mình; lakehouse cho mình openness và interoperability, nhưng bắt mình hiểu rõ hơn về catalog, metadata, commit protocol, compaction, evolution, and multi-engine consistency.

Nói ngắn gọn:

Lakehouse không phải phủ nhận warehouse. Nó là thử nghiệm tách những năng lực cốt lõi của warehouse thành các open components có thể chạy trên data lake.

Open questions / đọc tiếp Chapter 2

  • Iceberg metadata file, manifest list và manifest file cụ thể encode những gì?
  • Catalog pointer commit protocol hoạt động ra sao để đảm bảo atomicity?
  • Snapshot isolation của Iceberg giống/khác database MVCC thế nào?
  • Khi nhiều engines cùng ghi, conflict detection dựa trên những rule nào?
  • Phần nào của “warehouse black box” đã được Iceberg externalize, phần nào vẫn nằm trong compute engine/catalog implementation?

On this page