← 학습 카테고리

Learn

Airflow

151개 모듈 · 현재 54번째

Airflow 모듈 54/151 airflow-learn-54

Deferrable Operator란 무엇인가 (워커 슬롯 절약의 원리)

Apache Airflow Official Documentation (in-repo snapshot) — Apache Software Foundation authoring-and-scheduling/deferring.rst - Deferrable Operators & Triggers (도입부), Using Deferrable Operators (약 18-68줄)

이 모듈을 다 읽으면

  • 표준 Operator/Sensor가 워커 슬롯을 점유하는 문제와 Deferrable Operator가 이를 해결하는 방식을 설명할 수 있다
  • defer 발생 시 스케줄러-트리거러-워커 사이의 흐름을 순서대로 설명할 수 있다
  • Deferrable Operator와 Airflow 3.2 async task, Resumable Task의 차이를 구분할 수 있다

표준 Operator/Sensor는 대기 중에도 워커 슬롯을 계속 점유하지만, Deferrable Operator는 대기가 필요한 시점에 자신을 일시 중단(defer)하고 트리거러(triggerer)라는 별도 컴포넌트에 폴링을 위임함으로써 워커 슬롯을 즉시 반환한다.

워커 슬롯 점유 문제와 defer의 해법

표준 Operator와 Sensor는 실행되는 동안 유휴 상태여도 워커 슬롯 전체를 계속 점유한다. 예를 들어 워커 슬롯이 100개뿐인데 100개의 DAG가 모두 idle 상태로 센서를 돌리고 있다면, 클러스터 전체가 사실상 놀고 있어도 다른 작업을 하나도 실행할 수 없다.

센서의 `reschedule` 모드는 고정된 간격으로만 재실행하도록 해 이 문제를 일부 완화하지만, 시간 외의 다른 조건으로는 재개 시점을 판단할 수 없어 유연성이 떨어진다.

Deferrable Operator는 더 할 일이 없어 대기해야 하는 시점에 자기 자신을 defer해 워커를 다른 작업에 즉시 돌려준다. defer가 일어나면 실행이 트리거러로 옮겨가고, 그 오퍼레이터가 지정한 트리거가 트리거러에서 폴링이나 대기를 대신 수행한다. 트리거가 폴링/대기를 마치면 오퍼레이터에게 신호를 보내 실행을 재개시킨다. 이 defer 구간 동안에는 작업이 트리거러로 오프로드되었기 때문에 태스크가 더 이상 워커 슬롯을 차지하지 않아, 워크로드 여유 용량이 늘어난다. 기본적으로 deferred 상태의 태스크는 풀(pool) 슬롯도 점유하지 않으며, 원한다면 풀 설정을 바꿔 이 동작을 변경할 수 있다.

핵심 포인트

  • 표준 Operator/Sensor는 유휴 상태에서도 워커 슬롯 전체를 점유해, 극단적인 경우 클러스터가 사실상 놀고 있어도 새 작업을 못 띄울 수 있다
  • `reschedule` 모드는 고정 간격으로만 재시도해 이 문제를 일부 완화하지만 시간 외의 조건으로는 재개할 수 없어 유연성이 떨어진다
  • defer는 대기가 필요한 시점에 오퍼레이터를 일시 중단하고 실행을 트리거러로 옮겨, 워커 슬롯을 다른 작업에 즉시 반환한다
  • 기본적으로 deferred 상태의 태스크는 풀(pool) 슬롯을 점유하지 않으며, 필요하면 풀 설정으로 이를 바꿀 수 있다

defer 처리 흐름

defer가 일어나는 전체 과정은 대략 다음 네 단계로 이뤄진다.

태스크 인스턴스(실행 중인 오퍼레이터)가 다른 작업이나 조건을 기다려야 하는 시점에 도달하면, 자신을 재개시킬 이벤트에 연결된 트리거와 함께 defer한다 - 이로써 워커는 즉시 다른 작업을 실행할 수 있게 된다. 새로 만들어진 트리거 인스턴스는 Airflow에 등록되고, 트리거러 프로세스가 이를 가져가 실행한다. 트리거는 이벤트가 발생(fire)할 때까지 실행되며, 발생하는 순간 원래 소스 태스크가 스케줄러에 의해 재스케줄링된다. 마지막으로 스케줄러는 그 태스크를 워커 노드에서 재개하도록 큐에 넣는다.

핵심 포인트

  • 태스크 인스턴스가 defer되면 트리거가 등록되고 트리거러 프로세스가 이를 가져가 실행한다
  • 트리거가 이벤트를 발생(fire)시키면 스케줄러가 원래 태스크를 재스케줄링하고, 워커에 다시 큐잉한다

Deferral vs Async Task vs Resumable Task, 그리고 사용 제약

미리 작성된 Deferrable Operator(예: `TimeSensor`)를 그냥 쓰고 싶다면 Airflow 설치에 `triggerer` 프로세스를 최소 하나 이상(일반적인 `scheduler`에 더해) 띄우고, Dag에서 Deferrable Operator/Sensor를 사용하기만 하면 된다 - 나머지 defer 처리는 Airflow가 자동으로 해준다. 기존 Dag를 업그레이드하는 경우에도, Airflow가 제공하는 API 호환 센서 변형으로 다른 변경 없이 교체 투입할 수 있다.

Airflow 3.2는 Deferrable Operator와 별개로 파이썬 네이티브 async task도 지원한다. Deferrable Operator가 외부 이벤트를 기다리는 동안 워커 슬롯을 반환하는 반면, async task는 태스크 프로세스를 계속 띄운 채로 공유 이벤트 루프를 이용해 하나의 워커 슬롯 안에서 여러 동시 I/O 작업을 멀티플렉싱한다. 둘 중 무엇을 쓸지, 또는 (태스크 상태 저장소를 이용하는 크래시 안전 동기 오퍼레이터인) Resumable Task와 비교해 무엇을 쓸지는 각각의 가이드 문서에서 별도로 다룬다.

Human-in-the-loop(HITL) 오퍼레이터는 defer나 트리거러를 전혀 쓰지 않는다는 점도 주의해야 한다 - 이들은 스케줄러가 관리하는 `awaiting_input` 태스크 상태에서 대기하므로, 사람의 입력만 기다리는 배포라면 트리거러를 따로 띄울 필요가 없다.

defer 기능은 전통적인 클래스 기반 오퍼레이터에서만 쓸 수 있으며, 커스텀 PythonOperator나 TaskFlow 파이썬 함수 내부에서는 defer할 수 없다.

핵심 포인트

  • Deferred Operator는 워커 슬롯을 반환하고 트리거러에 위임하는 반면, Airflow 3.2의 async task는 워커 슬롯 안에서 공유 이벤트 루프로 동시 I/O를 멀티플렉싱한다 (슬롯은 유지)
  • Human-in-the-loop(HITL) 오퍼레이터는 defer/트리거러를 쓰지 않고 스케줄러가 관리하는 awaiting_input 상태에서 대기한다 - HITL만 쓰는 배포라면 트리거러가 필요 없다
  • defer 기능은 전통적인 클래스 기반 Operator에서만 쓸 수 있고, 커스텀 PythonOperator나 TaskFlow 파이썬 함수 내부에서는 쓸 수 없다
  • 기존 Dag를 업그레이드할 때는 API 호환 센서 변형을 그대로 교체 투입할 수 있다