1. Xây dựng Data Lakehouse Cục bộ với Dremio, Spark và Iceberg [0]

thumbnail Video này hướng dẫn cách thiết lập một Data Lakehouse cục bộ trên máy tính cá nhân bằng cách kết hợp các công cụ mã nguồn mở như Dremio, Spark, Iceberg, Nessie và MinIO. Mục tiêu là tạo ra một môi trường linh hoạt để khám phá và thử nghiệm kiến trúc Data Lakehouse.

1.1. Chuẩn bị Môi trường Cục bộ [0]

  1. Yêu cầu về công cụ: Để thực hiện theo hướng dẫn, người dùng cần cài đặt Visual Studio Code và Docker. [2]
  2. Kiến trúc tổng quan:
    • Một container sẽ chạy Apache Spark và Jupyter Notebook để xử lý dữ liệu theo lô (batch) và luồng (streaming). [5]
    • Một container khác sẽ chạy Nessie catalog để theo dõi các tập dữ liệu Apache Iceberg. [6]
    • Dremio sẽ đóng vai trò là công cụ truy vấn (query engine), cho phép truy vấn và tăng tốc độ truy vấn trên các tập dữ liệu. [7]
    • MinIO sẽ hoạt động như một lớp lưu trữ tương thích với S3 để lưu trữ dữ liệu. [11]
  3. Sử dụng Docker Compose:
    • Docker Compose được sử dụng để định nghĩa và thiết lập nhiều container (dịch vụ) chạy trên cùng một mạng chia sẻ, tạo ra môi trường làm việc. [8]
    • Các dịch vụ bao gồm: Dremio, MinIO, Spark Notebook, và Nessie server. [11]
    • Tất cả các dịch vụ này sẽ chạy trên một mạng chung có tên là "Iceberg environment". [14]
  4. Cấu hình biến môi trường:
    • Một tệp .env sẽ được tạo để lưu trữ các biến môi trường cần thiết, đặc biệt là cho container Spark. [15]
    • Các biến này bao gồm thông tin về region, access key và secret key cho MinIO, URL API của Nessie, và bucket lưu trữ (ví dụ: "Warehouse"). [17]

1.2. Khởi chạy và Cấu hình các Dịch vụ [23]

  1. Khởi chạy MinIO:
    • Mở một terminal và chạy lệnh docker compose up minio để khởi động riêng dịch vụ MinIO. [23]
    • MinIO sẽ được truy cập qua localhost:9000 (giao diện web) và localhost:9001 (API). [28]
    • Đăng nhập bằng tên người dùng minioadmin và mật khẩu minioadmin. [34]
    • Tạo bucket: Tạo một bucket có tên là "Warehouse" để lưu trữ dữ liệu. [38]
    • Lấy Access Key và Secret Key: Tạo một access key và secret key mới và sao chép chúng vào tệp .env. [40]
  2. Khởi chạy Nessie:
    • Mở một terminal mới và chạy lệnh docker compose up nessie. [52]
    • Nessie sẽ sử dụng cấu hình mặc định, lưu trữ metadata trong bộ nhớ (memory store). [54]
    • Nessie hỗ trợ nhiều tùy chọn xác thực, nhưng ở đây sử dụng cấu hình mặc định không có xác thực. [58]
  3. Khởi chạy Spark Notebook:
    • Mở một terminal khác và chạy lệnh docker compose up spark-notebook. [64]
    • Sau khi khởi động, một URL sẽ được cung cấp, bao gồm một token để truy cập vào giao diện Jupyter Notebook. [69]
    • Truy cập URL này trong trình duyệt để sử dụng Jupyter Notebook với Spark. [72]
  4. Khởi chạy Dremio:
    • Mở terminal cuối cùng và chạy lệnh docker compose up dremio. [76]
    • Quá trình này có thể mất một chút thời gian. [79]

1.3. Tích hợp Dữ liệu với Spark và Iceberg [80]

  1. Tạo Notebook mới: Trong Jupyter Notebook, tạo một notebook Python 3 mới. [84]
  2. Cấu hình Spark cho Iceberg và Nessie:
    • Đọc các biến môi trường từ tệp .env để cấu hình kết nối. [87]
    • Tải các thư viện cần thiết: Chỉ định các JAR cần tải về cho Spark, bao gồm Iceberg, Nessie, và AWS SDK bundle (để tương thích với S3). [92]
    • Cấu hình extension SQL: Kích hoạt các extension cho Nessie và Iceberg để sử dụng cú pháp SQL đặc biệt. [97]
    • Cấu hình catalog:
      • Đặt tên cho catalog (ví dụ: "Nessie"). [99]
      • Sử dụng NessieCatalog làm implementation. [102]
      • Chỉ định branch mặc định là "main". [107]
    • Cấu hình lưu trữ S3 tương thích:
      • Thiết lập endpoint URL cho MinIO thay vì AWS. [109]
      • Chỉ định bucket lưu trữ ("Warehouse") và sử dụng S3InputOutput cho việc ghi file. [110]
      • Cung cấp AWS credentials (access key và secret key) từ tệp .env. [112]
  3. Tạo và Chèn Dữ liệu vào Bảng Iceberg:
    • Sử dụng cú pháp CREATE TABLE trong Spark, chỉ định USING iceberg để tạo một bảng Iceberg đơn giản với một cột name kiểu string. [115]
    • Sử dụng câu lệnh INSERT INTO để chèn ba bản ghi tên (Alex Merced, Depend Camara, Zoomdar, Jason Hughes) vào bảng. [117]
  4. Truy vấn Dữ liệu từ Spark:
    • Thực hiện truy vấn SELECT * FROM names để xác nhận dữ liệu đã được chèn thành công. [119]
    • Quá trình này bao gồm việc tải thư viện, cấu hình Spark session và thực thi các lệnh SQL. [124]

1.4. Truy vấn Dữ liệu với Dremio [129]

  1. Truy cập Giao diện Dremio:
    • Truy cập Dremio qua localhost:9047. [129]
    • Thiết lập tên người dùng, email và mật khẩu khi lần đầu truy cập. [130]
  2. Cấu hình Nguồn Dữ liệu (Source) trong Dremio:
    • Thêm Source: Nhấp vào "ADD Source" trong Dremio. [161]
    • Kết nối với Nessie Catalog:
      • Đặt tên cho source là "Nessie". [162]
      • Nhập Nessie endpoint URL: http://nessie:19120/api/v2. [164]
        • Lý do sử dụng tên dịch vụ "nessie" là vì các container Docker chạy trên cùng một mạng và có thể giao tiếp với nhau bằng tên dịch vụ của chúng. [164]
        • Sử dụng /api/v2 vì connector Nessie của Dremio sử dụng phiên bản API V2, khác với Spark sử dụng V1. [166]
      • Chọn phương thức xác thực là "None". [169]
    • Kết nối với MinIO (Lưu trữ S3):
      • Nhập Access Key và Secret Key đã lấy từ MinIO. [174]
      • Chỉ định AWS root path là bucket "Warehouse". [177]
      • Thêm các thuộc tính tùy chỉnh:
        • fs.s3a.path.style.access: Đặt thành true để sử dụng kiểu truy cập đường dẫn S3. [186]
        • fs.s3a.endpoint: Đặt thành minio:9000 để chỉ định endpoint của MinIO. [187]
        • dremio.s3.compat: Đặt thành true để Dremio hoạt động ở chế độ tương thích với S3. [191]
        • Tắt kết nối SSL (dremio.ssl.enabled=false) vì đang chạy cục bộ. [193]
    • Lưu cấu hình source. Dremio sẽ kiểm tra kết nối với catalog và lớp lưu trữ. [195]
  3. Truy vấn Dữ liệu từ Dremio:
    • Sau khi kết nối thành công, Dremio sẽ hiển thị các bảng được tạo trong Spark (ví dụ: bảng "names"). [204]
    • Chạy truy vấn SELECT * FROM nessie.names để lấy dữ liệu. [208]
    • Dremio truy vấn dữ liệu bằng cách: lấy tham chiếu metadata từ Nessie, sau đó truy cập file metadata.json và các file dữ liệu parquet trong MinIO. [210]
  4. Tạo View và Tổ chức Dữ liệu:
    • Tạo một view đơn giản bằng cách chọn một bản ghi từ bảng "names" (SELECT * FROM nessie.names LIMIT 1). [210]
    • Lưu view này vào một space (ví dụ: "Gold data set") với tên "just Alex". [211]
    • Dremio cho phép tạo các view logic mà không cần sao chép dữ liệu, hỗ trợ kiến trúc no-copy. [214]
    • Người dùng cuối (data analyst, data scientist) có thể truy cập dữ liệu thông qua các view được tổ chức này, với tài liệu hóa (wiki) và quyền truy cập chi tiết. [215]
    • Dữ liệu có thể được truy cập qua UI của Dremio, REST API, ODBC, AeroFlight, hoặc tích hợp với các công cụ BI như Power BI và Tableau. [217]
  5. Sử dụng Nessie Branching:
    • Tạo một branch mới trong Nessie catalog có tên là "ETL" thông qua Dremio. [219]
    • Chuyển ngữ cảnh sang branch "ETL" và tạo một bảng mới có tên "names_2". [225]
    • Chèn dữ liệu vào bảng "names_2". [226]
    • Kiểm tra trạng thái catalog Nessie: branch "main" chỉ có bảng "names", trong khi branch "ETL" có cả "names" và "names_2". [232]
    • Điều này cho thấy khả năng cô lập các thay đổi dữ liệu vào các branch khác nhau, tương tự như Git. [234]
    • Các tính năng branching và merging của Nessie cũng có thể được sử dụng trong Spark thông qua các extension SQL. [235]

1.5. Dọn dẹp Môi trường [238]

  1. Dừng các Container:
    • Mở một terminal mới và chạy lệnh docker compose down. [239]
    • Lệnh này sẽ tắt tất cả các container đã được khởi động bằng Docker Compose. [240]
    • Sau khi chạy lệnh này, môi trường cục bộ sẽ được dọn dẹp. [241]