Batch 1 — Mô hình xử lý theo lô & khi nào dùng

22 thg 7, 2026 3 lượt xem
#orchestration
#eod
#etl
#data-engineering
#elt
#batch-processing

Mô hình tinh thần: batch là "chụp một khối, xử một lần"

Trước khi đi vào định nghĩa, hãy giữ một hình ảnh trong đầu: batch processing giống như gom cả ngày giao dịch lại rồi tối đến mới ngồi tính sổ một lượt, thay vì tính lại toàn bộ sổ sách mỗi lần có một giao dịch mới. Bạn chờ dữ liệu tích luỹ thành một khối, khoá khối đó lại (không còn thay đổi nữa), rồi chạy một quy trình xử lý trên toàn khối. Xong thì ghi kết quả ra, kiểm tra, và đợi khối tiếp theo.

Đây là mô hình xử lý dữ liệu lâu đời và phổ biến nhất trong doanh nghiệp — và trong ngân hàng thì gần như mọi thứ "chốt sổ" đều là batch: chạy EOD (End-of-Day), sinh sao kê, tính lãi, phân loại nợ, đối chiếu (reconciliation). Lý do batch bền bỉ không phải vì nó cũ kỹ, mà vì với rất nhiều bài toán, xử theo lô là cách đúng, rẻ và dễ kiểm soát nhất.

Bài này là bài mở màn cho series Xử lý Batch & ETL/ELT quy mô lớn gồm 9 bài. Mục tiêu của bài: cho bạn bản đồ tổng thể — batch là gì, khác streaming ở đâu, khi nào nên chọn, và một job batch "sống" qua những giai đoạn nào — để các bài sau đào sâu từng mảnh.

Series này nói về nguyên lý cross-cutting, không phụ thuộc một công cụ cụ thể. Khi cần công cụ, ta cross-link tới series chuyên sâu tương ứng: Spark, PySpark, Airflow. Song song còn có series xử lý luồng thời gian thực để bạn thấy hai nửa của bức tranh.

Batch processing là gì

Batch processing là mô hình xử lý trong đó dữ liệu được tích luỹ thành từng lô (batch) rồi xử lý một lần theo lịch hoặc theo trigger. Ba đặc điểm định nghĩa:

  1. Dữ liệu tích luỹ theo thời gian: giao dịch, log, file được gom lại trong một cửa sổ (một giờ, một ngày) trước khi xử lý.
  2. Xử lý khởi động theo lịch hoặc trigger: chạy lúc 23:00 mỗi ngày (theo lịch/schedule), hoặc khi "file đã đến đủ" (event-trigger), chứ không xử lý ngay khi từng bản ghi xuất hiện.
  3. Làm việc trên dữ liệu bị chặn (bounded): tại thời điểm chạy, lô dữ liệu có điểm đầu và điểm cuối rõ ràng — biết chính xác mình đang xử bao nhiêu bản ghi.

Điểm cuối cùng là mấu chốt phân biệt với streaming. Streaming làm việc trên unbounded data — một dòng vô tận không bao giờ "kết thúc"; còn batch luôn có một khối hữu hạn, đã đóng, để xử.

Batch vs micro-batch vs streaming

Ba mô hình này không phải "cái nào tốt hơn" mà nằm trên một trục đánh đổi giữa độ trễ (latency), thông lượng (throughput)độ phức tạp vận hành. Hiểu trục này là hiểu 80% chuyện chọn kiến trúc.

  • Batch thuần: xử lô lớn theo lịch. Độ trễ cao (phút → giờ → ngày) nhưng thông lượng trên mỗi đồng chi phí cao nhất, và mô hình lập trình đơn giản nhất. Ví dụ: EOD chạy 1 lần/đêm.
  • Micro-batch: chia dòng dữ liệu thành các lô rất nhỏ, xử liên tục cách nhau vài giây → vài phút. Là "batch chạy lặp rất nhanh". Đây là mô hình của Spark Structured Streaming ở chế độ mặc định. Độ trễ trung bình, tận dụng lại được tư duy batch.
  • Streaming thuần (record-by-record): xử từng sự kiện ngay khi đến, độ trễ dưới giây. Đổi lại phải quản lý state, watermark, xử lý dữ liệu đến trễ, exactly-once — phức tạp hơn hẳn. Đây là địa hạt của Flink và series streaming.
Tiêu chíBatchMicro-batchStreaming
Độ trễ điển hìnhphút → ngàygiây → phútmili-giây → giây
Biên dữ liệubounded"cắt lát" unboundedunbounded
Thông lượng/chi phícao nhấtcaothấp hơn
Độ phức tạp vận hànhthấptrung bìnhcao
Tái chạy (re-run)rất dễvừakhó (cần replay state)
Ví dụ ngân hàngEOD, sao kê, tính lãicập nhật dashboard mỗi phútphát hiện gian lận thẻ tức thời

Ranh giới không cứng: một hệ thống thực tế thường lai — streaming cho cảnh báo gian lận, batch cho báo cáo quy định. Chuyện chọn kiến trúc lai (Lambda/Kappa) sẽ được bàn trong series streaming.

Đặc trưng của batch: vì sao nó "dễ sống"

Batch có mấy đặc trưng kỹ thuật khiến nó đặc biệt dễ vận hành — và đây chính là lý do nó vẫn thống trị các workload chốt sổ:

  • Bounded data (dữ liệu hữu hạn, bất biến): lô đã chốt thì không đổi. Điều này khiến kết quả tất định (deterministic) — chạy lại trên cùng lô cho cùng kết quả, cực kỳ quý cho kiểm toán ngân hàng.
  • Thông lượng cao: xử cả khối lớn cùng lúc cho phép engine tối ưu — đọc tuần tự, xử song song theo partition, gom I/O — đạt hiệu suất trên mỗi CPU/đồng chi phí tốt hơn xử lẻ từng bản ghi.
  • Tái chạy dễ (re-runnable): nếu job lỗi lúc 2h sáng, bạn chỉ cần chạy lại lô đó — miễn là job được thiết kế idempotent (chạy 2 lần cho kết quả như chạy 1 lần). Đây là nền tảng cho backfill và là chủ đề riêng của bài idempotency.
  • Cửa sổ xử lý rõ ràng: batch thường có "batch window" — khoảng thời gian được phép chạy (ví dụ 23:00–05:00). Dễ lập lịch, dễ dành riêng tài nguyên, dễ đặt SLA.

Khi nào chọn batch

Chọn batch khi độ trễ không phải yêu cầu, nhưng thông lượng, chi phí và tính đúng đắn/kiểm toán là ưu tiên. Cụ thể:

  • Báo cáo cuối ngày (EOD) / cuối kỳ: số dư cuối ngày, sao kê tháng, báo cáo quản trị — bản chất chỉ có nghĩa khi "chốt sổ", nên xử theo lô là đúng bản chất nghiệp vụ.
  • ETL/ELT nạp kho dữ liệu: nạp dữ liệu định kỳ vào kho dữ liệu / lakehouse, xây bảng fact/dimension cho BI. Đây là use case batch kinh điển — bài tiếp theo ETL vs ELT đào sâu.
  • Tính toán nặng, phức tạp: mô hình rủi ro, tính lãi kép toàn danh mục, phân loại nợ (nhóm 1–5) trên hàng triệu khoản vay — cần quét toàn bộ dữ liệu, không hợp với xử từng bản ghi.
  • Tích hợp hệ thống theo file: nhiều core banking, hệ thống thẻ vẫn trao đổi bằng file cuối ngày; batch là cách tự nhiên để nuốt các file này.

Ngược lại, đừng chọn batch khi nghiệp vụ đòi phản ứng trong vài giây (chặn giao dịch gian lận, cảnh báo thấu chi tức thời, cá nhân hoá thời gian thực) — đó là lúc dùng streaming.

Vòng đời một job batch: Extract → Transform → Load → Verify

Một job batch không chỉ là "chạy SQL". Nó là một quy trình có các giai đoạn rõ ràng, và mỗi giai đoạn có thể lỗi độc lập, nên cần điểm kiểm tra riêng. Bốn giai đoạn cốt lõi:

  1. Extract — trích dữ liệu từ nguồn: đọc file EOD, query bản ghi trong cửa sổ, hoặc lấy delta qua incremental/CDC. Mục tiêu: chốt đúng phạm vi lô.
  2. Transform — biến đổi: làm sạch, chuẩn hoá kiểu, join tra cứu, tính các chỉ tiêu. Đây là nơi logic nghiệp vụ nằm.
  3. Load — ghi kết quả vào đích. Bước này phải idempotent và tốt nhất là atomic — hoặc thấy toàn bộ lô mới, hoặc không thấy gì, không có trạng thái "một nửa".
  4. Verify — kiểm chứng trước khi công bố: đếm số bản ghi, đối chiếu tổng số dư khớp nguồn, kiểm ràng buộc (không null khoá chính, không âm số dư). Chỉ khi verify đạt mới đánh dấu lô là "chính thức". Chủ đề chất lượng dữ liệu sẽ mở rộng bước này.

Một pseudocode rất rút gọn cho khung một job batch idempotent theo ngày:

# Khung job batch theo ngày (minh hoạ) — idempotent theo partition ngày
def run_batch(business_date):
    # 1) EXTRACT: chốt đúng lô của business_date
    raw = source.read(where=f"txn_date = '{business_date}'")

    # 2) TRANSFORM: làm sạch + tính chỉ tiêu nghiệp vụ
    clean = (raw
             .dropna(subset=["account_id", "amount"])
             .with_column("amount", cast_decimal("amount"))
             .join(dim_account, on="account_id", how="left"))

    # 3) LOAD: ghi idempotent — xoá đúng partition ngày rồi ghi lại
    #    chạy lại cùng business_date -> cùng kết quả (an toàn re-run)
    target.overwrite_partition(partition=business_date, data=clean)

    # 4) VERIFY: không đạt thì raise -> orchestrator giữ lô ở trạng thái chưa publish
    assert target.count(business_date) == raw.valid_count(), "Lệch số bản ghi"
    assert target.sum("amount", business_date) == raw.control_total(), "Lệch control total"

Ghi chú kỹ thuật quan trọng: mẫu "overwrite đúng partition của ngày" (thay vì append mù) là cách phổ biến nhất để job batch trở nên idempotent — chạy lại một ngày không tạo bản ghi trùng. Đây là cầu nối tới bài idempotencypartitioning.

Bản đồ series: 9 bài

Lộ trình 9 bài của series:

  1. Batch 1 — Mô hình xử lý theo lô & khi nào dùng (bài này) — bản đồ tổng thể, batch vs streaming, vòng đời job.
  2. Batch 2 — ETL vs ELT — hai triết lý biến đổi trước/sau khi nạp, khi nào dùng cái nào.
  3. Batch 3 — Nạp tăng dần & CDC — high-water-mark, watermark, Change Data Capture để chỉ xử phần thay đổi.
  4. Batch 4 — Idempotency & exactly-once — thiết kế để chạy lại an toàn, at-least-once vs exactly-once.
  5. Batch 5 — Backfill & reprocessing — nạp lại lịch sử, sửa dữ liệu sai mà không phá downstream.
  6. Batch 6 — Partitioning & tối ưu I/O — chia partition, file sizing, đọc ít quét ít.
  7. Batch 7 — Orchestration DAG — điều phối phụ thuộc, retry, lịch — liên hệ Airflow.
  8. Batch 8 — Chất lượng dữ liệu — kiểm thử, đối chiếu, cổng chất lượng trước khi publish.
  9. Batch 9 — EOD ngân hàng — ghép tất cả lại thành pipeline chốt sổ cuối ngày.

Use case thực tế

Bối cảnh (minh hoạ, số liệu giả định): NCB cần sinh báo cáo EOD cho ~3 triệu tài khoản mỗi đêm — tính số dư cuối ngày, phân loại nợ, và chuẩn bị dữ liệu sao kê. Yêu cầu: xong trước 05:00 để chi nhánh mở cửa 08:00 có số liệu chuẩn.

Vì sao batch là lựa chọn đúng ở đây:

  • Nghiệp vụ vốn theo lô: "số dư cuối ngày" chỉ có nghĩa sau khi thị trường/hệ thống đóng cửa — không có nhu cầu tính lại mỗi giao dịch.
  • Cửa sổ rõ ràng: batch window 23:30–05:00, dành riêng tài nguyên cụm Spark, không tranh chấp với hệ thống giao dịch ban ngày.
  • Tái chạy an toàn: đêm nào file core về trễ hoặc job lỗi giữa chừng, đội vận hành chỉ cần chạy lại đúng partition business_date — nhờ thiết kế idempotent, không lo số liệu nhân đôi.
  • Kiểm toán được: mỗi lô bất biến, có control total đối chiếu với core, đạt yêu cầu truy vết của thanh tra.

Con số minh hoạ: xử 3 triệu tài khoản + ~40 triệu giao dịch trong ~90 phút, verify 15 phút, publish lúc ~04:00 — còn dư biên an toàn trước hạn 05:00. Nếu cùng bài toán mà ép chạy streaming từng bản ghi, chi phí hạ tầng và độ phức tạp state sẽ tăng vọt mà không mang lại giá trị nghiệp vụ nào — vì không ai cần số dư cuối ngày ở độ trễ mili-giây.

Ghi nhớ

  • Batch = tích luỹ thành lô hữu hạn (bounded) rồi xử một lần theo lịch hoặc trigger; đối lập với streaming xử từng sự kiện trên dòng vô tận (unbounded).
  • Batch, micro-batch, streaming nằm trên trục đánh đổi độ trễ ↔ thông lượng/đơn giản — không có cái "tốt nhất" tuyệt đối, chỉ có cái hợp yêu cầu độ trễ.
  • Chọn batch khi độ trễ không gấp mà thông lượng, chi phí, tính đúng đắn/kiểm toán là ưu tiên: EOD, ETL kho dữ liệu, tính toán nặng.
  • Đặc trưng khiến batch "dễ sống": dữ liệu bất biến → kết quả tất định; thông lượng cao; tái chạy dễ nếu thiết kế idempotent.
  • Một job batch có vòng đời Extract → Transform → Load → Verify; mỗi giai đoạn lỗi độc lập, phải có kiểm tra trước khi công bố lô.
  • Mẫu overwrite đúng partition ngày là chìa khoá cho idempotency — chạy lại không tạo bản ghi trùng.
  • Đừng ép streaming vào bài toán vốn là batch: sẽ trả giá bằng độ phức tạp state/watermark mà không thêm giá trị nghiệp vụ.

Nguồn tham khảo

  • Fundamentals of Data Engineering — Joe Reis & Matt Housley (O'Reilly): chương về batch vs streaming và vòng đời pipeline.
  • Designing Data-Intensive Applications — Martin Kleppmann (O'Reilly): Chương 10 "Batch Processing" và Chương 11 "Stream Processing".
  • Streaming Systems — Tyler Akidau, Slava Chernyak, Reuben Lax (O'Reilly): mô hình bounded vs unbounded data, quan hệ batch–stream.
  • Apache Spark — tài liệu chính thức: https://spark.apache.org/docs/latest/
  • Apache Airflow — tài liệu chính thức (lập lịch & điều phối job batch): https://airflow.apache.org/docs/
  • Google Cloud Dataflow/Beam model paper — Akidau et al., VLDB 2015 (mô hình thống nhất batch & streaming).
  • "Questioning the Lambda Architecture" — Jay Kreps (O'Reilly Radar): góc nhìn về khi nào cần batch riêng.

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ẻ!