Batch 2 — ETL vs ELT & kiến trúc pipeline

22 thg 7, 2026 2 lượt xem
#etl
#data-engineering
#dbt
#elt
#medallion
#data-pipeline

Mô hình tinh thần: transform đứng ở đâu?

Mọi pipeline batch đều làm ba việc: lấy dữ liệu ra (Extract), biến đổi (Transform), và nạp vào đích (Load). Điều khiến ETL và ELT khác nhau không phải là transform hay không, mà là transform xảy ra ở đâu và lúc nào so với bước load.

  • ETL — Extract → Transform → Load: dữ liệu được biến đổi trước khi chạm vào kho đích. Transform chạy trên một engine trung gian (máy chủ ETL, cluster Spark, công cụ như Informatica/Talend). Chỉ dữ liệu đã sạch, đã đúng schema mới được nạp vào warehouse.
  • ELT — Extract → Load → Transform: dữ liệu thô được nạp nguyên trạng vào kho đích trước, rồi biến đổi ngay bên trong kho đó bằng chính sức tính toán của nó (thường là SQL). Warehouse/lakehouse vừa là nơi lưu vừa là engine transform.

Cùng một logic nghiệp vụ, chỉ khác nơi đặt bước "T". Nhưng cái "nơi đặt" đó kéo theo hàng loạt hệ quả về chi phí, khả năng truy vết, quản trị PII và tốc độ phát triển. Đây là bài thứ hai trong series; nếu bạn chưa đọc tổng quan xử lý batch, nên xem trước để nắm bối cảnh.

Điểm mấu chốt trong sơ đồ: ở ETL, kho đích không bao giờ nhìn thấy dữ liệu thô — engine trung gian gánh toàn bộ transform. Ở ELT, dữ liệu thô được lưu lại trong kho, và transform là một tầng logic (thường là view/bảng dẫn xuất) chồng lên trên.

Vì sao ELT lên ngôi cùng cloud warehouse/lakehouse

ETL thống trị suốt thập niên 1990–2000 vì một lý do kinh tế đơn giản: kho dữ liệu ngày đó rất đắt. Kho on-prem (Teradata, Oracle) tính tiền theo dung lượng và tài nguyên tính toán bị đóng cứng cùng phần cứng. Không ai muốn đổ hàng terabyte dữ liệu thô — phần lớn sẽ bị bỏ đi — vào một cỗ máy đắt đỏ. Nên người ta lọc, làm sạch, tổng hợp trước trên engine rẻ hơn, rồi chỉ nạp phần tinh.

Cloud warehouse và lakehouse đảo ngược nền kinh tế đó qua ba thay đổi:

  1. Tách storage khỏi compute. Trên BigQuery, Snowflake hay lakehouse Iceberg/Delta, lưu trữ nằm trên object storage (GCS/S3) và tính tiền riêng, rất rẻ. Bạn có thể giữ toàn bộ dữ liệu thô gần như miễn phí mà không đụng tới compute.
  2. Compute co giãn và rẻ theo nhu cầu. Bạn bật một warehouse/slot khi cần transform, tắt đi khi xong, chỉ trả cho phần đã dùng. Sức mạnh SQL phân tán đủ để biến đổi hàng tỉ dòng ngay tại chỗ — không cần engine trung gian riêng.
  3. SQL đủ mạnh làm engine transform. Warehouse hiện đại hỗ trợ window function, kiểu dữ liệu bán cấu trúc (JSON/STRUCT), MERGE... nên logic transform vốn phải viết bằng code nay diễn đạt được bằng SQL khai báo.

Khi đã có thể lưu thô gần như miễn phítransform tại chỗ gần như tuỳ ý, việc ép transform ra ngoài trước khi load trở nên vô nghĩa trong phần lớn tình huống. Đó là lý do ELT thành mặc định của modern data stack.

Tiêu chíETLELT
Nơi transformEngine trung gian (Spark, ETL tool)Trong warehouse/lakehouse bằng SQL
Dữ liệu thô có được giữ?Thường không (chỉ nạp phần đã sạch) — raw lưu lại, replay/backfill dễ
Schema-on-read vs writeThiên schema-on-writeThiên schema-on-read (áp schema khi transform)
Chi phí lưu trữƯu tiên tiết kiệm (kho đắt)Chấp nhận lưu nhiều (storage rẻ)
Tốc độ phát triểnChậm hơn (đổi logic = sửa job engine)Nhanh (đổi SQL, chạy lại)
PII / che dữ liệu nhạy cảmChe sớm, trước khi vào khoVào kho trước → cần kiểm soát truy cập tầng raw
Công cụ tiêu biểuInformatica, Talent, SSIS, Sparkdbt + SQL trên warehouse

Kiến trúc pipeline batch điển hình

Một pipeline batch trưởng thành hiếm khi biến dữ liệu thô thẳng thành bảng phục vụ trong một bước. Nó đi qua các lớp (layer/zone) có mục đích riêng, mỗi lớp là một hợp đồng về chất lượng. Cách đặt tên phổ biến nhất hiện nay là medallion (huy chương): bronze → silver → gold.

Ý nghĩa từng lớp:

  • Ingest / Landing zone: điểm dữ liệu vừa cập bến, thường là file (Parquet/CSV/JSON) rơi vào một thư mục object storage theo ngày. Chưa transform gì — chỉ hạ cánh. Đây là ranh giới giữa "ngoài" và "trong" hệ thống.
  • Bronze / Raw: dữ liệu giữ nguyên như nguồn, không sửa nội dung, chỉ thêm metadata kỹ thuật (thời điểm nạp, tên file/nguồn, batch id). Đây là nguồn sự thật bất biến để tái xử lý (reprocess) khi logic downstream đổi hay có lỗi — bạn không phải đi xin lại dữ liệu từ hệ nguồn. Đây chính là lợi ích lớn nhất mà ELT mang lại so với ETL.
  • Silver / Cleaned: dữ liệu đã parse, ép kiểu (cast), chuẩn hoá đơn vị/định dạng, khử trùng lặp (dedup), lọc bản ghi hỏng, và join làm giàu nhẹ. Mỗi bảng silver có schema rõ ràng và đáng tin để phân tích. Đây là nơi áp các kiểm thử chất lượng dữ liệu (xem batch 8 — data quality).
  • Gold / Curated: dữ liệu đã mô hình hoá theo nghiệp vụ — fact/dimension theo Kimball, bảng tổng hợp, hoặc One Big Table phục vụ dashboard/ML. Đây là lớp người dùng cuối và công cụ BI truy cập.

Staging là gì và khác gì với các lớp

Staging dễ gây nhầm vì từ này mang hai nghĩa tuỳ ngữ cảnh:

  • Staging kiểu ETL cổ điển: vùng đệm tạm thời, thường bị xoá sau mỗi lần chạy, để giữ dữ liệu extract ra trong lúc engine đang transform. Nó là bộ nhớ tạm, không phải lớp lưu trữ lâu dài.
  • Staging kiểu dbt/ELT: một tầng model đầu tiên (thư mục staging/) làm sạch tối thiểu và đổi tên cột từ mỗi source — 1 model staging ↔ 1 bảng nguồn. Nó đứng giữa raw và các model nghiệp vụ, đóng vai "giao diện chuẩn hoá" cho nguồn để phần logic phía sau không phụ thuộc trực tiếp vào tên cột thô của hệ nguồn. Về vị trí, staging của dbt gần với đầu lớp silver.

Điểm chung: staging là vùng chuyển tiếp, không phải đích cuối. Đừng để BI trỏ thẳng vào staging.

ELT trong thực tế với dbt/SQL

Với ELT, mỗi phép transform là một câu SQL SELECT khai báo "bảng này được dẫn xuất thế nào từ bảng kia". dbt quản lý các câu SELECT đó như code (version control, test, tài liệu, và tự suy ra thứ tự chạy theo phụ thuộc). Ví dụ một model silver làm sạch giao dịch thẻ từ bronze:

-- models/silver/stg_card_transactions.sql
-- Bronze (raw) -> Silver (cleaned): parse, ép kiểu, khử trùng lặp
with raw as (
    select * from {{ source('core_banking', 'card_txn_raw') }}
),

cleaned as (
    select
        cast(txn_id as string)                       as transaction_id,
        cast(card_no as string)                      as card_number,
        cast(amount as numeric)                      as amount_vnd,
        cast(txn_ts as timestamp)                    as transaction_ts,
        upper(trim(mcc_code))                        as merchant_category,
        -- cờ đánh dấu bản ghi lỗi để lớp gold loại ra
        (amount is null or txn_ts is null)           as is_invalid,
        _ingested_at,                                -- metadata từ bronze
        _source_file
    from raw
    -- khử trùng lặp: giữ bản mới nhất theo mỗi transaction_id
    qualify row_number() over (
        partition by txn_id order by _ingested_at desc
    ) = 1
)

select * from cleaned
where not is_invalid

Và một model gold tổng hợp doanh số theo ngày phục vụ báo cáo EOD:

-- models/gold/fct_daily_card_sales.sql
select
    date(transaction_ts)          as sales_date,
    merchant_category,
    count(*)                      as txn_count,
    sum(amount_vnd)               as total_amount_vnd
from {{ ref('stg_card_transactions') }}   -- dbt suy ra: gold phụ thuộc silver
group by 1, 2

{{ ref(...) }} khiến dbt tự dựng đồ thị phụ thuộc (DAG) — nó biết fct_daily_card_sales phải chạy sau stg_card_transactions. Đây chính là orchestration ở mức logic transform, bổ trợ cho orchestrator ở mức pipeline như Airflow.

Một số chi tiết quan trọng của ELT trong thực tế:

  • Idempotency: transform nên chạy lại được nhiều lần cho ra cùng kết quả. Model dbt kiểu table được CREATE OR REPLACE toàn bộ mỗi lần chạy nên idempotent tự nhiên; với dữ liệu lớn dùng model incremental (chỉ xử lý phần mới) — chủ đề của batch 3 — incremental & CDC.
  • Định dạng & phân vùng lưu trữ: hiệu năng ELT phụ thuộc mạnh vào cách lưu bronze/silver — cột hoá (Parquet/ORC), phân vùng theo ngày, thống kê để cắt tỉa (pruning). Đây là nội dung batch 6 — partitioning & I/O.

Đánh đổi: khi nào ETL, khi nào ELT

ELT là mặc định hợp lý cho phần lớn analytics hiện đại, nhưng không phải luôn thắng. Cân nhắc chính:

  • PII và dữ liệu nhạy cảm → nghiêng về ETL (hoặc ELT có kiểm soát). Điểm yếu cố hữu của ELT là dữ liệu thô — gồm cả PII chưa che — đã nằm trong kho ở lớp bronze trước khi bất kỳ transform nào chạy. Với dữ liệu ngân hàng (số thẻ đầy đủ, CMND/CCCD, số dư), nhiều tổ chức cần masking/tokenization sớm để hạn chế phạm vi phơi nhiễm và tuân thủ quy định. Hai hướng xử lý:
    • Chèn một bước ETL nhỏ trước khi load để mã hoá/tokenize các trường nhạy cảm ngay, kho không bao giờ thấy giá trị gốc.
    • Hoặc giữ ELT nhưng khoá chặt truy cập lớp bronze (chỉ pipeline đọc được), che dữ liệu ở lớp silver/gold, kèm mã hoá và column-level access. Xem che & mã hoá dữ liệuphân loại PII.
  • Cần linh hoạt, thử nghiệm nhanh, giữ lịch sử thô → ELT. Vì raw còn nguyên trong kho, khi yêu cầu nghiệp vụ đổi bạn chỉ sửa SQL và backfill lại từ bronze, không phải xin lại dữ liệu nguồn. Đây là lợi thế vận hành lớn nhất của ELT.
  • Engine transform hạn chế / logic quá phức tạp cho SQL → ETL. Nếu transform cần thư viện chuyên biệt (giải mã định dạng lạ, ML feature phức tạp, gọi API làm giàu), một engine như Spark/PySpark bên ngoài phù hợp hơn SQL thuần.
  • Ràng buộc mạng / dữ liệu không được rời vùng → ETL tại nguồn. Khi quy định cấm đưa dữ liệu thô ra khỏi một vùng an ninh, transform (lọc/ẩn danh) phải xảy ra trước.

Thực tế nhiều tổ chức chạy kiểu lai (ELT-with-early-masking): extract → mask PII → load vào bronze đã được ẩn danh một phần → transform bằng SQL cho phần còn lại. "ETL hay ELT" hiếm khi là lựa chọn nhị phân tuyệt đối; nó là câu hỏi đặt bước T nào ở đâu.

Use case thực tế

(Số liệu dưới đây là minh hoạ để hình dung quy mô, không phải số thật của NCB.)

Giả sử NCB cần dựng pipeline báo cáo EOD giao dịch thẻ cho ~5 triệu giao dịch/ngày. Thiết kế ELT với masking sớm:

  1. Ingest/Landing: mỗi đêm, hệ core xuất file giao dịch (Parquet) vào GCS theo phân vùng dt=2026-07-20/.
  2. Bước masking trước load (ETL nhỏ): một job tokenize số thẻ đầy đủ (PAN) thành token không hồi phục, chỉ giữ 6 số đầu + 4 số cuối. Kho không bao giờ chứa PAN đầy đủ.
  3. Bronze: nạp nguyên trạng (đã tokenize) vào bảng bronze.card_txn_raw, thêm _ingested_at, _source_file. Giữ lịch sử để backfill.
  4. Silver (stg_card_transactions): parse, ép kiểu, khử trùng lặp bằng qualify row_number(), loại bản ghi lỗi, gắn nhãn MCC.
  5. Gold (fct_daily_card_sales): tổng hợp doanh số theo ngày × nhóm merchant, phục vụ dashboard vận hành và báo cáo.

Khối lượng ~5 triệu dòng/ngày transform bằng SQL trong warehouse chạy trong ít phút, chi phí compute co giãn theo lần chạy. Khi phòng nghiệp vụ đổi cách phân nhóm merchant sau 3 tháng, đội dữ liệu chỉ sửa model gold và backfill 90 ngày từ bronze — không cần đụng hệ core hay xin lại dữ liệu.

Ghi nhớ

  • ETL vs ELT khác nhau ở vị trí bước Transform: trước khi load (ETL) hay sau khi load, ngay trong kho (ELT).
  • ELT lên ngôi nhờ cloud warehouse/lakehouse: tách storage/compute, storage rẻ, compute co giãn, và SQL đủ mạnh làm engine transform.
  • Lợi ích cốt lõi của ELT là giữ lại dữ liệu thô trong kho (lớp bronze) → replay/backfill dễ khi logic đổi.
  • Pipeline batch trưởng thành đi theo các lớp: ingest/landing → bronze/raw → silver/cleaned → gold/curated (medallion).
  • Staging là vùng chuyển tiếp, không phải đích; nghĩa của nó khác nhau giữa ETL cổ điển và dbt/ELT.
  • dbt biến ELT thành SQL + ref() với DAG phụ thuộc, test và tài liệu; transform nên idempotent.
  • Đánh đổi chính: ETL/masking sớm cho PII (dữ liệu ngân hàng), ELT cho linh hoạt và giữ lịch sử; thực tế thường là lai.

Nguồn tham khảo

Bài viết liên quan

So sánh các định dạng dữ liệu (CSV, JSON, XML, Avro, Parquet, ORC) và lý do lưu theo cột nhanh hơn cho phân tích. Bài đi sâu vào row vs columnar storage, nén (Snappy/gzip/zstd), schema evolution, OLTP vs OLAP, object storage và partitioning để tối ưu chi phí lẫn tốc độ truy vấn.

13 thg 7, 2026 10

Data Engineering là ngành xây dựng và vận hành hệ thống biến dữ liệu thô thành dữ liệu sạch, tin cậy, sẵn sàng cho phân tích và AI. Bài giới thiệu vai trò Data Engineer trong vòng đời dữ liệu (nguồn → ingestion → storage → transformation → serving), phân biệt với Analyst/Scientist/ML Engineer, bức tranh hệ sinh thái công cụ và bài toán đưa dữ liệu core banking sang kho phân tích.

13 thg 7, 2026 9

Stream processing là gì, khác biệt batch vs stream (bounded/unbounded), micro-batch (Spark) vs true streaming, Apache Flink là gì và định vị so với Spark Structured Streaming và Kafka Streams. Kiến trúc runtime JobManager/TaskManager, các tầng API, triết lý streaming-first và bối cảnh phát hiện gian lận ngân hàng.

13 thg 7, 2026 8

Vì sao một máy không đủ và cần xử lý phân tán: từ MapReduce, Hadoop/HDFS đến Apache Spark in-memory. Kiến trúc driver–executor–cluster manager, các mức trừu tượng RDD/DataFrame/Dataset, cơ chế lazy evaluation với DAG, và vì sao shuffle (wide dependency) là phần tốn kém nhất. Kèm PySpark, Spark SQL và các kỹ thuật tối ưu (partition, broadcast join, cache, chống skew) cùng khi nào KHÔNG nên dùng Spark.

13 thg 7, 2026 7

Cảm nhận của bạn

Bình luận

Bạn cần để viết bình luận.

Chưa có bình luận. Hãy là người đầu tiên chia sẻ!