Airflow 1 — Tổng quan & kiến trúc (Airflow 3.x)
Airflow là gì — và không phải là gì
Apache Airflow là một orchestrator (bộ điều phối) workflow: nó chịu trách nhiệm lập lịch (schedule), kích hoạt (trigger), theo dõi (monitor) và phối hợp phụ thuộc (dependency) giữa các bước công việc trong một quy trình dữ liệu. Điểm cốt lõi cần khắc sâu ngay từ đầu: Airflow không phải là công cụ xử lý dữ liệu. Nó không thay thế Spark, không thay thế một warehouse, không tự mình biến đổi hàng terabyte dữ liệu. Airflow là "nhạc trưởng" — nó ra lệnh cho từng nhạc công (Spark job, câu lệnh SQL trên BigQuery, một script Python, một lệnh gọi API) chơi đúng lúc, đúng thứ tự, và báo lại khi ai đó chơi sai.
Sự phân biệt này không phải chuyện chữ nghĩa. Rất nhiều đội mắc sai lầm khi nhồi logic xử lý nặng bên trong task Airflow — đọc DataFrame khổng lồ vào bộ nhớ của worker, join, ghi ra. Cách làm đúng là để Airflow đẩy công việc (push down) xuống hệ thống chuyên xử lý: gửi job sang cụm Spark, submit query xuống warehouse, trigger một dbt run. Worker Airflow chỉ nên làm việc nhẹ: gọi lệnh, chờ kết quả, kiểm tra trạng thái. Khi bạn giữ đúng ranh giới này, Airflow trở nên cực kỳ đáng tin cậy và dễ mở rộng.
Đơn vị mô hình hoá của Airflow là DAG — Directed Acyclic Graph, đồ thị có hướng không chu trình. Mỗi node là một task (một đơn vị công việc), mỗi cạnh là một quan hệ phụ thuộc ("task B chỉ chạy sau khi task A xong"). "Không chu trình" nghĩa là không có vòng lặp — bạn không thể để A chờ B và B lại chờ A. Cấu trúc DAG cho phép Airflow biết chính xác cái gì có thể chạy song song, cái gì phải chờ, và khi một task fail thì những task phía sau nào bị chặn.
"Pipeline as code" — vì sao điều này quan trọng
Triết lý nền tảng của Airflow là pipeline as code: bạn định nghĩa toàn bộ workflow bằng Python, không phải bằng giao diện kéo-thả hay file cấu hình tĩnh. Nghe qua có vẻ chỉ là chi tiết kỹ thuật, nhưng hệ quả rất sâu:
- Versioning & code review: pipeline nằm trong Git. Mọi thay đổi đều có lịch sử, có diff, có pull request, có review. Bạn rollback được.
- Dynamic generation: vì DAG là code Python, bạn có thể sinh task bằng vòng lặp, đọc cấu hình từ file, tạo pipeline theo tham số. Một đoạn code ngắn có thể sinh ra hàng trăm task theo danh sách bảng cần load.
- Testability: bạn viết unit test cho logic sinh DAG, kiểm tra cấu trúc phụ thuộc trước khi deploy.
- Reusability: tách logic thành hàm, module, operator tuỳ biến — tái sử dụng khắp các pipeline.
Đây là điểm phân biệt Airflow với các công cụ lập lịch dạng GUI: bạn có toàn bộ sức mạnh của một ngôn ngữ lập trình và toàn bộ hệ sinh thái kỹ thuật phần mềm (CI/CD, test, linting) áp lên chính các pipeline dữ liệu của mình.
Kiến trúc Airflow 3
Airflow 3.x (GA tháng 4/2025) là một bước ngoặt kiến trúc: chuyển sang mô hình service-oriented (hướng dịch vụ), tách bạch các thành phần rõ ràng hơn hẳn Airflow 2. Dưới đây là các thành phần chính.
API server (FastAPI). Đây là thay đổi lớn nhất về mặt vận hành. Airflow 3 thay thế webserver Flask cũ bằng một API server viết trên FastAPI. API server phục vụ hai vai trò: (1) là backend cho UI React mới cùng REST API công khai, và (2) — quan trọng hơn — là điểm truy cập trung tâm cho Task Execution API mà các worker dùng để giao tiếp với hệ thống.
Scheduler. Bộ não lập lịch. Scheduler đọc trạng thái các DAG đã được parse, quyết định task nào đủ điều kiện chạy (phụ thuộc đã thoả, đến đúng thời điểm lịch), và đẩy chúng vào hàng để executor thực thi. Scheduler cũng theo dõi và cập nhật trạng thái các DAG run và task instance.
DAG processor. Trong Airflow 2, việc parse file DAG mặc định chạy bên trong tiến trình scheduler (tuỳ chọn tách ra được). Airflow 3 chuẩn hoá việc tách DAG processor thành tiến trình riêng. Đây là quyết định về cả hiệu năng lẫn bảo mật: parse code Python người dùng viết là hoạt động tiềm ẩn rủi ro và tốn CPU; tách nó khỏi scheduler giúp scheduler ổn định hơn và cô lập code người dùng khỏi lõi lập lịch.
Workers / Executor. Executor là lớp trừu tượng quyết định task chạy ở đâu và như thế nào — trên local, trên một pool tiến trình, hay trên Celery/Kubernetes. Worker là tiến trình thực sự thực thi task. (Chi tiết về các loại executor và cách scale, xem bài Executors & scaling.)
Triggerer. Tiến trình chạy các deferrable operator — task kiểu "chờ đợi" (chờ file xuất hiện, chờ một job bên ngoài xong). Thay vì chiếm một worker slot để bận rộn poll liên tục, task có thể "defer" (nhường chỗ): nó đăng ký một trigger async chạy trên triggerer bằng asyncio, giải phóng worker slot, và chỉ được đánh thức khi điều kiện thoả. Với các pipeline có nhiều bước chờ, đây là khoản tiết kiệm tài nguyên rất lớn.
Metadata Database. Cơ sở dữ liệu quan hệ (Postgres hoặc MySQL) lưu toàn bộ trạng thái: định nghĩa DAG, DAG run, task instance, XCom, connection, variable, log ghi chú, quyền... Đây là "nguồn sự thật" (source of truth) của toàn hệ thống.
Điểm mấu chốt của Airflow 3: Task Execution API + Task SDK
Đây là thay đổi kiến trúc có ý nghĩa nhất và đáng để hiểu kỹ. Trong Airflow 2, worker khi chạy task sẽ truy cập trực tiếp metadata DB — mở kết nối tới Postgres/MySQL để đọc cấu hình, ghi trạng thái, đọc/ghi XCom. Điều này có ba vấn đề: worker phải có credential DB (rủi ro bảo mật), worker phải nằm cùng mạng với DB (khó chạy remote), và mọi worker đều tạo tải kết nối trực tiếp lên DB.
Airflow 3 phá vỡ mô hình đó bằng Task Execution API. Giờ đây worker không còn chạm vào metadata DB trực tiếp. Thay vào đó, worker giao tiếp với hệ thống qua một REST API (do API server phục vụ), được xác thực bằng JWT. Phía worker, code task chạy thông qua Task SDK — một giao diện lập trình ổn định, tách rời khỏi lõi Airflow. Hệ quả thực chiến:
- Chạy remote / đa cloud / edge: worker chỉ cần gọi được HTTP tới API server là đủ; nó có thể nằm ở cloud khác, ở edge, sau firewall — không cần đường mạng tới DB.
- Bảo mật hơn: worker không giữ credential DB; bề mặt tấn công thu hẹp lại quanh một API có xác thực JWT rõ ràng.
- Hợp đồng ổn định & đa ngôn ngữ: Task Execution API là một "contract" ổn định, mở đường cho task viết bằng ngôn ngữ khác Python trong tương lai.
Điểm cần đọc kỹ trong sơ đồ: mũi tên từ Workers không đi thẳng vào Metadata DB nữa, mà đi qua API server bằng REST + JWT. Đó chính là ranh giới an toàn mới của Airflow 3. Scheduler, DAG processor và API server (control plane) vẫn nói chuyện với DB; còn lớp thực thi (workers, triggerer) thì bị đẩy ra sau một API.
Một DAG tối giản (minh hoạ)
Dưới đây là một DAG viết theo phong cách hiện đại (TaskFlow API) — Python thuần, hàm được trang trí thành task, phụ thuộc suy ra từ cách gọi hàm. Đoạn code chỉ mang tính minh hoạ.
# minh hoạ — dags/daily_sales.py
from __future__ import annotations
import pendulum
from airflow.sdk import dag, task # Task SDK (Airflow 3.x)
@dag(
schedule="0 6 * * *", # 06:00 mỗi ngày (cron)
start_date=pendulum.datetime(2025, 1, 1, tz="Asia/Ho_Chi_Minh"),
catchup=False, # không backfill quá khứ khi bật DAG
tags=["sales", "etl"],
)
def daily_sales():
@task
def extract() -> dict:
# thực chiến: chỉ gọi API / trigger job, không xử lý nặng ở đây
return {"rows": 1280, "date": "2025-06-30"}
@task
def transform(payload: dict) -> int:
# push-down thật sự nên nằm ở Spark / warehouse
return payload["rows"]
@task
def load(row_count: int) -> None:
print(f"Đã nạp {row_count} dòng vào bảng đích")
# phụ thuộc suy ra từ luồng gọi hàm: extract -> transform -> load
load(transform(extract()))
daily_sales()
Vài điểm đáng lưu ý: schedule nhận cả cron lẫn các định nghĩa hướng sự kiện; catchup=False ngăn Airflow tự chạy bù toàn bộ khoảng thời gian trong quá khứ khi bạn bật DAG — một cái bẫy kinh điển với người mới. Chi tiết về task, phụ thuộc, XCom, operator sẽ có trong bài DAG & Task.
Airflow 2 so với Airflow 3
Nếu bạn đến từ Airflow 2, đây là những khác biệt cần nắm:
- Kiến trúc hướng dịch vụ: API server (FastAPI) thay webserver Flask; DAG processor tách riêng theo mặc định; worker giao tiếp qua Task Execution API thay vì chạm DB trực tiếp.
- DAG versioning: Airflow 3 theo dõi phiên bản của DAG. Khi bạn sửa code, các DAG run cũ vẫn giữ đúng cấu trúc phiên bản của chúng — giúp truy vết và debug lịch sử chuẩn xác hơn.
- Datasets đổi tên thành Assets + scheduling hướng sự kiện: khái niệm "dataset" của Airflow 2 nay là Asset, và mô hình lập lịch dựa trên cập nhật asset được mở rộng thành event-driven scheduling (DAG chạy khi một asset được cập nhật, không chỉ theo lịch giờ). Xem bài Scheduling & Assets.
- Bỏ SubDAG: SubDAG (vốn hay gây deadlock và khó vận hành) bị loại bỏ; dùng TaskGroup thay thế.
- Bỏ SequentialExecutor và DebugExecutor.
- UI làm lại hoàn toàn trên nền React.
execution_datebị bỏ hẳn: khái niệm gây nhầm lẫn kinh niên này được thay bằnglogical_datevà mô hình data interval (khoảng dữ liệu mà một DAG run chịu trách nhiệm) rõ ràng hơn.
Đây là các thay đổi phá vỡ tương thích (breaking), nên việc nâng cấp từ 2 lên 3 cần được lên kế hoạch — không phải chỉ đổi số phiên bản. Chủ đề nâng cấp và vận hành production được bàn ở bài Vận hành production.
Khi nào nên — và không nên — dùng Airflow
Nên dùng Airflow khi:
- Batch ETL/ELT theo lịch: nạp dữ liệu hằng đêm/hằng giờ, chạy transform trên warehouse, refresh model — đúng "sân nhà" của Airflow.
- Phụ thuộc phức tạp: quy trình nhiều bước với nhánh, điều kiện, fan-in/fan-out, cần biết bước nào chặn bước nào khi có sự cố.
- Cần backfill: chạy lại pipeline cho một khoảng thời gian trong quá khứ (ví dụ vừa sửa logic transform, cần tính lại 30 ngày) — Airflow xử lý việc này bài bản qua data interval.
- Điều phối đa hệ thống: một pipeline chạm vào nhiều nơi (S3, Spark, warehouse, API bên thứ ba) và bạn cần một nơi duy nhất để nhìn toàn cảnh, retry, và cảnh báo.
Không nên dùng Airflow khi:
- Streaming real-time thuần: cần xử lý sự kiện với độ trễ mili-giây, throughput liên tục — hãy dùng Kafka / Flink. Airflow lập lịch theo phút, không phải theo dòng sự kiện liên tục; ép nó làm streaming là dùng sai công cụ.
- Job đơn giản, đơn lẻ: nếu bạn chỉ cần chạy một script mỗi đêm, không phụ thuộc, không cần theo dõi phức tạp — một dòng cron là đủ. Dựng cả cụm Airflow cho việc đó là bổ dao mổ trâu.
- Xử lý dữ liệu nặng bên trong task: như đã nói, đây là lạm dụng. Push-down xuống engine chuyên dụng.
Use case thực tế
Một tình huống điển hình trong ngân hàng / fintech: mỗi sáng cần tổng hợp dữ liệu giao dịch của ngày hôm trước để phục vụ báo cáo và mô hình rủi ro. Pipeline Airflow điển hình sẽ: (1) sensor/deferrable task chờ file dump từ core banking xuất hiện trên object storage (chờ bằng triggerer, không chiếm worker); (2) task submit một Spark job để chuẩn hoá và làm sạch dữ liệu thô; (3) task chạy dbt / SQL trên warehouse để build các bảng mô hình theo lớp; (4) task chạy kiểm tra chất lượng (row count, null, giá trị bất thường) và fail nếu vi phạm ngưỡng; (5) task cập nhật một Asset để kích hoạt các DAG hạ nguồn (dashboard refresh, feature store). Nếu bước 4 fail, Airflow chặn các bước sau, gửi cảnh báo, và cho phép đội trực chạy lại chỉ nhánh bị lỗi. Toàn bộ pipeline này là code trong Git, review được, và backfill được khi cần tính lại quá khứ. Đây chính là chỗ Airflow toả sáng: điều phối, không phải xử lý.
Ghi nhớ
- Airflow là orchestrator ("nhạc trưởng"), không phải công cụ xử lý dữ liệu — luôn push-down việc nặng xuống Spark/warehouse.
- Đơn vị mô hình là DAG (đồ thị có hướng, không chu trình); pipeline được viết bằng Python ("pipeline as code") → versioning, test, review, sinh động (dynamic).
- Kiến trúc Airflow 3: API server (FastAPI) + Scheduler + DAG processor (tách riêng) + Workers/Executor + Triggerer + Metadata DB.
- Thay đổi cốt lõi của Airflow 3: Task Execution API + Task SDK — worker không truy cập metadata DB trực tiếp mà qua REST + JWT → chạy remote/đa cloud/edge, bảo mật hơn.
- Khác Airflow 2: kiến trúc hướng dịch vụ, DAG versioning, Datasets → Assets + event-driven scheduling, bỏ SubDAG, bỏ SequentialExecutor/DebugExecutor, UI React mới, bỏ
execution_date(dùnglogical_date/ data interval). - Dùng Airflow cho batch ETL/ELT theo lịch, phụ thuộc phức tạp, backfill; không dùng cho streaming real-time thuần (→ Kafka/Flink) hay job đơn giản (→ cron).
Bài viết liên quan
CSV/JSON/Parquet/Avro, lưu trữ theo hàng vs cột, nén, và OLTP vs OLAP.
Data Engineering là gì, vai trò trong vòng đời dữ liệu, và bức tranh hệ sinh thái công cụ.
Vì sao xử lý phân tán, mô hình Spark (RDD/DataFrame), lazy evaluation, shuffle và tối ưu.
Đảm bảo chất lượng & minh bạch dữ liệu bằng dbt: data tests dựng sẵn (unique, not_null, relationships, accepted_values), singular test, unit test, và tài liệu tự sinh kèm lineage graph.