Airflow의 철학, 스타일 가이드 + Anti-pattern 톺아보기
[Airflow]Airflow의 철학, 스타일 가이드 + Anti-pattern 톺아보기
Airflow의 철학, 스타일 가이드 + Anti-pattern 톺아보기
Airflow는 워크플로우를 선언적으로 구성하고, 시간 기반으로 안정적이고 재현 가능한 실행을 지향하는 도구임.
대표적으로 DAG작성할 때, 로직 관련된 코드는 따로 분리하는 것이 좋다고 함.
그래서 airflow만들어주신 분들의 뜻을 이어 야무지게 DAG를 짜는 게, 배우는 이의 덕목이므로 고것에 대해 공부해봤음.
- Airflow가 지향하는 철학 및 설계 원칙
- 그 원칙에 맞는 코드 스타일 가이드
- Anti-pattern
1. Airflow의 철학과 설계 원칙
1-1. Orchestration First (조율자 역할)
Airflow는 데이터를 직접 처리하는 도구가 아님. Spark, Python, Bash, dbt 등 외부 연산 도구들을 연결하고 언제 실행할지, 어떤 순서로 실행할지, 성공했는지를 조율하는 게 핵심 목적임.
1-2. 선언적 DAG 구성
Airflow의 DAG은 파이썬으로 작성하지만, 실상은 선언형으로 구성되어야 함. 즉, DAG은 흐름만 설명하고, 내부 로직은 별도 함수/모듈로 분리해서 간결하고 읽기 쉽게 유지해야 함.
1-3. 시간 기반 재현성 (Reproducibility)
Airflow는 매번 실행할 때 execution_date, data_interval_start 등 논리적 시간 기준을 기반으로 작업을 수행함. 이는 과거 데이터를 백필(backfill)하거나 동일한 결과를 반복해서 얻는 데 매우 중요함.
1-4. Task는 멱등성 보장 (Idempotent)
각 Task는 다시 실행해도 같은 결과를 내야 함. 예를 들어, 중복 insert가 발생하면 안 되고, 덮어쓰기 방식이나 upsert 등을 활용해야 함. 재실행에 강한 구조가 필수임.
1-5. 인프라 중립성
Airflow는 로컬, GCP, AWS, Kubernetes 등 다양한 환경에서 동일하게 작동함. DAG 코드 변경 없이 Operator나 Hook 설정만 바꿔서 실행 환경을 유연하게 바꿀 수 있음.
1-6. 템플릿화와 메타데이터 기반 운영
Airflow는 템플릿(Jinja)을 통해 경로, 날짜, 쿼리 등을 유동적으로 설정할 수 있고, 모든 실행 이력은 메타DB에 저장되어 운영/모니터링에 용이함.
2. Airflow 철학에 맞는 코드 스타일 가이드
2-1. DAG은 흐름만, 로직은 분리
# 안 좋은 예
PythonOperator(task_id="run_all", python_callable=lambda: do_all())
DAG 파일에 lambda로 모든 로직을 담으면 테스트도 어렵고 재사용도 불가능함.
# 좋은 예
from tasks.cleanup import clean_old_data
PythonOperator(task_id="clean_data", python_callable=clean_old_data)
로직은 외부 모듈로 분리해서 DAG은 선언적 흐름만 나타냄.
2-2. Task는 멱등성 보장
# 중복 실행 시 중복 insert 발생 가능
insert_to_db(data)
중복 실행 시 데이터베이스에 같은 값이 여러 번 들어갈 수 있음.
# 멱등성 보장
save_to_db(data, mode="overwrite")
재실행 시에도 같은 결과가 나오도록 덮어쓰기나 upsert를 활용함.
2-3. 날짜는 context 기반으로 처리
# 시스템 시간 기준
now = datetime.now()
실행 시점의 현재 시간이 사용되면 백필 등에 문제가 발생함.
# Airflow의 논리적 시간 사용
run_date = context["ds"]
execution_date를 기반으로 작업해야 재현성과 일관성을 확보할 수 있음.
2-4. 경로, 쿼리는 Jinja 템플릿 활용
# 하드코딩된 날짜
bash_command="curl http://api.com/data?date=2024-01-01"
DAG 스케줄과 무관하게 동작해서 유지보수가 어려움.
# 템플릿 활용
bash_command="curl http://api.com/data?date="
스케줄에 맞춰 동적으로 날짜가 반영되어 안정적인 실행이 가능함.
2-5. 명확한 DAG / Task 이름
# 이름이 추상적이고 기능을 알 수 없음
dag_id="process"
task_id="do_stuff"
여러 DAG이 있는 상황에서 어떤 작업을 하는지 파악하기 어려움.
# 이름에 의미 부여
dag_id="daily_sales_aggregation"
task_id="fetch_order_data"
DAG과 태스크의 목적이 명확하게 드러나므로 운영과 디버깅이 쉬워짐.
3. Airflow DAG 작성 시 주의해야 할 Anti-pattern
3-1. datetime.now() 사용
from datetime import datetime
today = datetime.now()
Airflow는 논리적 시간(execution_date)을 기준으로 돌아가기 때문에 현재 시간을 쓰면 재현이 어려움.
run_date = context["ds"]
Airflow에서 제공하는 템플릿 변수(ds)를 사용하여 실행 기준 시점을 정확히 반영해야 함.
3-2. DAG에 모든 로직 몰아넣기
def full_etl():
...
전체 작업을 한 파일에 담으면 유지보수 및 테스트가 매우 어려움.
from tasks.pipeline import run_etl
각 작업은 함수 또는 모듈 단위로 나누고 DAG에는 흐름만 작성하는 게 바람직함.
3-3. XCom에 대용량 데이터 전달
context["ti"].xcom_push("data", df)
XCom은 작은 메타데이터를 전달하는 용도이므로 DataFrame 등 대용량은 부적합함.
context["ti"].xcom_push("data_path", "/tmp/data.csv")
데이터는 파일 시스템, S3 등에 저장하고 경로만 전달해야 성능 문제가 없음.
3-4. 하드코딩된 날짜 / 경로
bash_command="python etl.py 2024-01-01"
날짜가 고정되어 있어 매번 DAG 수정이 필요함.
bash_command="python etl.py "
Jinja 템플릿을 사용하면 DAG 스케줄에 맞게 동적으로 처리 가능함.
3-5. DAG / Task 이름이 모호함
dag_id="daily"
task_id="run"
기능이 드러나지 않아서 에러 추적이나 UI 관리가 어려움.
dag_id="daily_user_engagement"
task_id="calculate_active_users"
이름에 기능을 반영해서 DAG UI나 로그에서 바로 이해 가능함.
3-6. 무분별한 동적 Task 생성
for table in huge_table_list:
PythonOperator(...)
동적으로 수백 개의 Task가 DAG 파일에 생기면 파싱 시간과 UI 렌더링 성능에 문제가 생김.
@task
def run_table_job(table): ...
run_table_job.expand(table=table_list)
Airflow 2.3 이상에서는 Dynamic Task Mapping을 사용해 효율적으로 확장 가능함.
3-7. DAG 테스트 없이 바로 배포
airflow tasks test my_dag fetch_data 2023-01-01
로컬 테스트 없이 DAG을 배포하면 런타임 에러가 발생할 수 있음.
airflow dags show my_dag
실행 전에 구조 시각화를 통해 흐름을 점검하고 오류를 방지할 수 있음.
4. 정리 요약표
| 항목 | 문제점 | 권장 방식 |
|---|---|---|
| datetime.now() 사용 | 재현 불가 | execution_date / ds 사용 |
| 로직이 DAG에 몰려 있음 | 유지보수 어려움 | 함수 분리, tasks 폴더로 관리 |
| 대용량 XCom 사용 | 성능 저하, 오류 가능성 | 파일/S3/DB에 저장 후 경로만 전달 |
| 하드코딩된 날짜/경로 | 확장성 낮음, 수정 어려움 | Jinja 템플릿 활용 (, ) |
| DAG / Task 이름이 모호함 | 관리 어려움 | 명확한 이름 작성 |
| 동적 Task를 무작정 생성함 | DAG 파싱 시간, UI 성능 저하 | Dynamic Task Mapping 활용 (Airflow 2.3+) |
| 테스트 없이 배포함 | 런타임 에러 가능성 | airflow tasks test, dags show 활용 |
Airflow는 단순히 DAG을 실행하는 도구가 아니라, 시간 기반 재현성과 선언적 워크플로우 구성이라는 철학을 따르는 도구임. 위의 원칙과 스타일 가이드, 그리고 Anti-pattern을 잘 숙지하면 나중에 DAG짤 때 유용하게 써먹을 듯 함.
댓글남기기