[Airflow 101] Day 5: 과거를 지배하는 자, Backfill & Best Practices
들어가며: Airflow의 시간은 거꾸로 간다?
Airflow를 처음 접하는 분들이 가장 헷갈려 하는 것이 바로 ‘실행 기준 날짜(Logical Date)’입니다.
“매일 자정(
00:00)에 도는 스케줄을 만들었어요. 지금이 1월 9일 00:00인데, 왜 로그에는2026-01-08이라고 찍히죠?”
버그가 아닙니다. Airflow는 기본적으로 “데이터의 기간(Interval)이 끝나는 시점”에 실행되기 때문입니다. 1월 8일 하루치(00:00 ~ 23:59) 데이터를 처리하려면, 1월 8일이 다 지나간 1월 9일 00:00가 되어야 실행할 수 있겠죠? 그래서 실제 실행 시간은 9일이지만, 이 태스크가 처리해야 할 주인공(Logical Date)은 8일인 것입니다.
이 개념을 이해해야 오늘의 핵심 주제인 Backfill을 정복할 수 있습니다.
1. Backfill: 타임머신을 타고 과거 데이터 채우기
여러분이 오늘(1월 9일) 멋진 매출 집계 DAG를 완성해서 배포했습니다. 내일부터는 잘 돌겠죠. 하지만 팀장님이 묻습니다. “작년 1년 치 매출 데이터도 이 로직으로 다시 뽑아줄 수 있어?”
이때 사용하는 강력한 기능이 Backfill(백필)입니다.
(1) catchup=True의 함정
DAG 설정 중 catchup=True (기본값)로 두면, DAG를 켜는 순간 start_date부터 현재까지 밀린 작업 수백 개를 한꺼번에 실행하려고 듭니다. 서버가 터질 수 있으니, 기본적으로는 False로 두고 필요한 구간만 명령어로 실행하는 것이 안전합니다.
(2) CLI로 우아하게 Backfill 하기
Docker 컨테이너 내부로 들어가서 아래 명령어를 입력하면, 특정 기간의 데이터를 순차적으로 재처리할 수 있습니다.
1
2
3
4
5
6
7
# 1. 스케줄러 컨테이너 접속
docker exec -it <컨테이너_이름> bash
# 2. Backfill 명령어 실행
# 형식: airflow dags backfill -s <시작날짜> -e <종료날짜> <DAG_ID>
airflow dags backfill -s 2025-01-01 -e 2025-12-31 hello_airflow_v1
이 명령어를 치면 Airflow는 2025년 1월 1일부터 12월 31일까지의 날짜를 `` 변수에 차례대로 주입하며 태스크를 실행합니다. 코드를 수정할 필요 없이, 날짜만 바꿔가며 과거 데이터를 완벽하게 채워주는 것이죠.
2. 반드시 지켜야 할 Best Practices 3계명
Airflow를 운영하다 보면 서버가 이유 없이 느려지거나 멈출 때가 있습니다. 90%는 아래 3가지를 지키지 않아서입니다.
(1) Top-Level Code를 피하라 (가장 중요!)
Airflow 스케줄러는 새로운 DAG가 있는지 확인하기 위해 파이썬 파일들을 30초마다 한 번씩 파싱(실행)합니다.
나쁜 예:
1
2
3
4
5
6
7
# DAG 밖(Top-Level)에서 DB 연결이나 무거운 연산을 함
import requests
res = requests.get("http://heavy-api.com") # 매 30초마다 요청을 보냄 (서버 부하 유발)
with DAG(...) as dag:
...
좋은 예:
1
2
3
4
5
6
7
8
with DAG(...) as dag:
def my_task():
# 태스크(함수) 안에서 실행해야, 실제 작업이 돌 때만 1번 실행됨
import requests
res = requests.get("http://heavy-api.com")
PythonOperator(..., python_callable=my_task)
Top-Level에는 import 문과 DAG 정의 등 최소한의 코드만 있어야 합니다.
(2) 멱등성(Idempotency)을 유지하라
Day 3에서도 강조했지만, 태스크는 몇 번을 재실행하든 결과가 같아야 합니다. INSERT 대신 DELETE 후 INSERT (Overwrite) 방식을 사용하거나, UPSERT를 사용하세요. 재시도가 두려워서는 안 됩니다.
(3) 무거운 작업은 Airflow 밖에서
Airflow는 ‘지휘자’이지 ‘연주자’가 아닙니다. 수 기가바이트의 데이터를 Pandas로 Airflow 워커 메모리에서 직접 가공하면 안 됩니다.
- Airflow: “Spark야, 이 데이터 좀 처리해줘.” (지시)
- Spark/BigQuery/Snowflake: 실제 데이터 처리 (수행)
- Airflow: “다 했니? 그럼 다음 단계 진행할게.” (확인)
3. 마무리: 튜토리얼 종료 및 리소스 정리
5일간의 긴 여정이 끝났습니다. 이제 실습을 위해 띄워둔 컨테이너들을 깔끔하게 정리해 봅시다.
1
2
3
4
5
6
# 컨테이너 종료 및 삭제
docker compose down
# (선택) 볼륨(DB 데이터)까지 깨끗하게 지우고 싶다면
docker compose down -v