데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      Apache Airflow 3.x 무엇이 달라졌고, 어디로 가고 있는가?

      추영욱 26.09.18
      101 1 1
      DEVOTEE 요약
      Airflow는 단순한 시간 기반 ETL 스케줄러를 넘어 데이터, 이벤트, AI/ML 워크플로우를 아우르는 범용 오케스트레이션 플랫폼으로 확장하고 있습니다.Airflow 3.x는 실행(Execution)과 코어(Orchestration)를 분리한 아키텍처 개편과 표준 인터페이스인 `airflow.sdk` 도입을 통해 보안성, 격리성, 개발 생태계의 안정성을 강화했습니다.또한 시간 위주에서 자산(Asset)과 이벤트 중심 모델로 전환하고 DAG 버저닝을 지원하여, 데이터 상태 변화에 유연하게 반응하고 과거 실행 맥락을 정밀하게 관측·추적할 수 있게 되었습니다.
      DEVOTEE 추천 블로그

      우리가 오해하고 있는 Airflow

      Airflow가 뭔가요? 그거? ETL하는 스케줄러

      'Airflow가 뭔가요?'라는 질문에 '워크플로우를 오케스트레이션하는 플랫폼입니다.'라는 대답이 때때로 충분하지 않을 때가 있습니다.


      그럴 때마다 'ETL할 때 쓰는 스케줄러입니다.'라고, 틀린 말은 아니지만 다소 범위를 좁혀 설명하곤 했습니다.

      그때마다 '하, 이걸 이렇게밖에 설명 못 하나' 싶어 마음이 좀 죄송스러웠는데 아마 우리에게 익숙한 Airflow가 이런 그림이라 그랬던 것 같습니다.

      Schedule → Dag → Task → Data Warehouse

      정해진 시간이 되면 Dag가 뜨고, Task가 순서대로 실행되고, 결국 데이터가 웨어하우스에 적재됩니다.

      크론을 대신하는, 조금 더 똑똑한 배치 스케줄러. 오랫동안 이게 Airflow의 정체성이었고, 지금도 많은 분들에게 그렇습니다.


      하지만 Airflow의 정확한 정의는 그것이 아니다

      잘 만든 오픈소스 프로젝트는 자신을 한 줄로 설명하는 데 능합니다. Airflow도 마찬가지인데, 스스로를 이렇게 정의하고 있습니다.

      Apache Airflow is a platform created by the community to programmatically author, schedule and monitor workflows.

      Airflow는 워크플로우를 프로그래밍 방식으로 작성하고, 스케줄링하고, 모니터링하기위한 커뮤니티에서 만든 플랫폼이다.

      즉, Airflow는 처음부터 스케줄링하는 대상을 ETL로 한정 짓지 않고 있었습니다. 오히려 한정 짓고 있었던 건 저 자신이었다는 생각도 듭니다.


      실제로 요즘 우리가 운영하는 워크플로우는 이쪽에 더 가깝습니다.

      Event → Data → Model → Inference → Decision → Action

      이벤트가 들어오면 데이터가 붙고, 모델이 돌고, 추론 결과로 의사결정을 하고, 액션까지 이어집니다.

      우리가 이해하던 방식은 끝이 '적재'였지만, 이제는 끝이 '행동'일 필요가 있습니다.

      시작도 다릅니다. 전통적인 워크플로우는 시간이 방아쇠였지만, 최근엔 이벤트가 방아쇠가 될 필요도 생겼습니다.


      여기서 생기는 질문은. 이 둘은 같은 종류의 Workflow일까?


      저는 이 간극이 Airflow 3.x를 이해하는 출발점이라고 생각합니다.

      Airflow 3의 중요한 변화는 기능이 늘어난 게 아니라, Airflow가 감당하려는 Workflow의 범위가 넓어졌다는 것입니다.

      그리고 그 확장은 우연히 흩뿌려진 기능들의 합이 아니라, 세 개의 축이 한 방향으로 수렴한 결과입니다.


      마누라하고 자식 빼고 다 바꾼 Airflow

      지난 몇 년간, Airflow 커뮤니티는 3.0을 향해 대대적인 변화를 계획하고 실행해 왔습니다.

      바꾸려면 철저히 바꿔. 극단적으로 이야기해, 농담이 아니야. 마누라하고 자식 빼고 다 바꿔봐.

      이 말처럼, Airflow도 정말 '마누라하고 자식만 빼고' 철저히 바뀝니다.

      image.png


      제가 생각하는 3개의 축

      3.x의 변경점을 다 세면 수십 개입니다. 이 변화를 3개의 축으로 묶어보려고 합니다.

      • Architecture: Execution과 Orchestration의 분리

      • Developer Experience: Airflow 내부 구현에 의존하는 것에서, 안정적으로 보장되는 Authoring 인터페이스로

      • Workflow Model: Data/Time 중심에서 Asset/Event 중심을 모두 지원하는 방향으로

      이 셋은 따로 노는 변화가 아니라, 철저히 계획된 한 곳을 노리는 변화입니다.

      Workflow Orchestration

      그리고 그 오케스트레이션이 감당하는 범위가 Data Workflow → Event-driven Workflow → ML/AI Workflow로 넓어집니다.

      지금부터 세 축을 하나씩 이야기해 보려고 합니다. 각 부분은 왜 이 변화가 필요했나 → 무엇이 바뀌었나 → 그래서 우리가 얻는 것, 이 순서로 정리해 보겠습니다.


      Architecture: Task는 더 이상 DB를 직접 만지지 않는다

      Airflow 2.x 의 구조를 떠올려봅시다.

      스케줄러와 웹서버가 있고, 스케줄러가 익스큐터를 거쳐 워커에 테스크를 넘기는 구조.

      여기서 워커가 태스크를 실행하는 동안 메타데이터 DB에 직접 접근합니다. 커넥션도 변수도 XCom도 상태도 전부 직접 DB를 거칩니다. 이게 Airflow 2.x의 암묵적 전재였습니다.

      image.png

      Airflow 3.x에서는 이 전제를 깹니다. 눈에 띄는 변화 3가지를 보면.


      첫째, 웹서버가 API Server가 됐다. 이제 UI와 REST API를 서빙하는 것을 넘어, 태스크가 상태를 보고하는 창구 역할까지 합니다.

      태스크는 DB가 아니라 이 API Server를 통해서만 Airflow와 대화합니다.


      둘째, Dag Processor가 필수 컴포넌트로, 독립 프로세스로 분리됐다. Dag 파일을 파싱하는 일을 스케줄러에서 떼어냈습니다.

      그래서 스케줄러는 Dag 작성자가 쓴 코드를 직접 실행하지 않게되었습니다. 보안 경계가 하나 생긴 것으로 볼 수 있습니다.

      Dag Bundle을 읽고 파싱해서 메타데이터 DB에 직렬화하는 것은 Dag Processor의 몫이고, 스케줄러는 그 결과만 읽는 형태죠.


      셋째, 익스큐터는 더 이상 별도의 박스가 아니다.

      공식 문서 표현 그대로, 익스큐터는 "스케줄러의 설정값이지 별도 컴포넌트가 아니며 스케줄러 프로세스 안에서 돈다."

      2.x의 멘탈 모델인 스케줄러 → 익스큐터 → 워커를 세 개의 상자로 그리던 그림이 바뀝니다.


      개념적으로 3.x의 구조는 이렇게 정리됩니다.

      image.png

      여기서 진짜 중요한 건 컴포넌트 배치보다 태스크가 어떻게 실행되는가가 바뀌었다는 점입니다.


      Task Execution API: 실행과 오케스트레이션의 분리

      Airflow 3.x에서 워커는 사용자 코드를 직접 실행하지 않습니다.

      워커는 가벼운 Supervisor 프로세스를 띄우고, Supervisor가 다시 별도 프로세스를 포크해서 그 안에서 Task SDK 런타임이 사용자 코드를 돌립니다.

      둘은 소켓으로 대화하게 됩니다.


      핵심은. 짧게 발급된 태스크 토큰(JWT)과 실행 API를 쥐는 쪽은 오직 Supervisor뿐이다.

      사용자 코드는 그 토큰을 절대 보지 못하고, DB를 직접 만지지도 못합니다.

      커넥션이 필요하면? 변수가 필요하면? XCom을 읽어야 하면? 전부 Supervisor를 통해 Task Execution API로 프록시됩니다.

      image.png

      이 분리가 왜 중요한가를 살펴보면, 오케스트레이션과 실행이 떨어지기 때문입니다.

      • Orchestration: 무엇을, 언제, 어떤 순서로 실행할지, 실패하면 어떻게 할지. 이건 Airflow Core의 몫이다.

      • Execution: 실제로 코드가 도는 일. 이건 Task Execution API만 말할 수 있으면 어디서든 일어날 수 있다.

      일반 워커든, 엣지든, 컨테이너든, 원격이든 상관없습니다. 심지어 언어도 Python만이 아니어도 됩니다.

      3.3에서는 Go와 Java로 태스크를 작성하는 Language Task SDK가 들어왔고.

      그건 Python DAG에서 @task.stub(queue=...)로 태스크의 모양만 선언하고, 실제 구현은 Go 바이너리나 Java jar가 맡는 형태입니다.

      다만 이건 아직 실험적 (experimental)이라 프로덕션에 바로 얹을 기능은 아니라고 보시면 됩니다.


      저는 이 "실행 환경의 decoupling"이 3.x에서 가장 근본적인 변화라고 생각하고 있습니다.

      "Task를 어떻게 실행할 것인가"와 "Workflow를 어떻게 orchestrate할 것인가"가 처음으로 분리되기 시작했기 때문이죠.


      그래서 우리가 얻는 게 뭐냐 하면, 이렇게 답할 수 있을 것 같습니다.

      실행을 코어에서 떼어냈으니, 같은 워크플로우를 격리된 워커, 엣지, 컨테이너, 원격에서, 심지어 Go, Java로도 돌릴 수 있습니다.

      태스크가 메타데이터 DB를 직접 만지지 않으니 보안 경계도 분명해집니다. "어디서 어떻게 실행하느냐"를 "무엇을 언제 오케스트레이트하느냐"와 따로 고를 수 있게 된 것입니다.


      Developer Experience: airflow.sdk, 무엇에 의존해도 되는가

      코드로 보면 3.x의 변화는 import 한 줄처럼 보이는데 그 안에는 엄청난 변화가 있습니다.

      # Before: 내부 구현에 의존
      from airflow.models import DAG
      from airflow.decorators import task
      
      # Airflow 3.x: 보장되는 Authoring Interface
      from airflow.sdk import DAG, task, Asset

      이걸 "import 방식 정도 바뀌었네" 정도로 넘기면 많이 아쉽습니다.

      지금까지 우리는 Airflow의 내부 구현을 그냥 가져다 썼습니다.

      airflow.models는 Airflow가 내부적으로 쓰는 ORM 모델이지, 우리에게 안정성을 약속한 인터페이스가 아니었죠.

      그래서 내부가 리팩토링되면 내 Dag가 조용히 깨질 수 있었습니다.


      airflow.sdk는 그 경계를 다시 그은 것입니다.

      "Dag를 작성할 때 여러분이 의존해도 되는 것은 여기까지"라고 Airflow가 보장하는 표면. 3.1부터 공식적으로 이 네임스페이스로 작성할 것을 권장하고, 옛 import는 동작은 하되 경고를 냅니다.


      한 줄의 import처럼 보이지만, 이건 장기적으로 Dag 호환성, provider 개발, 생태계 전체의 안정성으로 이어지는 엄청난 변화입니다.

      그리고 방향으로 보면 앞에 설명한 Architecture와 같은 방향입니다.

      코어와 작성 인터페이스를 분리하는 것. 실행을 코어에서 떼어냈듯, 작성 인터페이스도 코어에서 떼어내 안정된 계약으로 만드는 것입니다.


      그래서 우리가 얻게 되는 것은 이렇습니다.

      내부가 리팩토링돼도 airflow.sdk만 붙들고 있으면 Dag가 조용히 깨지지 않습니다.

      Airflow를 운영하는 팀과 Dag를 작성하는 사람이 서로 독립적으로 업그레이드할 수 있고, provider와 생태계가 흔들리지 않는 계약 위에 쌓인다.


      Workflow Model: 시간에서 이벤트로

      데이터 인식 스케줄링(data-aware scheduling) 자체는 새로운 건 아닙니다.

      Airflow2.4의 Datasets에서 시작된 개념이긴 합니다. 어떤 태스크가 데이터셋을 갱신하면, 그 데이터셋을 소비하는 다른 Dag로 자동으로 도는 구조입니다.


      3.0은 이 Dataset을 Asset으로 확장합니다. 사용법은 직관적입니다.

      from airflow.sdk import DAG, Asset
      
      # 생산자: 이 태스크가 성공하면 Asset이 갱신된다
      with DAG(dag_id="producer", ...):
          MyOperator(task_id="producer", outlets=[Asset("s3://bucket/example.csv")])
      
      # 소비자: 그 Asset이 갱신되면 이 DAG이 실행된다
      with DAG(dag_id="consumer", schedule=[Asset("s3://bucket/example.csv")]):
          ...

      한 가지 짚을 점은. Airflow는 태스크가 성공적으로 끝났을 때만 Asset을 '갱신됨'으로 표시합니다. 실패하거나 스킵되면 다운스트림은 돌지 않습니다.

      image.png


      왜 이름을 Asset으로 바꿨나

      먼저 단어의 무게를 봅시다. Dataset이라는 단어는 문자 그대로 '데이터셋'에 갇혀 있었습니다.

      파일 하나, 테이블 하나. Asset은 조금 더 넓습니다. "이름이 붙은, 상태를 가진 리소스." S3 경로일 수도, 테이블일 수도, 학습된 모델일 수도 있죠.


      여기서 과장은 반드시 경계해야 합니다. Asset은 "세상 모든 이벤트를 담는 범용 이벤트 버스"가 아닙니다.

      그렇게 설명하면 틀린 설명이 됩니다. Airflow의 모델은 어디까지나 Asset 중심입니다. 다만 그 Asset을 갱신하는 방법이 넓어졌을 뿐입니다.

      1. 다른 Dag의 태스크가 갱신: 내부(internal) 방식. 위 예시처럼 outlets로.

      2. 외부 시스템이 REST API로 이벤트를 push: 큐잉된 asset event로 쌓였다가 조건이 차면 Dag가 돕니다.

      3. Asset Watcher가 외부 소스를 pull: 메시지 큐나 스토리지 같은 외부 이벤트 소스를 AssetWatcher가 지켜보다가, 이벤트가 오면 해당 Asset을 갱신하고 Dag를 깨웁니다. 무한 재스케줄을 막기 위해 BaseEventTrigger를 상속한 트리거만 허용됩니다.

      조건도 걸 수 있습니다. &는 AND("A와 B가 둘 다 갱신되면"), |는 OR("A 또는 B가 갱신되면"). 시간과 함께 걸고 싶으면 AssetOrTimeSchedule을 씁니다.

      정리하면, Asset은 특정 데이터셋에 종속되지 않는, 더 일반적인 resource 중심 모델입니다. 그리고 그 갱신의 방아쇠가 더 이상 시간만은 아닙니다.


      Asset이 들어오면서 우리가 얻은 것은 이렇습니다.

      파이프라인을 크론 시간표가 아니라 '데이터의 상태'로 잇습니다.

      파일 하나가 아니라 '이름 붙은 리소스'가, 그것도 다른 Dag, REST push, 외부 큐 어느 쪽에서 갱신돼도 워크플로우가 깨어납니다.


      그런데 왜 시간이 아니라 이벤트인가

      기존 Airflow의 기본 가정을 한 줄로 요약하면 이렇게 됩니다.

      Time → Schedule → Dag

      "시간이 되었으니 Workflow를 실행한다." 크론이 세계관의 중심이었습니다.

      그런데 현실에선 이런 질문을 할 수도 있습니다.

      Workflow를 실행시키는 방아쇠가 반드시 시간이어야 할까?

      새 데이터가 도착했을 때, 메시지 큐에 이벤트가 들어왔을 때, 업스트림 산출물이 준비됐을 때. 그때 도는 게 훨씬 자연스러운 워크플로우가 이제 훨씬 많지 않나?


      그래서 3.x는 트리거 조건을 시간에서 사건으로 넓혔습니다.

      Event → Asset → Workflow

      이벤트가 Asset의 상태를 바꾸고, 그 Asset이 Workflow를 깨웁니다. 여기서 오해하지 말아야 할 게 있습니다.

      시간 기반 스케줄이 사라진 게 아닙니다. 여전히 @daily도 크론도 쓸 수 있습니다. 사라진 게 아니라 유일한 방아쇠가 아니게 된 것입니다.


      이 관점을 쥐면, 시간과 관련된 다른 기본값들이 함께 바뀐 이유도 보입니다.

      Airflow 3에서 catchup의 기본값은 False입니다.

      예전엔 Dag을 켜면 과거 구간을 우르르 다 메꿨지만("무조건 과거를 다 채운다"), 이제 기본은 "최신 구간만"입니다. 시간 중심 세계관이 옵션으로 물러난 것이죠.


      이걸 이어 붙이면 하나의 그래프가 됩니다.

      Event → Asset A → Workflow A → Asset B → Workflow B → …

      image.png

      02_curate_orders의 Overview.

      Schedule이 orders_raw(Asset)이고, 오른쪽 "Created Asset Events" 패널은 이 Dag가 orders_curated를 갱신할 때마다 다운스트림 03_report_orders가 트리거됐음을 보여줍니다.

      1546617c9dc1495352faf21e6b45946de3fb3cac.gif

      01_ingest_orders를 한 번 트리거하면 시간이 아니라 Asset 이벤트02_curate_orders03_report_orders가 스스로 이어서 도는 모습.

      비어 있던 Latest Run들이 차례로 실행되고 초록으로 바뀌는 것을 볼 수 있습니다.


      개별 Dag들의 모음이 아니라, Asset으로 연결된 하나의 큰 그래프죠.

      3.2부터는 여기에 파티션(partition) 개념까지 들어왔습니다.

      "어제치 파티션이 갱신됐을 때만 그 다운스트림을 돈다"처럼, 바뀐 조각에 반응하는 다운스트림만 정확히 트리거할 수 있게 됐습니다.

      예전엔 하나만 바뀌어도 다운스트림이 전부 돌았는데, 이제 시간표가 아니라 데이터의 상태가 흐름을 만들 수 있게 된 것입니다.

      그래서 필요할 때만, 데이터가 준비됐을 때만 돕니다. "혹시 몰라 5분마다 크론" 같은 낭비와, "데이터는 도착했는데 다음 크론까지 기다리는" 지연이 함께 줄어듭니다.


      Workflow도 버전을 가진 산출물이다.

      실무에서 이런 일을 겪어봤을 것입니다.

      "지난주엔 성공했던 Dag가 오늘 실패했다."

      그런데 코드를 열어보면 그 사이에 이미 여러 번 바뀌어 있다.

      2.x에서는 항상 최신 코드로만 다시 돌렸기 때문에, 과거의 실행을 지금의 코드로 거꾸로 해석해야 했고. 그래서 사실상 추적이 불가능했습니다.


      3.x는 Dag를 버전을 가진 산출물(versioned artifact) 로 다룹니다.

      Dag v1 ──► Run #1
      Dag v2 ──► Run #2
      Dag v3 ──► Run #3

      어떤 Dag Run이 어떤 버전으로 돌았는지 UI에 남습니다. 그래서 이런 추적선이 명확해집니다.

      Dag Version → Dag Run → Task Instance

      image.png

      오른쪽 상단에 버전 드롭다운(v2, 2026-09-10 17:55:10)과 헤더의 Latest Dag Version: v2가 보입니다.

      이 Dag는 validate 태스크를 추가하면서 v1→v2로 올라갔고, 과거 Run은 여전히 v1로 추적됩니다.

      image.png

      Runs 탭에는 Dag Version(s) 컬럼이 있습니다. 같은 Dag의 Run들이 각각 어느 버전으로 돌았는지(v2 / v1 / v1)가 그대로 기록됩니다.


      실패를 "지금"이 아니라 "그때"의 맥락에서 볼 수 있게 되는 것입니다. 저는 이게 운영자에게는 아키텍처 변화만큼이나 체감이 큰 변화라고 생각합니다.

      관측할 수 없던 것이 관측 가능해지는 순간이니까요. 참고로 3.3에서는 clear, rerun, backfill을 할 때 최신 버전으로 돌릴지, 원래 버전으로 돌릴지까지 선택할 수 있게 됐습니다.

      그래서 우리가 얻는 것은 "지난주엔 됐는데" 류의 장애를, 지금 코드가 아니라 '그때 그 버전'으로 재현하고 추적할 수 있다. 관측할 수 없던 과거 실행이 비로소 관측 가능해집니다.


      Backfill과 logical_date: 시간 모델의 재정의

      "시간이 되면 돈다"는 가정이 풀리자, 시간과 얽혀 있던 것들이 함께 재정의됐습니다.

      Backfill. 예전엔 CLI 서브프로세스로 돌리던 백필이, 3.x에서는 스케줄러가 관리하고 UI, API로 제어하는 정식 기능이 됐습니다.

      과거를 다시 채우는 일이 별도 도구가 아니라 오케스트레이션의 일부가 된 것입니다.


      logical_date = None. 이제 logical_date는 없을 수 있습니다.

      데이터 인터벌(data interval)이 없는 실행, 이벤트나 수동으로 트리거된 실행은 굳이 특정 시점에 묶이지 않습니다.

      2.2 이전에 execution_date라고 부르던 이 값은 3.0에서 완전히 사라졌습니다.

      "모든 실행은 특정 시간 구간에 속한다"는 오래된 전제가 옵션이 된 것이죠.


      catchup 기본값 False. 앞에서 말한 그대로 입니다.

      이 셋은 따로 변경된 것이 아니라. 전부 같은 이야기로 볼 수 있습니다.

      Airflow가 서 있던 시간 중심의 세계관이, 이벤트 중심의 세계관으로 확장되면서 함께 조정된 것입니다.

      image.png

      Backfill은 이제 스케줄러가 관리하는 정식 기능입니다.

      From/To 구간, Reprocess Behavior(Missing Runs), 생성, 완료 시각과 소요 시간이 UI에 남습니다.

      예전처럼 CLI 서브프로세스로 따로 돌리는 게 아니라 오케스트레이션의 일부가 된 거죠.

      그래서 백필이 손으로 돌리는 CLI 작업이 아니라, UI, API로 관리, 모니터링되는 1급 기능이 됩니다. 언제, 어디까지, 어떤 정책으로 다시 채웠는지가 기록으로 남습니다.


      DAG라는 용어가 우리의 미래에 걸림돌이 될 수 있다

      갑자기 이 논의가 나왔을 때, 제가 잘못 봤나 했습니다.

      아무리 제대로 변화한다고 해도, 10년간 Airflow를 끌어올려 준 가장 Core 개념인 DAG를 바꾼다고?


      논의가 시작된 배경에는, 우리가 오랫동안 "DAG"라고 불러온 개념이 특정 수학적 의미(Directed Acyclic Graph, 단방향 비순환 그래프)에 갇혀 있다는 문제의식이 있었습니다.

      커뮤니티에서는 앞으로 Airflow가 발전함에 따라 보다 유연한 형태의 그래프 구조를 지원할 수도 있다는 점에서, DAG라는 용어가 너무 한정적이라는 의견이 제기된 것이죠.


      즉, Airflow는 더 이상 "Directed Acyclic Graph"라는 학문적 개념에 갇히고 싶지 않다는 뜻입니다.


      우리가 에이전트를 돌린다고 생각해 보면 이해가 됩니다. 에이전트를 돌릴 때의 요구사항은 이렇습니다.

      결과를 보고 다시 시도하고, 사람에게 물어보고, 조건이 맞을 때까지 반복하는 것. 그런데 순수한 의미의 DAG(비순환)가 이 요구사항을 그대로 따라올 수 있을까요? 그렇지 않죠.


      실제로 Airflow는 커뮤니티 투표를 거쳐 표기를 정리했습니다.

      옵션 A~D를 두고 논의한 끝에, "문서에서는 Dag, 클래스와 import에서는 DAG"(옵션 B)로 결정됐습니다.

      이 글에서도 개념을 가리킬 땐 'Dag', 코드를 가리킬 땐 DAG로 쓰고 있었던 게 그래서입니다.


      더 이상 '단방향 비순환 그래프'라는 DAG라는 학문적 정의가 아니라, Airflow의 워크플로우Dag라는 독립적 개념으로 가게 된 것입니다.

      https://discourse.airflow-kr.org/t/dag-vs-dag-vs-dag-dag/452


      AI Agent 시대의 Airflow

      자 그러면 여기서 AI 이야기를 해야 합니다. 다만 조금 조심하려고 합니다.

      AI를 Airflow의 종착지라고 말하는 것은 아닙니다.

      AI는 이 공통 뼈대가 감당하는 범위가 넓어지는 과정에서 자연스럽게 들어온 하나의 사례일 뿐입니다.


      먼저 그림을 하나 보겠습니다. 데이터, ML, AI 워크플로우는 도메인이 다르지만 뼈대가 같습니다.

      Data :  New Data   → Validation → Transform → Warehouse
      ML   :  New Model  → Evaluation → Deploy    → Inference
      AI   :  Request    → Agent      → Tool/LLM  → Action

      무언가 일어나고, 상태가 바뀌고, 흐름이 돌고, 일이 실행됩니다. 셋 다 Event → Asset → Workflow → Task → Execution입니다.

      ML은 사실 새로운 이야기가 아닙니다. 학습, 평가, 배포, 추론 사이클은 데이터 파이프라인과 뼈대가 같습니다.

      3.x 관점에서 달라지는 건, 각 단계의 산출물인 학습된 모델, 평가 지표, 예측 결과를 Asset으로 다룰 수 있다는 점입니다.

      그리고 3.1의 HITL을 여기 끼워 넣을 수 있습니다. 모델을 프로덕션에 밀기 전에, 사람이 UI에서 승인하는 게이트를 정식으로 두는 것입니다.

      image.png

      evaluate_model → approve_deploy → deploy 파이프라인에서 approve_deploy(HITLOperator)가 Awaiting Input 상태로 멈춰,

      "Deploy model orders-forecast:v3 to production? (Holdout AUC=0.91)"라는 질문과 함께 Approve / Reject 버튼을 UI에 띄웁니다.

      자동화된 흐름 한가운데 '사람의 판단'이 1급 단계로 들어온 것입니다.

      856171740bb655f34686840c4afc941b4c9eb5fd.gif

      사람이 Approve를 누르는 순간, approve_deploySuccess로 바뀌고("Response received … from Anonymous"), 대기하던 deploy가 그제서야 실행돼 초록이 됩니다.

      대기 → 사람의 승인 → 다음 태스크로 이어지는 Human-in-the-Loop 전체 사이클이죠.


      감사 가능한 에이전트 그래프

      이 "사람이 개입할 수 있는 지점"이라는 관점은, AI 에이전트로 가면 훨씬 더 중요해집니다.


      어떤 질문은 SQL 하나로 끝나지 않습니다.

      여러 차원을 각각 조회한 뒤 종합해야 답이 나옵니다.

      이걸 에이전트 하네스(agent harness) 안에서만 처리하면 이렇게 됩니다.

      LLM이 내부적으로 툴을 호출하고, 결과를 쌓고, 종합합니다. 문제는 그 과정 전체가 블랙박스라는 것입니다.

      툴 호출 하나가 실패하면 루프 전체가 다시 돕니다. "왜 그렇게 답했는가"라고 물으면, 남은 흔적이 없습니다.


      Airflow는 같은 로직을 다른 모양으로 만듭니다.

      각 LLM 호출이 이름 붙은 Task가 됩니다. 병렬 실행은 Dynamic Task Mapping으로 펼칩니다.

      각 Task는 자기 로그, 자기 XCom, 자기 재시도 카운터를 가집니다. 네 개 중 세 번째만 실패하면, 그것만 다시 돌립니다. 나머지 셋의 결과는 그대로 보존됩니다.

      image.png

      실제 Airflow 3.3의 Graph 뷰입니다.

      make_batches → process[0] → summarize → validate 구조에서 process가 개별 태스크 인스턴스로 펼쳐집니다(Dynamic Task Mapping).

      각각이 독립적으로 로그, XCom, 재시도를 갖는 이 모양이, 에이전트의 병렬 도구 호출을 "감사 가능한 그래프"로 만든 것입니다.


      여기서 에이전트에 대해서 개인적인 생각을 하나 꺼내고 싶습니다. 저는 에이전트에 대해서 결과보다 과정을 믿고 싶습니다.

      무언가 권위 있는 존재(프론티어 모델)이기 때문에 믿는 것과, 내가 언제든 들여다볼 수 있고, 필요하면 수정할 수 있으며, 원한다면 되돌릴 수도 있기 때문에 믿는 것은 전혀 다른 종류의 신뢰입니다.

      후자는 맹신이 아니라 검증 가능한 신뢰입니다. 관측할 수 있어야 하고, 제어할 수 있어야 하고, 되돌릴 수 있어야 합니다.


      흥미롭게도 Airflow가 AI에 기여하는 방식이 정확히 이 지점에 있습니다.

      공식 블로그의 표현을 그대로 빌리면 Observable, Retryable, Auditable by Design. 에이전트 하네스가 내부에 숨겨두는 정보를, Airflow는 표면에 드러냅니다.


      Airflow는 에이전트가 아니다

      그래서 한 가지는 분명히 하고 싶습니다. Airflow는 AI 에이전트가 되려는 것이 아닙니다.


      "Airflow가 AI 에이전트 플랫폼이 된다" 같은 표현에 저는 동의하지 않습니다. 에이전트는 판단하고, 생성하고, 추론합니다.

      Airflow가 하는 일은 다릅니다. 오케스트레이션, 스케줄링, 의존성 관리, 재시도, 관측 가능성, 운영 제어, 워크플로우 생애주기 관리.


      실제로 3.x에는 common.ai 프로바이더(아직 0.x 초기 릴리스)가 들어왔습니다.

      LLMOperator, 멀티스텝 AgentOperator, 자연어를 SQL로 바꾸는 @task.llm_sql 같은 오퍼레이터 6개와

      그에 대응하는 TaskFlow 데코레이터 6개, 툴셋 5개, 그리고 20개가 넘는 모델 프로바이더를 한 패키지로 묶었습니다(내부는 Pydantic AI 기반으로 돌아갑니다).

      사람이 승인하는 HITL도 require_approval, enable_hitl_review 옵션으로 들어 있습니다.

      하지만 이건 Airflow가 LLM을 호출하는 방법을 표준화한 것이지, Airflow가 LLM이 된 것이 아닙니다.


      한 문장으로 정리하면 이렇습니다. Airflow는 AI Agent를 만드는 것이 아니라, AI Agent를 포함한 Workflow를 orchestrate합니다.

      에이전트가 실행한 워크플로우를 누가 관리하고, 실패하면 누가 되돌리고, 누가 감사하는가. 그 자리를 Airflow가 맡습니다.


      그래서 우리가 에이전트 시대에 Airflow를 활용하여 얻는 것은 이렇습니다.

      AI를 '더 똑똑하게' 만드는 게 아니라, AI가 한 일을 관측하고, 되돌리고, 감사할 수 있게 됩니다. 블랙박스 추론 루프가, 언제든 들여다보고 특정 단계만 다시 돌릴 수 있는 그래프가 됩니다.


      그래서 Airflow는 어디로 가는가

      지금까지의 이야기를 하나의 궤적으로 잡아보면 이렇게 됩니다.

      Batch → Data Workflow → Event-driven → ML → AI → Workflow Orchestration

      여기서 중요한 건, 이게 다섯 개의 서로 다른 제품이 아니라는 점입니다.

      같은 뼈대가 감당하는 범위가 넓어진 것인데, 이게 가능할 수 있는 이유는 실행을 코어에서 떼어냈기 때문에 어디서든 돌릴 수 있고,

      트리거 조건을 시간에서 이벤트로 넓혔기 때문에 무엇으로든 깨울 수 있고, 작성 인터페이스를 안정화했기 때문에 생태계가 그 위에 쌓일 수 있습니다.


      그리고 지금 코드에 이미 찍혀 있는 방향은 이렇습니다.

      • 실행의 분리는 다언어(Go, Java, Typescript)로 더 깊어지고 있습니다.

      • 상태(state)가 1급 시민이 됐습니다.

      • 데이터 인식이 파티션 단위로 정밀해지고 있습니다.

      • 사람의 개입이 워크플로우 안에 정식으로 들어왔습니다.

      이 네 방향을 이으면, 다음 칸의 물음표는 "더 많은 기능"이 아니라 "더 넓은, 더 검증 가능한 오케스트레이션"에 가깝다고 볼 수 있을 것 같습니다.

      정리하면, Airflow가 감당하려는 Workflow의 범위가 넓어지고 있다는 것입니다.


      마무리하며

      정리하면, 이제 Airflow는:

      • 시간은 더 이상 유일한 트리거가 아니다. 이벤트가, 데이터의 상태가 워크플로우를 깨운다.

      • 데이터만이 산출물이 아니다. 모델도, 예측도, 그리고 Dag 그 자체도 버전을 가진 산출물이 된다.

      • 태스크는 더 이상 하나의 런타임에 묶여 있지 않다. 실행은 오케스트레이션에서 분리되어, 어디서든 어떤 언어로든 일어날 수 있다.

      Airflow 3의 가장 중요한 변화는 새로운 기능이 아니라고 생각합니다. Airflow가 Workflow를 바라보는 방식 자체가 바뀌고 있다는 것.

      그래서 저는 3.x를 "DAG 스케줄러의 업그레이드"가 아니라 "워크플로우 오케스트레이터로의 이동" 이라고 생각합니다.


      Reference

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      추영욱 님의 최신 블로그

      더보기

      DEVOTEE 추천 블로그

      동영상 기고하기