DE

[DE Blog #03] Giải Mã Định Dạng Tệp Big Data (Parquet, Avro, ORC) & Bản Chất NoSQL / Định Lý CAP

40 views
[DE Blog #03] Giải Mã Định Dạng Tệp Big Data (Parquet, Avro, ORC) & Bản Chất NoSQL / Định Lý CAP

1. Bối cảnh thực tế (Context & Problem Statement)

Khi lưu trữ và xử lý hàng Terabyte đến Petabyte dữ liệu trên Data Lake (AWS S3, Google Cloud Storage, HDFS), việc lựa chọn định dạng file có thể quyết định:

  • Tốc độ truy vấn nhanh hơn 10x – 50x.
  • Tiết kiệm 60% – 80% dung lượng lưu trữ nhờ các thuật toán nén chuyên dụng.
  • Giảm thiểu hàng nghìn USD chi phí quét dữ liệu trên các Query Engine phân tán (Spark, Presto/Trino, BigQuery External Tables).

Ngược lại, việc lạm dụng định dạng văn bản thô (CSV, JSON) cho các tác vụ phân tích quy mô lớn là một trong những nguyên nhân hàng đầu gây sập cluster (OOM - Out of Memory) và tắc nghẽn I/O.


2. Các Khái Niệm & Cơ Chế Cốt Lõi

2.1. Phân loại định dạng tệp (Row-based vs. Columnar)

  • Row-based (Lưu theo dòng - CSV, JSON, Avro): Lưu toàn bộ các trường của một bản ghi nối tiếp nhau. Tối ưu cho việc ghi dữ liệu liên tục (streaming ingestion, CDC) và đọc trọn vẹn từng bản ghi.
  • Columnar (Lưu theo cột - Parquet, ORC): Gom toàn bộ giá trị của cùng một cột trên nhiều dòng lại để lưu cùng nhau. Tối ưu cho việc đọc phân tích, tính toán tổng hợp trên một số cột nhất định.
Dữ liệu: [ID, Name, Age]
Row-Based:    (1, Alice, 25) | (2, Bob, 30) | (3, Charlie, 28)
Column-Based: (1, 2, 3) | (Alice, Bob, Charlie) | (25, 30, 28)

2.2. Cơ chế tối ưu hóa của Apache Parquet

  1. Column Projection (Đọc tỉa cột): Khi câu lệnh chỉ SELECT age FROM users, Engine chỉ cần đọc duy nhất khối dữ liệu của cột age từ đĩa, hoàn toàn bỏ qua các cột khác.
  2. Predicate Pushdown (Đẩy bộ lọc xuống tầng lưu trữ): Parquet lưu trữ metadata (Min/Max value, Null count) cho từng khối dữ liệu (Row Group). Nếu câu lệnh có WHERE age > 50, Engine sẽ đọc metadata trước; nếu một Row Group có max_age = 45, toàn bộ Row Group đó sẽ bị bỏ qua (Skip) mà không cần đọc dữ liệu thực tế.
  3. Mã hóa & Nén hiệu quả (Compression & Encoding): Vì cùng một cột có cùng kiểu dữ liệu, Parquet áp dụng các thuật toán mã hóa tối ưu như Dictionary Encoding, Run-Length Encoding (RLE), Bit-Packing kết hợp với nén Snappy/ZSTD/Gzip.

2.3. Cơ sở dữ liệu NoSQL & 4 Nhóm Kiến Trúc

  • Key-Value Store: Lưu trữ cặp khóa - giá trị đơn giản, truy xuất cực nhanh theo Key (Redis, AWS DynamoDB).
  • Document Store: Lưu trữ tài liệu dạng bán cấu trúc như JSON/BSON (MongoDB, Couchbase).
  • Wide-Column Store: Lưu trữ theo họ cột (Column Family), hỗ trợ ghi khối lượng dữ liệu khổng lồ với độ trễ thấp (Apache Cassandra, ScyllaDB, HBase).
  • Graph Database: Tối ưu cho việc biểu diễn và truy vấn các mối quan hệ phức tạp, mạng lưới (Neo4j, Amazon Neptune).

2.4. Định lý CAP (CAP Theorem)

Trong một hệ thống phân tán chia sẻ dữ liệu qua mạng, bạn chỉ có thể đảm bảo tối đa 2 trong 3 yếu tố:

  • Consistency (Tính nhất quán - C): Mọi client đều đọc được dữ liệu mới nhất tại cùng một thời điểm (hoặc nhận lỗi nếu chưa đồng bộ xong).
  • Availability (Tính khả dụng - A): Mọi request gửi đến hệ thống đều nhận được phản hồi thành công (không bị lỗi hoặc timeout), dù dữ liệu trả về có thể chưa phải là bản mới nhất.
  • Partition Tolerance (Tính chịu lỗi phân vùng mạng - P): Hệ thống vẫn tiếp tục hoạt động ngay cả khi kết nối mạng giữa các node bị đứt đoạn hoặc mất gói tin.

⚠️ Quy tắc thực tế: Trong mạng phân tán, sự cố mạng (Network Partition - P) là điều không thể tránh khỏi. Do đó, bài toán thực tế luôn là lựa chọn giữa CP (Consistency over Availability) hay AP (Availability over Consistency) khi xảy ra Partition.


3. Các Bảng Markdown So Sánh Chi Tiết

📊 Bảng 1: So Sánh Toàn Diện Các Định Dạng Tệp Big Data

Tiêu chíApache ParquetApache AvroApache ORCCSV / JSON
Cấu trúc lưu trữColumnar (Theo cột)Row-based (Theo dòng)Columnar (Theo cột)Text / Row-based
Hỗ trợ SchemaSchema nhúng trong file (Footer)Schema độc lập (JSON format), hỗ trợ Schema RegistrySchema nhúng trong file (Stripe footer)Schema yếu hoặc không có (Schema-on-read)
Schema EvolutionTốt (hỗ trợ thêm/bớt cột)Xuất sắc nhất (Tương thích xuôi/ngược hoàn hảo)Tốt (tương tự Parquet)Kém, dễ gây lỗi parse khi đổi format
Khả năng nénRất cao (Snappy, ZSTD, Gzip)Trung bình (Deflate, Snappy)Rất cao (ZLIB, Snappy)Kém
Splittable (Chia khối)Có (theo Row Groups)Có (theo Sync Markers)Có (theo Stripes)CSV có thể split, JSON n-line khó split
Trường hợp sử dụngData Lake, OLAP Queries, Spark, Presto/TrinoStreaming Pipeline (Kafka), CDC, Event IngestionHệ sinh thái Hadoop/Hive, ClouderaLưu trữ cấu hình, API Payload, log đơn giản

📊 Bảng 2: So Sánh 4 Nhóm Cơ Sở Dữ Liệu NoSQL

Phân loạiCông nghệ phổ biếnƯu điểm cốt lõiNhược điểmUse-case điển hình
Key-ValueRedis, Memcached, DynamoDBĐọc/ghi siêu nhanh (< 1ms), cấu trúc đơn giảnKhông hỗ trợ truy vấn lọc phức tạp theo giá trịCaching, Session store, Shopping Cart, Leaderboard
DocumentMongoDB, CouchbaseSchema linh hoạt, phát triển ứng dụng nhanhKém hiệu quả khi cần JOIN nhiều collectionsQuản lý Content/CMS, Product Catalog, User Profile
Wide-ColumnCassandra, ScyllaDB, HBaseKhả năng mở rộng ngang (Scale-out) cực mạnh, ghi cực nhanhTruy vấn bị giới hạn theo Partition Key & Clustering KeyTime-series data, IoT Sensor Logs, Viễn thông
GraphNeo4j, Amazon NeptuneTruy vấn quan hệ đa tầng (Traversal) siêu tốcKhó mở rộng phân tán quy mô cực lớnMạng xã hội, Hệ thống gợi ý (Recommendation), Phát hiện gian lận (Fraud Detection)

📊 Bảng 3: Phân Loại Hệ Thống Theo Định Lý CAP

Mô hình CAPCơ chế khi đứt mạng (Network Partition)Hệ thống / Database tiêu biểu
CP (Consistency + Partition Tolerance)Từ chối request hoặc trả về lỗi nếu không thể đảm bảo dữ liệu mới nhất đồng bộ giữa các node.HBase, MongoDB (với w: "majority"), Google Spanner, Apache ZooKeeper
AP (Availability + Partition Tolerance)Vẫn trả về dữ liệu thành công từ node còn sống (chấp nhận dữ liệu có thể là bản cũ - Eventually Consistent).Apache Cassandra, Amazon DynamoDB, Couchbase
CA (Consistency + Availability)Chỉ tồn tại trên hệ thống đơn node (Single-node). Không khả thi trên hệ thống mạng phân tán.PostgreSQL, MySQL (mô hình Standalone truyền thống)

4. Best Practices & Cạm Bẫy Thực Chiến (Pro-Tips & Pitfalls)

💡 Vấn đề "Small Files Problem" trên Data Lake

  • Cạm bẫy: Việc tạo ra hàng nghìn file Parquet dung lượng chỉ vài KB (do streaming nạp liên tục hoặc do số lượng Spark Partition quá lớn) sẽ làm nghẽn NameNode (HDFS) và tốn chi phí gọi Metadata API trên Cloud Storage (S3/GCS).
  • Giải pháp:
    • Luôn gộp file (File Compaction) định kỳ sao cho kích thước lý tưởng của một file Parquet rơi vào khoảng 128 MB – 512 MB.
    • Trong Spark, dùng .coalesce(n) hoặc repartition() trước khi ghi file.

💡 Tối ưu hóa Partitioning cho Data Lake

  • Partition thư mục theo các cột có độ chọn lọc vừa phải (ví dụ: year=2026/month=08/day=15/).
  • Tránh Over-partitioning: Không bao giờ partition theo các cột có Cardinality quá cao như user_id hay timestamp chính xác đến từng giây.

5. Góc Ôn Luyện Phỏng Vấn (Interview Corner)

❓ Câu hỏi 1: Tại sao Apache Parquet lại tối ưu hơn JSON/CSV cho các truy vấn phân tích (OLAP)? Trình bày cơ chế Predicate Pushdown.

  • Gợi ý trả lời:
    1. Columnar Storage: Parquet chỉ nạp đúng các cột có trong SELECT, giảm tối đa băng thông I/O so với việc đọc toàn bộ dòng như CSV/JSON.
    2. Encoding & Compression: Các giá trị trong cùng một cột có cùng kiểu dữ liệu nên được nén cực mạnh (tiết kiệm 70%+ dung lượng đĩa).
    3. Predicate Pushdown: Parquet lưu metadata thống kê (min_value, max_value, null_count) ở phần Header/Footer của mỗi Row Group. Query Engine đẩy trực tiếp điều kiện lọc (WHERE) xuống tầng đọc file. Nếu giá trị cần lọc nằm ngoài khoảng Min/Max, toàn bộ Row Group đó được bỏ qua ngay lập tức mà không cần nạp vào RAM.

❓ Câu hỏi 2: Khi nào bạn nên chọn Apache Avro thay vì Apache Parquet trong hệ thống Data Pipeline?

  • Gợi ý trả lời:
    • Chọn Apache Avro khi:
      • Xây dựng Streaming Ingestion Pipeline (Apache Kafka / Event Streams): Avro là định dạng lưu trữ dạng dòng (Row-based) nhỏ gọn ở dạng nhị phân, rất nhanh khi tuần tự hóa (Serialization) và giải tuần tự hóa (Deserialization) từng message đơn lẻ.
      • Quản lý Schema Evolution khắt khe: Kết hợp với Confluent Schema Registry, Avro kiểm soát hoàn hảo các quy tắc tương thích xuôi/ngược (Backward, Forward, Full Compatibility) khi hệ thống nguồn thay đổi cấu trúc bảng.
    • Tóm tắt quy tắc phối hợp: Sử dụng Avro ở tầng Ingestion / Streaming Bus (Kafka, Raw Landing Zone) và chuyển đổi sang Parquet ở tầng Data Lake / Data Warehouse phục vụ truy vấn phân tích.

❓ Câu hỏi 3: Hãy giải thích tại sao trong một hệ thống phân tán, ta bắt buộc phải đánh đổi giữa Consistency (C) và Availability (A) khi xảy ra Network Partition (P)?

  • Gợi ý trả lời:
    • Giả sử hệ thống có 2 node (N1N_1N2N_2) đang đồng bộ dữ liệu với nhau. Khi đường truyền mạng giữa N1N_1N2N_2 bị đứt (Partition - P):
      • Một Client gửi yêu cầu ghi dữ liệu mới lên N1N_1.
      • Sau đó, một Client khác gửi yêu cầu đọc dữ liệu từ N2N_2.
    • Lúc này hệ thống chỉ có 2 lựa chọn:
      1. Chọn Consistency (CP): N2N_2 nhận thấy nó không thể liên lạc với N1N_1 để lấy bản cập nhật mới nhất, nên nó từ chối phục vụ hoặc trả về lỗi \rightarrow Đảm bảo dữ liệu không bị sai lệch (C) nhưng mất tính khả dụng (mất A).
      2. Chọn Availability (AP): N2N_2 vẫn trả về dữ liệu đang có trong bộ nhớ của nó \rightarrow Đảm bảo hệ thống luôn phản hồi thành công (A) nhưng dữ liệu trả về bị cũ/lỗi thời (mất C).

6. Tóm Tắt Ghi Nhớ Nhanh (Key Takeaways)

  1. Parquet & ORC (Columnar) dành cho OLAP / Data Lake Querying (tối ưu nén, Predicate Pushdown, Column Projection).
  2. Avro (Row-based) dành cho Streaming Ingestion / Apache Kafka (nhẹ, nhanh, kiểm soát Schema Evolution).
  3. Kích thước file Parquet lý tưởng trong Data Lake là 128 MB – 512 MB để tránh Small Files Problem.
  4. Định lý CAP: Trong mạng phân tán, sự cố mạng (P) là tất yếu, hệ thống bắt buộc phải chọn hy sinh Consistency (CP) hoặc hy sinh Availability (AP).
0Claps