이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Spring Batch와 Airflow는 각각 어떤 책임을 가져야 하는가?
  • 업무 처리 로직을 DAG에 넣을 때와 백엔드 batch에 둘 때의 trade-off는 무엇인가?
  • Airflow가 Spring Batch job을 호출할 때 parameter, idempotency, retry 경계는 어떻게 잡는가?
  • 백엔드 개발자는 데이터 팀과 어떤 계약을 문서화해야 하는가?

개요

Spring Batch는 업무 처리 구현에 강하다.

chunk transaction, reader/processor/writer, job repository, restartability를 제공한다.

Airflow는 여러 작업의 순서와 운영 관측에 강하다.

schedule, dependency, retry, SLA, backfill, task log를 제공한다.

둘을 섞을 때 핵심은 “로직은 어디에 두고 orchestration은 어디에 둘 것인가”다.

책임 분리

Spring Batch
  - 업무 query
  - transform logic
  - chunk transaction
  - item-level retry/skip
  - job parameter와 checkpoint
 
Airflow
  - DAG schedule
  - upstream/downstream dependency
  - task retry
  - SLA and alert
  - backfill orchestration

Spring Batch가 한 job 내부의 처리 신뢰성을 맡는다.

Airflow는 여러 job의 흐름과 운영 상태를 맡는다.

나쁜 경계

Airflow Python task 안에 복잡한 주문 정산 로직을 직접 쓰면 테스트와 배포가 어려워진다.

백엔드 팀의 domain rule이 DAG repository로 흩어진다.

반대로 Spring Scheduler만으로 extract, transform, validate, report 의존성을 모두 처리하면 workflow 상태를 보기 어렵다.

경계가 흐리면 장애 때 어느 팀이 어디를 고쳐야 하는지 모호해진다.

좋은 경계

Airflow task는 Spring Batch job을 명시적 parameter로 호출한다.

java -jar batch.jar \
  --spring.batch.job.name=buildOrderMart \
  targetDate={{ ds }} \
  runId={{ run_id }}

Spring Batch는 targetDate 기준으로 idempotent하게 처리한다.

Airflow는 이 task가 언제 실행되고, 실패하면 몇 번 재시도하며, downstream이 무엇인지 관리한다.

Retry 경계

Spring Batch retry와 Airflow retry는 다르다.

Spring Batch retry는 item 또는 chunk 내부의 일시 오류를 다룬다.

Airflow retry는 task 전체 재실행이다.

둘을 모두 켜면 같은 데이터를 여러 번 처리할 수 있다.

따라서 writer는 idempotent해야 하고, job parameter와 checkpoint가 명확해야 한다.

Airflow retry는 “job을 처음부터 다시 호출해도 안전한가”를 기준으로 결정한다.

Parameter 계약

Airflow와 Batch 사이에는 parameter 계약이 필요하다.

  • job name
  • target date 또는 range
  • run id
  • batch size
  • dry run 여부
  • force 여부
  • output partition

이 계약이 없으면 backfill과 장애 재실행이 사람의 기억에 의존한다.

parameter는 log와 job repository에도 남아야 한다.

Data Quality 경계

품질 검증을 어디에 둘지도 정한다.

기본 row-level validation은 Batch 안에서 할 수 있다.

source-target 합계 검증이나 downstream mart freshness 검증은 Airflow validation task로 분리하는 편이 좋다.

Batch job success와 quality rule success를 분리하면 원인 분석이 쉬워진다.

운영 지표

  • Spring Batch job status: job 내부 처리 결과다.
  • read/write/skip count: batch 처리량과 skip이다.
  • Airflow task retry count: task 재실행 횟수다.
  • DAG duration: workflow 소요 시간이다.
  • validation failure count: 데이터 품질 실패다.
  • backfill run count: 과거 재처리량이다.

두 시스템의 지표를 run id나 target date로 연결해야 한다.

개인 프로젝트 기준

개인 프로젝트에서는 Spring Batch job 하나와 Airflow DAG 하나를 연결하면 충분하다.

Airflow는 targetDate를 넘겨 job을 호출한다.

Spring Batch는 같은 targetDate를 두 번 실행해도 target 결과가 같아야 한다.

Airflow에는 validation task를 별도로 둔다.

위험 신호!

  • Airflow DAG에 domain business logic이 길게 들어간다.
  • Spring Scheduler가 복잡한 workflow dependency를 직접 관리한다.
  • Airflow retry와 Batch retry가 중복되는데 idempotency가 없다.
  • target date와 run id parameter가 없다.
  • Batch success와 data quality success를 같은 것으로 본다.

확인 질문

확인 질문

  • 이 로직은 업무 처리인가, workflow 조율인가?
    • 업무 처리는 Spring Batch, 조율은 Airflow가 맡는 편이 명확하다.
  • Airflow가 같은 Spring Batch job을 재시도해도 결과가 안전한가?
    • target date, checkpoint, idempotent writer가 필요하다.
  • Airflow run과 Batch job execution을 어떤 key로 연결하는가?
    • run id, target date, job execution id가 함께 기록되어야 한다.

참고 문서