당신의 ML 파이프라인은 작업(Task)의 DAG가 아니라 자산(Asset)의 그래프입니다
요약
기존의 작업(Task) 중심 오케스트레이션은 ML 파이프라인의 데이터 신선도와 드리프트를 관리하기에 부적합합니다. 대신 데이터셋, 피처, 모델을 버전 관리된 객체로 취급하는 자산(Asset) 중심의 접근 방식이 필요합니다.
핵심 포인트
- 작업 중심 오케스트레이션은 실행 순서에만 집중하여 데이터 상태를 반영하지 못함
- ML 파이프라인은 데이터 신선도 계약(Freshness contracts)을 기반으로 작동해야 함
- 재학습은 단순 스케줄링이 아닌 데이터 분포 변화(Drift)에 따른 자산 상태 의존성 문제임
- 성공적인 ML 운영을 위해 실행(Run)이 아닌 자산(Asset)을 추적하는 모델링이 필수적임
요약(TL;DR) — Airflow 스타일의 오케스트레이션(Orchestration)은 ML 파이프라인을 성공적으로 실행된 작업(Task)들의 시퀀스로 모델링하지만, 이는 재학습(Retraining), 드리프트(Drift)로 인한 실행, 버전 관리된 아티팩트(Artifact)를 다루기에 잘못된 추상화 단위입니다. 데이터셋, 피처(Feature), 모델을 신선도 계약(Freshness contracts)을 가진 일급의 버전 관리된 객체로 취급하는 자산 중심(Asset-centric) 오케스트레이션이 실제 ML 의존성 그래프가 작동하는 방식과 일치합니다. 해결책은 Airflow 대신 Dagster를 선택하는 것이 아니라, 무엇을 중심으로 오케스트레이션할 것인지를 바꾸는 것입니다.
여러분이 사용해 온 모든 오케스트레이터는 단 하나의 질문에 답하기 위해 설계되었습니다: '작업 A가 성공한 후 작업 B가 실행되었는가?' Airflow는 그 질문을 매우 신뢰할 수 있게 만들었습니다. Cron은 그것을 명시적으로 만들었습니다. Dagster, Prefect 및 그 동료들도 모두 동일한 핵심 프리미티브(Primitive)를 상속받았습니다: 즉, 스케줄이나 센서(Sensor)에 의해 트리거되어 순서대로 실행되는 작업들의 유향 그래프(Directed graph of tasks)입니다.
이 프리미티브는 ETL에는 적합합니다. 하지만 ML에는 미묘하게 틀렸습니다.
모든 DAG에 내재된 가정
작업 기반(Task-based) 오케스트레이션은 두 가지를 가정합니다. 첫째, '성공적으로 실행됨'이 추적해야 할 의미 있는 상태라는 것입니다. 둘째, 의존성은 데이터 상태가 아니라 실행 순서에 관한 것이라는 점입니다. 이 두 가지 가정은 야간 보고서(Nightly report)에는 유효합니다: 추출(Extract), 변환(Transform), 로드(Load), 완료. 아무도 어제의 추출 데이터가 어떤 의미론적 관점에서 '신선하지 않은지(Stale)' 묻지 않습니다. 실행되었거나, 되지 않았거나 둘 중 하나일 뿐입니다.
ML 파이프라인은 그런 방식으로 작동하지 않습니다. 피처 테이블(Feature table)은 단순히 '계산됨' 또는 '계산되지 않음'의 상태가 아닙니다. 그것은 이를 소비하는 모델과 관련된 신선도 계약(Freshness contract)을 가집니다. 모델은 단순히 '학습됨'이 아닙니다. 모델은 특정 데이터 스냅샷(Snapshot)을 대상으로 학습되며, 만약 그 스냅샷이 조용히 드리프트(Drift)된다면, DAG 내의 모든 작업이 초록색 체크 표시를 보여주더라도 그 모델은 신선하지 않은(Stale) 상태가 됩니다. 작업은 실행되었습니다. 하지만 그 작업이 생성한 자산(Asset)은 더 이상 신뢰할 수 없습니다. 작업 기반 오케스트레이터는 이러한 간극을 설명할 어휘가 없습니다. 왜냐하면 애초에 실행(Run)을 추적했을 뿐, 자산(Asset)을 추적한 적이 없기 때문입니다.
재학습은 스케줄의 문제가 아닙니다
가장 명확한 증상은 재학습(Retraining) 로직에서 나타납니다. 작업(Task) 중심의 세계에서 재학습은 보통 크론 잡(Cron job)으로 덧붙여집니다. 즉, 의미 있는 변화가 있었는지 여부와 상관없이 매주 월요일마다, 혹은 매 N시간마다 재학습을 수행하는 식입니다. 그러면 팀들은 그 위에 드리프트 탐지기(Drift detectors)를 얹게 되고, 탐지기가 알람을 울리면 사람은 이를 다시 수동적인 DAG 트리거로 변환해야 합니다. 오케스트레이터(Orchestrator)와 실제 재학습의 이유는 서로 소통하지 않는 두 개의 서로 다른 시스템에 존재하게 됩니다.
근본적인 의존성은 "시간이 흘렀다"가 아닙니다. "입력 분포(Input distribution)가 충분히 변하여 현재 모델이 더 이상 그것의 유효한 함수가 아니다"라는 점입니다. 이것은 스케줄이 아니라 자산 상태(Asset-state)에 대한 의존성입니다. 이를 크론 잡으로 모델링하는 것은 데이터 상태를 일급 노드(First-class node)로 이해하는 그래프가 없기 때문에 사용하는 임시방편일 뿐입니다.
자산 중심 오케스트레이션(Asset-Centric Orchestration)이 실제로 바꾸는 것
Dagster의 소프트웨어 정의 자산(Software-defined assets)은 이러한 대안적 모델을 구현한 가장 명확한 주류 사례이지만, 중요한 것은 도구보다 그 개념 자체입니다. 우연히 데이터를 생성하는 작업들을 오케스트레이션하는 대신, 피처 테이블(Feature table), 임베딩 인덱스(Embedding index), 학습된 모델과 같은 데이터 객체 자체를 그래프의 노드로 선언합니다. 각 노드는 구체화 함수(Materialization function)를 가지며, 결정적으로 스케줄이 아닌 자산에 부착된 신선도 정책(Freshness policy)을 가집니다.
이것이 단순히 명칭의 차이처럼 들릴 수도 있습니다. 하지만 그렇지 않습니다. 자산이 오케스트레이션의 단위가 되면, 작업 중심 시스템에서는 사후에 덧붙이기가 매우 고통스러운 다음과 같은 속성들을 얻을 수 있습니다:
-
신선도 저하(Staleness)를 쿼리할 수 있게 됩니다. 실행 이력 전체를 로그 스크래핑(log-scraping)하는 수고 대신, 그래프 쿼리(graph query)를 통해 "이 모델의 학습 데이터가 신선도 계약(freshness contract)에서 허용하는 것보다 오래되었는가?"라고 물을 수 있습니다.
-
파티션(Partitions)이 네이티브하게 작동합니다. ML 데이터는 거의 항상 일자별, 고객 세그먼트별, 데이터 소스별로 파티셔닝되어 있으며, 백필(backfill)은 전체 파이프라인 실행이 아닌 자산의 특정 파티션에 대해 동작해야 합니다. 자산 그래프(Asset graphs)는 파티션 수준의 구체화(materialization) 상태를 추적하지만, 작업 그래프(task graphs)는 대부분 그렇지 않습니다. 이것이 바로 Airflow에서 피처 테이블(feature table)의 3일 치 데이터를 백필할 때, 파티션을 인식하도록 설계되지 않은 로직을 다시 실행해야 하는 이유입니다.
-
리니지(Lineage)가 자동으로 생성됩니다. 모델 자산이 피처 자산을 상위 의존성(upstream dependency)으로 선언하고, 피처 자산이 원천 수집(raw ingestion) 자산을 상위로 선언하면, 작업 로그 위에 별도의 메타데이터 추적 레이어를 덧붙이지 않고도 아티팩트(artifact) 수준의 리니지를 얻을 수 있습니다.
-
재학습 트리거(Retraining triggers)가 선언적으로 변합니다. "상위 피처 자산의 신선도 정책(freshness policy)이 위반되면 이 모델을 다시 구체화(rematerialize)하라"는 것은 크론 표현식(cron expression)과 별도의 알림(out-of-band alert)의 조합이 아닌, 하나의 그래프 규칙이 됩니다.
코드로서의 파이프라인(Pipelines-as-Code)이 여전히 중요한 지점 — 그리고 도움이 되지 않는 지점
코드로서의 파이프라인(Pipelines-as-code)은 그래프를 다른 소프트웨어 아티팩트처럼 검토 가능하고, 버전 관리 가능하며, 테스트 가능하게 만듦으로써 오케스트레이션(orchestration) 문제를 해결할 것으로 기대되었습니다. 이는 재시도(retries), 백오프(backoff), 리소스 할당, 비밀값(secrets), 스케줄링 구문과 같은 실행 메커니즘 측면에서는 그 약속을 이행했습니다. 하지만 이것이 해결하지 못한 것은 코드 아래에 깔린 추상화(abstraction)입니다. 여러분은 아름답게 테스트되고 버전 관리되는 Airflow DAG를 작성할 수 있지만, 그 DAG가 생성한 모델이 의미론적으로 신선한지는 여전히 알 수 없습니다. 왜냐하면 "신선함(freshness)\
이것이 바로 도구를 바꾼다고 해서 근본적인 문제가 저절로 해결되는 경우가 드문 이유이기도 합니다. 자산 (Asset) 모델이 자동으로 나타날 것이라 기대하며 Airflow에서 Dagster로 전환하는 팀들은 종종 실망하곤 합니다. 왜냐하면 자산 대신 작업 (Task)을 모델링하는 Dagster 코드를 작성하는 것도 충분히 가능하기 때문입니다. 프레임워크가 더 나은 기본 단위 (Primitive)를 제공할 뿐, 그것을 사용하도록 강제하지는 않습니다. 필요한 규율은 파이프라인의 노드 중 어떤 것이 추적할 가치가 있는 생명 주기를 가진 데이터 객체인지, 그리고 어떤 것이 기억할 만한 독립적인 상태가 없는 순수한 실행 단계인지를 명확히 식별하는 것입니다. 모든 것이 자산일 필요는 없습니다. 로깅 단계, 알림, 정리 작업 (Cleanup job) 등은 진정한 의미의 작업이며, 이를 자산 모델로 강제하는 것은 이득 없이 절차만 복잡하게 만듭니다.
실무적인 구분
유용한 설계 규칙은 "모든 곳에서 자산 기반의 오케스트레이션 (Orchestration)을 사용하라"는 것보다 더 좁습니다. 그것은 다음과 같습니다. 후속 소비자 (Downstream consumers)가 정확성을 위해 의존하는 모든 것 — 피처 (Features), 임베딩 (Embeddings), 모델 체크포인트 (Model checkpoints), 평가 데이터셋 (Evaluation datasets) — 은 코드를 실행하는 오케스트레이터가 무엇인지와 상관없이, 버전 관리와 신선도 (Freshness)를 인식하는 자산으로 모델링되어야 합니다. 파이프라인을 진행시키기 위해서만 존재하는 모든 것 — 재시도 (Retries), 결합 단계 (Glue steps), 오케스트레이션 제어 흐름 (Orchestration control flow) — 은 작업으로 남겨두어도 됩니다. 실행과 독립적으로 그 "상태 (State)"를 추적하는 것은 얻을 수 있는 이득이 없기 때문입니다.
Airflow도 최근 버전에서 추가된 데이터셋 (Datasets) 및 자산 인식 스케줄링 기능을 통해 이를 근사하게 구현할 수 있으며, 많은 팀이 순수한 작업 DAG 위에 외부 메타데이터나 피처 스토어 (Feature-store) 시스템을 계층화하여 실질적인 가치를 얻고 있습니다. 중요한 것은 도구가 아니라, 그래프를 구축하기 전에 코드 상에서 그 경계선을 명확히 긋는 규율입니다. 3주 전 데이터로 학습된 모델이 왜 파이프라인의 모든 작업을 통과했는지 누군가 질문했을 때, 3개월이 지나서야 그 사실을 깨닫는 것이 아니라 말입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기