본문 바로가기
C.W.K.
Stream
Lesson 02 of 05 · published

Apache Airflow — DAG, Operator, Scheduler

~16 min · airflow, orchestration

Level 0구경꾼
0 XP0/47 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

많은 production 팀의 default

Apache Airflow (2026.8 기준 3.3) 는 세계에서 가장 많이 배포된 orchestrator 야. 2014년 Airbnb 에서 태어나 2019년 Apache top-level project 가 됐고, Lyft, Stripe, Netflix, Spotify — 이름을 들어 봤을 법한 "data platform team" 의 production 파이프라인이 거의 다 이 위에서 돌아. 모델은 task 의 DAG — Directed Acyclic Graph.

Airflow 3 은 건너뛸 수 있는 버전이 아냐

Airflow 3.0 이 2025년 4월에 나오면서 두 가지가 한꺼번에 무효가 됐어. 사람들이 복사해 돌리던 DAG 파일, 그리고 그 이전에 쓰인 모든 글의 배포 구성도. 2.x 자료로 Airflow 를 배웠다면 — 인터넷에 남아 있는 자료는 아직도 대부분 2.x 야 — 여기가 중요한 부분이야.

  • DAG 작성이 airflow.sdk 로 옮겨 갔어. from airflow.decorators import dag, task 는 아직 돌아가고 deprecation 경고를 뱉어. 이제 안정된 인터페이스는 from airflow.sdk import dag, task 야. 밑에서는 task 실행이 client-server 로 갈라졌고, 그게 Python 아닌 task 런타임을 가능하게 만든 변화야.
  • DAG versioning. Run 은 시작할 때의 DAG 버전으로 끝까지 가. 도는 중에 파일을 고쳐도 실행 중인 파이프라인이 하는 일이 소리 없이 바뀌지 않아 — 프로젝트 자체 설문에서 가장 많이 요청된 기능이었어.
  • Dataset 이 Asset 이 됐고, 스케줄링이 event-driven 이 됐어. 이제 DAG 은 시계가 움직여서만이 아니라 Airflow 바깥의 asset 이 바뀌어서도 깨어날 수 있어.
  • 아예 사라진 것들: SubDAG (TaskGroup 써), SLA (Deadline Alert 로 대체), Sequential Executor, 그리고 execution_date / tomorrow_ds / yesterday_ds 계열 context 변수 전부. 살아남은 건 logical_date.
  • 기본값이 뒤집혔어: catchup_by_default 가 이제 False 야. 새 DAG 을 올렸다고 과거 run 이 떼로 몰려오지 않아.

구성 요소

  • API server — REST API 와 새로 만든 React UI 를 서빙. 예전에 webserver 라고 부르던 게 이거야.
  • Scheduler — 뭐가 돌 차례인지 정하고 executor 에 task 를 넘겨.
  • DAG processor — DAG 파일을 파싱해서 DB 에 직렬화. Airflow 3 에선 필수 독립 프로세스야. 규모 커지면 켜는 선택지가 아니라.
  • 메타데이터 DB — production 에선 Postgres.
  • Worker, 그리고 deferred task 용 triggerer — executor 선택에 따라 선택 사항.

Airflow 2 보다 필수 부품이 하나 더 늘었다는 뜻이야. Dagster 와 Prefect 가 깎아내리는 마찰이 바로 이거고, Airflow 3 은 그 간격을 좁힌 게 아니라 벌렸어. 거래의 모양은 그대로고 기울기만 가팔라진 거지. Airflow 는 두 경쟁자보다 세우는 비용이 크고, 그걸 돌려받게 해 주는 게 ecosystem (커뮤니티가 관리하는 provider 패키지 80개 이상, 그리고 이 분야에서 제일 큰 커뮤니티) 이야.

Code

Airflow 3 DAG — airflow.sdk 에서 가져온 @task API·python
from datetime import datetime, timedelta
from airflow.sdk import dag, task

@dag(
    dag_id='orders_pipeline',
    schedule='0 3 * * *',
    start_date=datetime(2026, 8, 1),
    catchup=False,          # Airflow 3 의 기본값이지만 명시해 두는 게 나아
    default_args={'retries': 3, 'retry_delay': timedelta(minutes=5)},
    tags=['orders', 'analytics'],
)
def orders_pipeline():

    @task
    def extract(ds: str) -> str:
        # ds 는 logical date, YYYY-MM-DD. logical date 가 있는 run 에만 존재해.
        # Airflow 3 에선 logical_date 가 None 일 수 있고 — asset 이 깨운 run 과
        # 손으로 trigger 한 run 이 그 경우야.
        path = f'raw/orders/{ds}.json'
        # ... 실제 fetch + write ...
        return path

    @task
    def transform(raw_path: str, ds: str) -> str:
        out_path = f'warehouse/orders/date={ds}/'
        # ... raw_path 읽고, transform, out_path 에 Parquet ...
        return out_path

    @task
    def validate(parquet_path: str) -> None:
        # ... pandera schema 검증 ...
        return None

    raw = extract('{{ ds }}')
    out = transform(raw, '{{ ds }}')
    validate(out)

orders_pipeline()

External links

Exercise

Docker 가 가능하면 Astronomer CLI 로 astro dev start 해서 local Airflow 를 띄워. 토이 데이터셋으로 3-task DAG (extract → transform → validate) 를 airflow.sdk 에서 import 해서 짜 봐. UI 에서 trigger 하고, task instance 가 도는 걸 보고, 실패를 클릭해서 로그까지 들어가. 목표는 이 loop 를 몸으로 느끼는 거야 — Airflow 의 가치는 scheduler 보다 visibility 쪽에 있거든.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.