0

QUY TRÌNH 5 BƯỚC TRIỂN KHAI ENTERPRISE DATA LAKE & ETL PIPELINE

BƯỚC 1: KHẢO SÁT NGUỒN DỮ LIỆU & THIẾT KẾ HẠ TẦNG LƯU TRỮ

A. Khảo sát và Phân loại Nguồn Dữ Liệu

CDC (Change Data Capture): Sử dụng Debezium kết hợp Kafka để trích xuất dữ liệu thay đổi từ PostgreSQL/MySQL OLTP theo thời gian thực.

Batch Ingestion: Đọc dữ liệu lịch sử từ REST APIs hoặc File dumps (CSV, JSON) định kỳ theo giờ/ngày.

B. Định Dạng File Lưu Trữ Tối Ưu

Tuyệt đối tránh lưu trữ CSV/JSON ở quy lớn: Dữ liệu dạng dòng (Row-oriented) làm tốn dung lượng và quét chậm khi thực hiện câu lệnh SELECT theo cột.

Sử dụng Định dạng Cột (Columnar Format - Apache Parquet): Giúp nén dữ liệu từ 70% - 80% bằng thuật toán Snappy, hỗ trợ Predicate Pushdown (chỉ đọc các cột cần thiết trong câu truy vấn), giúp tăng tốc truy vấn SQL gấp 10-20 lần.

C. Mã Mô Phỏng: Chuyển Đổi JSON Thô Sang Apache Parquet

Đoạn mã Python dưới đây mô phỏng kịch bản tiền xử lý nén file log JSON thô sang Parquet phân vùng theo thời gian:

import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq
from datetime import datetime

def convert_json_to_partitioned_parquet(json_file_path: str, output_base_dir: str):
    # 1. Đọc dữ liệu JSON thô
    df = pd.read_json(json_file_path, lines=True)
    
    # 2. Thêm Metadata kiểm toán (Audit Metadata)
    df['_ingested_at'] = datetime.utcnow()
    df['year'] = pd.to_datetime(df['timestamp']).dt.year
    df['month'] = pd.to_datetime(df['timestamp']).dt.month
    df['day'] = pd.to_datetime(df['timestamp']).dt.day
    
    # 3. Ghi ra thư mục theo chuẩn phân vùng Partitioning (Hive style)
    table = pa.Table.from_pandas(df)
    pq.write_to_dataset(
        table,
        root_path=output_base_dir,
        partition_cols=['year', 'month', 'day'],
        compression='SNAPPY'
    )
    print("-> Đã chuyển đổi và phân vùng Parquet thành công!")

# Ví dụ thực thi:
# convert_json_to_partitioned_parquet("raw_logs.json", "s3://my-company-datalake/bronze/app_logs/")

BƯỚC 2: TẦNG INGESTION & BẢO TỒN NGUYÊN BẢN (BRONZE ZONE)

Tầng Bronze có nhiệm vụ hấp thụ (ingest) dữ liệu với tốc độ cao nhất mà không thực hiện bất kỳ phép biến đổi nghiệp vụ nào, đảm bảo tính khả lặp (Idempotency) khi cần chạy lại pipeline trong quá khứ.

A. Nguyên Tắc Thiết Kế Bronze Zone

Immutable Storage: Dữ liệu ở tầng Bronze chỉ được phép Append (thêm mới), không được UPDATE hoặc DELETE.

Metadata Enforcement: Mỗi bản ghi phải đính kèm _source_system, _file_name và _ingested_at.

B. Mã Mô Phỏng: PySpark Ingestion Đưa Dữ Liệu Vào Bronze Delta Table

from pyspark.sql import SparkSession
from pyspark.sql.functions import current_timestamp, input_file_name

# Khởi tạo Spark Session hỗ trợ Delta Lake
spark = SparkSession.builder \
    .appName("Bronze_Zone_Ingestion") \
    .config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
    .config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog") \
    .getOrCreate()

def ingest_to_bronze(raw_stream_path: str, bronze_table_path: str):
    # Đọc dữ liệu JSON bất cấu trúc từ staging
    raw_df = spark.read.format("json").load(raw_stream_path)
    
    # Bổ sung trường Audit
    bronze_df = raw_df.withColumn("_ingested_at", current_timestamp()) \
                      .withColumn("_source_file", input_file_name())
    
    # Ghi dữ liệu dạng Delta Format vào Bronze Zone
    bronze_df.write \
        .format("delta") \
        .mode("append") \
        .option("mergeSchema", "true") \
        .save(bronze_table_path)

    print("-> Đã nạp thành công vào Bronze Delta Lake Zone.")

BƯỚC 3: LÀM SẠCH, MÃ HÓA PII & QUẢN LÝ TRANSACTION (SILVER ZONE)

Tầng Silver chuyển hóa dữ liệu thô từ Bronze thành dữ liệu chuẩn hóa, sẵn sàng cho công tác phân tích. Đây là nơi giải quyết bài toán giao dịch ACID (Atomicity, Consistency, Isolation, Durability) và xử lý dữ liệu thay đổi từ nguồn (CDC Upsert).

A. Các Tác Vụ Cốt Lõi Tại Silver Zone

Deduplication: Loạt bỏ bản ghi trùng lặp dựa trên khóa chính và mốc thời gian cập nhật gần nhất.

PII Masking (Bảo mật thông tin cá nhân): Mã hóa SHA-256 đối với Số điện thoại, Email, Số CCCD/CMND để tuân thủ quy định bảo mật dữ liệu (GDPR/Decree 13).

Upsert Logic (MERGE INTO): Áp dụng Delta Lake MERGE để cập nhật dữ liệu mới và chèn bản ghi mới.

B. Mã Mô Phỏng: PySpark & Delta Lake Merge (Upsert CDC Into Silver Zone)

from delta.tables import DeltaTable
from pyspark.sql.functions import col, sha2, concat_ws, row_number
from pyspark.sql.window import Window

def process_bronze_to_silver(spark, bronze_path: str, silver_table_path: str):
    # 1. Đọc dữ liệu từ Bronze Zone
    bronze_df = spark.read.format("delta").load(bronze_path)
    
    # 2. Khử trùng lặp (Deduplication) - Lấy bản ghi mới nhất theo timestamp
    window_spec = Window.partitionBy("customer_id").orderBy(col("updated_at").desc())
    dedup_df = bronze_df.withColumn("rn", row_number().over(window_spec)) \
                        .filter(col("rn") == 1) \
                        .drop("rn")
    
    # 3. Mã hóa thông tin cá nhân PII (SHA-256)
    silver_cleansed_df = dedup_df.withColumn("email_masked", sha2(col("email"), 256)) \
                                 .withColumn("phone_masked", sha2(col("phone"), 256)) \
                                 .drop("email", "phone")
    
    # 4. Kiểm tra xem Bảng Silver Delta đã tồn tại chưa
    if not DeltaTable.isDeltaTable(spark, silver_table_path):
        silver_cleansed_df.write.format("delta").save(silver_table_path)
    else:
        # Thực hiện giao dịch ACID MERGE INTO (Upsert)
        silver_table = DeltaTable.forPath(spark, silver_table_path)
        silver_table.alias("target").merge(
            silver_cleansed_df.alias("source"),
            "target.customer_id = source.customer_id"
        ).whenMatchedUpdate(set={
            "customer_name": col("source.customer_name"),
            "email_masked": col("source.email_masked"),
            "phone_masked": col("source.phone_masked"),
            "status": col("source.status"),
            "updated_at": col("source.updated_at"),
            "_processed_at": current_timestamp()
        }).whenNotMatchedInsert(values={
            "customer_id": col("source.customer_id"),
            "customer_name": col("source.customer_name"),
            "email_masked": col("source.email_masked"),
            "phone_masked": col("source.phone_masked"),
            "status": col("source.status"),
            "created_at": col("source.created_at"),
            "updated_at": col("source.updated_at"),
            "_processed_at": current_timestamp()
        }).execute()

    print("-> Đã MERGE dữ liệu thành công sang Tầng Silver Delta Lake!")

BƯỚC 4: MÔ HÌNH HÓA HOÀN THIỆN & BIẾN ĐỔI NGHIỆP VỤ (GOLD ZONE & DATA WAREHOUSE)

Tầng Gold là tầng dữ liệu đã qua tính toán chỉ số nghiệp vụ, sẵn sàng phục vụ cho các Báo cáo Quản trị (BI Dashboards) và các truy vấn siêu tốc.

A. Mô Hình Hóa Ngôi Sao (Star Schema)

Bảng Sự Kiện (Fact Tables): Chứa các số đo tính toán (amount, quantity, discount_value).

Bảng Chiều (Dimension Tables): Chứa thông tin ngữ cảnh (dim_customers, dim_products, dim_date), quản lý lịch sử thay đổi theo chuẩn Slowly Changing Dimensions (SCD Type 2).

B. Mã Mô Phỏng SQL Transformation Với dbt (data build tool)

Đoạn mã SQL dbt dưới đây mô phỏng khâu tổng hợp doanh thu theo ngày và phân khúc khách hàng từ Tầng Silver sang Bảng Gold Fact Sales:

-- file: models/gold/fact_daily_customer_sales.sql

{{ config(
    materialized='incremental',
    unique_key=['sales_date', 'customer_id'],
    file_format='delta'
) }}

WITH silver_orders AS (
    SELECT 
        customer_id,
        CAST(order_timestamp AS DATE) AS sales_date,
        order_id,
        total_amount,
        status
    FROM {{ ref('silver_orders_cleansed') }}
    WHERE status = 'COMPLETED'
),

daily_aggregation AS (
    SELECT
        sales_date,
        customer_id,
        COUNT(DISTINCT order_id) AS total_orders,
        SUM(total_amount) AS total_revenue,
        AVG(total_amount) AS avg_order_value,
        CURRENT_TIMESTAMP() AS _created_at
    FROM silver_orders
    GROUP BY sales_date, customer_id
)

SELECT * FROM daily_aggregation

{% if is_incremental() %}
    -- Logic chạy tăng tiến cho dbt
    WHERE sales_date >= (SELECT MAX(sales_date) FROM {{ this }})
{% endif %}

BƯỚC 5: ĐIỀU PHỐI TỰ ĐỘNG HÓA & GIÁM SÁT OBSERVABILITY (ORCHESTRATION)

Để toàn bộ hệ thống ETL/ELT vận hành tự động, chống chịu lỗi (Fault-tolerant) và gửi cảnh báo khi sập sự cố, Kỹ sư Dữ liệu phải sử dụng công cụ điều phối đồ thị có hướng không chu trình (DAGs - Directed Acyclic Graphs) như Apache Airflow.

A. Mã Mô Phỏng: Airflow DAG Điều Phối Chuỗi Tác Vụ End-to-End

from airflow import DAG
from airflow.providers.databricks.operators.databricks import DatabricksSubmitRunOperator
from airflow.operators.python import PythonOperator
from airflow.utils.dates import days_ago
from datetime import timedelta

default_args = {
    'owner': 'data_engineering_team',
    'depends_on_past': False,
    'email_on_failure': True,
    'email': ['data_alerts@company.com'],
    'retries': 2,
    'retry_delay': timedelta(minutes=5),
}

with DAG(
    dag_id='enterprise_medallion_etl_pipeline',
    default_args=default_args,
    description='Pipeline điều phối ETL 3 tầng Bronze -> Silver -> Gold',
    schedule_interval='0 2 * * *', # Chạy tự động lúc 2:00 AM hàng ngày
    start_date=days_ago(1),
    catchup=False,
    tags=['production', 'data_lake', 'etl'],
) as dag:

    # Task 1: Ingest dữ liệu thô từ nguồn lên Bronze Zone
    task_ingest_bronze = DatabricksSubmitRunOperator(
        task_id='ingest_raw_to_bronze',
        notebook_task={'notebook_path': '/Pipelines/01_Ingest_Bronze'},
    )

    # Task 2: Làm sạch, Deduplicate và Merge sang Silver Zone
    task_process_silver = DatabricksSubmitRunOperator(
        task_id='transform_bronze_to_silver',
        notebook_task={'notebook_path': '/Pipelines/02_Process_Silver'},
    )

    # Task 3: Chạy dbt model tính toán các chỉ số Gold Zone
    task_build_gold = DatabricksSubmitRunOperator(
        task_id='aggregate_silver_to_gold',
        notebook_task={'notebook_path': '/Pipelines/03_Build_Gold'},
    )

    # Task 4: Kiểm thử chất lượng dữ liệu (Data Quality Test)
    def run_data_quality_checks():
        print("Checking Data Quality... NULL values < 0.01% -> PASSED!")

    task_quality_check = PythonOperator(
        task_id='validate_data_quality',
        python_callable=run_data_quality_checks
    )

    # Thứ tự thực thi chuỗi công việc (Dependency Chain)
    task_ingest_bronze >> task_process_silver >> task_build_gold >> task_quality_check

NHỮNG BẪY KỸ THUẬT VÀ QUY TẮC CỐT LÕI KHI VẬN HÀNH PRODUCTION

Bẫy "Small File Problem" (Hiện tượng rác file nhỏ): Trong quá trình ghi Streaming hoặc Ingestion liên tục, Hồ dữ liệu sẽ xuất hiện hàng triệu file Parquet dung lượng vài KB, gây suy giảm 95% tốc độ truy vấn.

Giải pháp: Thiết lập định kỳ lệnh OPTIMIZE và VACUUM trên Delta Lake để nén hợp nhất các file nhỏ thành các file lớn chuẩn 128MB - 1GB.

Schema Evolution (Quản lý sự thay đổi cấu trúc dữ liệu): Dữ liệu nguồn đột ngột thêm/bớt trường thông tin có thể làm sập Pipeline.

Giải pháp: Sử dụng tính năng mergeSchema=true của Delta Lake để tự động mở rộng bảng khi có trường dữ liệu mới mà không ngắt quãng hệ thống.

Tính Khả Lặp (Idempotency): Đảm bảo kịch bản khi một Job bị crash giữa chừng và chạy lại 10 lần thì kết quả cuối cùng trong Data Lake vẫn hoàn toàn giống hệt lần chạy thành công đầu tiên, không sinh dữ liệu trùng lặp (Duplicate Records).

NÂNG CAO NĂNG LỰC KỸ SƯ DỮ LIỆU THỰC CHIẾN CÙNG CHUYÊN GIA

Để tự tay thiết lập trọn vẹn quy trình 5 bước này trên các hạ tầng Cloud thực tế (Google BigQuery, AWS S3, Spark Cluster) với các tập dữ liệu doanh nghiệp dung lượng Gigabyte/Terabyte thật, việc tiếp cận một giáo trình đào tạo bài bản cùng sự dẫn dắt của Chuyên gia là giải pháp tối ưu nhất.

KẾT LUẬN

Việc làm chủ quy trình 5 bước thiết lập Enterprise Data Lake và ETL Pipeline chính là bệ phóng vững chắc giúp bạn khẳng định vị thế Kỹ sư Dữ liệu cấp cao (Senior Data Engineer / Data Architect). Một hệ thống hạ tầng dữ liệu được thiết kế bài bản không chỉ bảo vệ tài sản thông tin của doanh nghiệp mà còn là động cơ thúc đẩy mọi chiến lược Chuyển đổi số thành công.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí