Arhitectura datelor și a sistemelor, de la zero Lecția 57 / 80

Orchestrare în profunzime: Airflow, Prefect, Dagster, Argo Workflows

Cei patru pretendenți, când câștigă fiecare, încadrarea task-oriented vs asset-oriented și decizia gestionat vs self-hosted.

Modulul 7 s-a închis cu substratul de runtime: Kubernetes pentru majoritatea echipelor de date în 2026, cu operator pattern făcând munca grea pentru Spark, Flink și restul. Modulul 8 începe un strat mai sus. Acum că workload-urile au un loc unde să ruleze, ce le declanșează, în ce ordine, cu ce dependențe și ce le urmărește când eșuează? Asta e treaba orchestrator-ului, iar alegerea orchestrator-ului e una dintre deciziile mai importante pe care le ia o platformă de date.

Alegerea a devenit mai bogată în ultimii ani. Pentru cea mai mare parte a anilor 2010 „orchestrator” însemna efectiv Airflow, cu cron și scripturi făcute pe genunchi ca alternativă la scară mică. Până în 2026 sunt patru pretendenți serioși, fiecare cu o nișă defensabilă: Airflow, Prefect, Dagster și Argo Workflows. Nu sunt interschimbabili. Fac presupuneri diferite despre ce e un pipeline, ce stare deține orchestrator-ul și cum ar trebui să arate modelul mental al utilizatorului. Alegerea dintre ei e o decizie arhitecturală reală, nu o chestiune de gust.

Lecția asta parcurge ce face un orchestrator, apoi fiecare dintre cele patru, apoi încadrarea care ajută o echipă să aleagă: task-oriented vs asset-oriented (pe care lecția 58 o extinde) și gestionat vs self-hosted (care e de obicei decizia care se ia prima în practică).

Ce face de fapt un orchestrator

Dă la o parte marketingul și un orchestrator e responsabil pentru o listă mică, stabilă de treburi.

Planifică job-uri. Rulează acest pipeline la 02:00 în fiecare zi. Rulează-l pe ăsta când ajunge un fișier nou în S3. Rulează-l pe al treilea când un pipeline din amonte se termină cu succes.

Urmărește starea. Acest task e în coadă. Ăsta rulează. Celălalt s-a terminat la 02:14 cu cod de ieșire 0. Un istoric al ce task-uri au rulat, când și cum s-au terminat e log-ul persistent al orchestrator-ului despre ce a făcut sistemul tău de date.

Gestionează dependențele. Task-ul B depinde de task-ul A. Nu porni B până când A nu reușește. Dacă A eșuează, nu porni B. Dacă A întârzie, B așteaptă.

Reîncearcă la eșec. Eșecurile tranzitorii (un blip de rețea, un API flaky) ar trebui să reîncerce automat, cu backoff, până la o limită configurată. Eșecurile reale ar trebui să iasă la suprafață către un om.

Alertează la probleme. Un task eșuat, un task care a rulat prea mult timp, un SLA ratat: orchestrator-ul emite un semnal pe care un om îl prinde. Slack, PagerDuty, email, orice folosește echipa.

Îți dă un UI. Când ceva e greșit la 03:00 ai nevoie de un ecran care arată ultimele douăzeci și patru de ore de rulări, task-urile eșuate, log-urile și graful de dependențe, ideal fără să citești cod sursă.

Fiecare orchestrator face aceste lucruri. Diferențele sunt în cum le expun, ce alte lucruri aduc cu ele și ce presupuneri coc în model.

Airflow: originalul

Airflow a apărut din Airbnb în 2014, s-a alăturat incubatorului Apache în 2016 și a absolvit la statusul de proiect top-level în 2019. Maxime Beauchemin, autorul original, l-a scris ca răspuns la experiența dureroasă de a rula pipeline-uri batch prin cron și scripturi făcute în casă la o companie care scala rapid. Alegerea de design care a definit Airflow a fost DAG-uri Python-first: pipeline-urile sunt fișiere Python care importă operatori și-i leagă împreună, iar scheduler-ul citește acele fișiere ca să-și dea seama ce să ruleze.

Alegerea aceea taie în ambele sensuri.

Partea bună: un ecosistem enorm de operatori vine cu Airflow sau ca pachete de comunitate. BigQuery, Snowflake, Redshift, S3, GCS, Spark, dbt, Slack, serviciile de compute și storage ale fiecărui cloud major, fiecare unealtă majoră de date. Dacă vrei să orchestrezi ceva, operatorul probabil există. Anii 2020 au adus și deployment Kubernetes-native prin Helm chart-ul oficial și KubernetesExecutor (lecția 55), care lasă fiecare task să ruleze în propriul pod cu propriul buget de resurse și propria imagine de container.

Partea nu-așa-de-bună: DAG-urile ca fișiere Python amestecă orchestrarea cu logica. Scheduler-ul parsează periodic fiecare fișier de DAG, ceea ce înseamnă că importarea accidentală a unei biblioteci grele în vârful unui fișier de DAG face scheduler-ul lent. Backfill-urile (rerularea unui interval de date cu codul cel mai recent) erau dureroase înainte de Airflow 2.x și complet rezonabile doar de la 2.3 încolo. Migrarea 1.x la 2.x în 2020 a fost muncă reală de inginerie pentru shop-urile care construiseră infrastructură Airflow semnificativă.

Instalarea Airflow e grea după standardele moderne. Arhitectura implicită are un webserver, un scheduler, o bază de date de metadate (Postgres sau MySQL), un result backend și un pool de workeri (Celery, Kubernetes sau locali). Să rulezi asta singur sunt câteva zile de muncă ca să faci bine și o povară on-call continuă. Majoritatea shop-urilor în 2026 fie folosesc un Airflow gestionat (Astronomer, AWS MWAA, GCP Cloud Composer), fie au o echipă de platformă care îl menține ca serviciu împărtășit.

Când câștigă Airflow. Organizații mari care s-au standardizat deja pe el. Shop-uri care au nevoie de ecosistemul de operatori. Echipe ale căror pipeline-uri sunt predominant job-uri batch programate temporal cu DAG-uri lungi. Oriunde cu destulă scară încât „încă o unealtă” e o vânzare mai grea decât „unealta existentă, folosită bine”.

Prefect: răspunsul orientat pe experiența developer-ului

Prefect a început în 2018 ca răspunsul lui Jeremiah Lowin la fricțiunile pe care le-a întâlnit rulând Airflow la scară. Linia 1.x a fost o reimaginare de la zero; linia 2.x (2022) a fost o rescriere care a simplificat modelul mai departe; linia 3.x (2024) a strâns API-ul din nou. Funcționalitatea principală e experiența developer-ului: flow-urile sunt funcții Python decorate, dependențele sunt deduse din cum le apelezi, iar API-ul se simte mai aproape de scrierea de Python normal decât de autorarea unui DAG.

from prefect import flow, task

@task
def extract():
    return load_from_source()

@task
def transform(rows):
    return clean(rows)

@flow
def daily_etl():
    rows = extract()
    cleaned = transform(rows)
    write_to_warehouse(cleaned)

Ăsta e un flow Prefect funcțional. Dependența dintre extract și transform e implicită în fluxul de date. Nu există fișier de DAG de înregistrat, nici configurație de scheduler separată de scris. Flow-urile dinamice (unde forma DAG-ului depinde de date la runtime) sunt de prim rang, ceea ce Airflow suportă stângaci prin API-ul de dynamic task mapping, dar Prefect gestionează nativ.

Când câștigă Prefect. Echipe mai mici care valorează experiența developer-ului. Pipeline-uri a căror formă e dinamică (un fan-out peste un număr necunoscut de fișiere, un flow per-client al cărui număr variază de la zi la zi). Echipe care vor un orchestrator gestionat cu un nivel gratuit generos și onboarding cu fricțiune mică.

Compromisul e un ecosistem mai mic decât al Airflow. Prefect are integrări pentru uneltele de date majore, dar coada lungă de operatori de nișă pe care Airflow i-a acumulat de-a lungul unui deceniu nu e acolo. Majoritatea echipelor nu lovesc asta în practică; apare la margini.

Dagster: răspunsul asset-oriented

Dagster, tot din 2019, a luat o lovitură diferită. Insight-ul de bază: orchestrator-ii care gândesc în task-uri ratează ce le pasă efectiv inginerilor de date, care sunt assets-urile pe care le produce pipeline-ul. Un task e un mijloc spre un scop. Scopul e tabela de clienți, mart-ul de venituri zilnic, artefactul de model antrenat. Așa că fă asset-ul unitatea de orchestrare.

În Dagster, declari assets:

from dagster import asset

@asset
def raw_events():
    return load_from_kafka()

@asset
def sessionized_events(raw_events):
    return sessionize(raw_events)

@asset
def customer_lifetime_value(sessionized_events):
    return compute_clv(sessionized_events)

Dependențele dintre assets sunt citite din semnăturile funcțiilor. Dagster construiește graful de assets automat. Lineage-ul nu e ceva ce adaugi; e modelul. Orchestrarea (ce task rulează când) e derivată din graful de assets, nu declarată separat.

Schimbarea asta, pe care lecția 58 o explorează în profunzime, are consecințe. Lineage-ul vine pe gratis. Modelele dbt sunt assets de prim rang, nu task-uri opace pe care orchestrator-ul le rulează. Inputurile și outputurile tipate îi permit lui Dagster să valideze la runtime că un asset a produs efectiv ce a pretins. UI-ul arată prospețimea asset-urilor („ultima dată materializat acum două ore”) în loc de doar starea task-ului („reușit la 02:14”).

Când câștigă Dagster. Echipe care țin la lineage, calitatea datelor și disciplina de inginerie software aplicată datelor. Utilizatori grei de dbt care vor ca orchestrator-ul și unealta de transformare să împartă vocabularul. Platforme noi fără moștenire de orchestrator unde modelul asset-oriented poate fi adoptat din ziua întâi.

Compromisurile sunt buy-in conceptual (echipa trebuie să învețe să gândească în assets, nu în task-uri) și un ecosistem mai mic decât al Airflow, deși decalajul s-a strâns. Migrarea unui shop Airflow existent la Dagster e un proiect real, nu un weekend.

Argo Workflows: răspunsul nativ Kubernetes

Argo Workflows e cel ciudat din listă. N-a fost construit primar pentru date; a fost construit pentru Kubernetes. Fiecare pas într-un workflow Argo e un pod. Workflow-ul însuși e o resursă custom Kubernetes definită în YAML. Orchestrator-ul e un controller care urmărește resurse de workflow și le reconciliază, același pattern ca Spark Operator și restul ecosistemului Kubernetes (lecția 55).

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  name: daily-etl
spec:
  entrypoint: pipeline
  templates:
    - name: pipeline
      dag:
        tasks:
          - name: extract
            template: extract-step
          - name: transform
            template: transform-step
            dependencies: [extract]

Argo e popular pentru pipeline-uri ML (Kubeflow Pipelines e construit pe Argo) și pentru orchestrare generală de workflow-uri în shop-uri care s-au angajat ferm la Kubernetes. Scalează la mii de pod-uri concurente. E rapid, simplu și se aliniază bine cu restul unei stive cloud-native.

Când câștigă Argo. Echipe ML-grele care folosesc Kubeflow. Echipe de platformă care vor ca orchestrator-ul lor să se simtă ca restul Kubernetes. Workload-uri dominate de rulări scurte, paralele de containere mai degrabă decât job-uri batch cu durată lungă cu semantică bogată de date.

Compromisul e YAML-ul și suportul mai slab pentru preocupări specifice de date. Argo nu știe ce e un query Snowflake. N-are integrare nativă dbt. Lineage-ul e ce-i atașezi tu. Pentru pipeline-uri care sunt în mare parte „rulează acest Python într-un container, apoi rulează-l pe ăla”, Argo e grozav. Pentru pipeline-uri care sunt în mare parte „rulează această transformare Snowflake, apoi acest model dbt, apoi publică în BigQuery”, un orchestrator cu integrări de date de prim rang e de obicei o potrivire mai bună.

Gestionat vs self-hosted

Alegerea orchestrator-ului se încurcă, în practică, cu alegerea gestionat-vs-self-hosted. Majoritatea shop-urilor în 2026 aterizează pe gestionat, iar raționamentul e consecvent.

Self-hosting-ul unui orchestrator înseamnă rularea bazei lui de date de metadate (de obicei Postgres), a scheduler-ului lui, a workerilor lui, a UI-ului lui, a logicii lui de retry, a stocării lui de log-uri. Pentru Airflow asta e o jumătate de duzină de componente cu propriile poveri de scalare și upgrade. Pentru Prefect, Dagster, Argo, ușor mai puțin dar tot real. Oricine a rulat upgrade-uri Airflow de la 1.10 la 2.x și apoi 2.x la 2.7 cunoaște taxa operațională.

Ofertele gestionate absorb taxa aia în schimbul banilor: Astronomer (Airflow), Prefect Cloud, Dagster Cloud, Databricks Workflows (propriul orchestrator, integrează cu job-urile Databricks), AWS MWAA (Airflow gestionat), GCP Cloud Composer (Airflow gestionat), Azure Data Factory (orchestrator-ul Microsoft). Prețurile variază, dar pentru majoritatea echipelor matematica e „plătim zeci de mii pe an, salvăm o lună-inginer pe an la operațiuni de cluster și avem un vendor pe care să-l sunăm când scheduler-ul moare duminica”.

Excepțiile sunt organizațiile destul de mari încât să staffeze o echipă dedicată de platformă care rulează orchestrarea ca serviciu împărtășit și organizațiile cu constrângeri de reglementare care fac un SaaS gestionat dificil. Ambele sunt reale, ambele sunt comune la scară și ambele implică schimbarea banilor pentru control.

Arborele de decizie

Punând la un loc, arborele de decizie aproximativ pe care-l parcurg majoritatea echipelor:

flowchart TD
    Q1{Pipeline complexity?}
    Q1 -->|Few jobs, simple deps| CRON[cron + scripts]
    Q1 -->|Real DAGs, real ops| Q2{Asset model fits?}
    Q2 -->|Yes, lineage matters| Q3a{Managed?}
    Q2 -->|No, task-oriented OK| Q3b{Existing tool?}
    Q3a -->|Yes| DC[Dagster Cloud]
    Q3a -->|No, want to host| DAGSTER[Self-host Dagster]
    Q3b -->|Yes, Airflow| Q4{Managed?}
    Q3b -->|No, fresh start| Q5{Style?}
    Q4 -->|Yes| AST[Astronomer/MWAA/Composer]
    Q4 -->|No| AF[Self-host Airflow]
    Q5 -->|Pythonic, dynamic| PRE[Prefect]
    Q5 -->|K8s-native, simple| ARGO[Argo Workflows]

Diagramă de creat: o versiune îngrijită a arborelui de decizie de mai sus, cu cei patru orchestratori frunză distinși vizual. Punctul e că alegerea se împarte curat pe trei axe (asset vs task, gestionat vs self-hosted, potrivire de ecosistem) și că toate cele patru frunze sunt răspunsuri defensabile pentru o anumită echipă.

Același ETL simplu exprimat în Airflow vs Dagster schițează diferența. Airflow:

with DAG("daily_etl", schedule="@daily") as dag:
    e = PythonOperator(task_id="extract", python_callable=extract)
    t = PythonOperator(task_id="transform", python_callable=transform)
    l = PythonOperator(task_id="load", python_callable=load)
    e >> t >> l

Dagster:

@asset
def raw_data():
    return extract()

@asset
def cleaned_data(raw_data):
    return transform(raw_data)

@asset
def warehouse_table(cleaned_data):
    return load(cleaned_data)

Același pipeline, modele mentale diferite. Airflow e „rulează aceste task-uri în ordine pe acest schedule”. Dagster e „astea sunt assets-urile pe care le produci; dă-ți seama cum să le ții proaspete”. Lecția următoare e despre de ce încadrarea aceea a doua schimbă cum gândesc echipele la scară.

Ce a pregătit lecția asta

Treaba Modulului 8 e să ia arhitectura care rulează și s-o facă operabilă: orchestrare (lecția asta), încadrare asset-oriented (lecția următoare), observabilitate (lecția 59), practici de fiabilitate (restul modulului). Orchestrator-ul e coloana vertebrală. Alegerea pe care o faci aici se propagă în fiecare altă decizie: cum instrumentezi lineage-ul, cum gestionezi retry-urile, cum definești un SLO pentru un produs de date. Alegerea deliberată merită timpul.

Pentru majoritatea shop-urilor de date medii spre mari în 2026, răspunsul practic e unul din: Airflow gestionat dacă ai o moștenire Airflow, Dagster Cloud dacă începi proaspăt și ții la produsele de date, Prefect Cloud dacă vrei experiența developer-ului și ai workflow-uri dinamice, Argo dacă platforma ta e Kubernetes-first și workload-urile tale sunt în formă de container. Toate cele patru sunt bune. Cel care se potrivește modelului mental al echipei tale și infrastructurii tale existente e aproape întotdeauna cel potrivit.

Citări și lectură suplimentară

  • Documentația Apache Airflow, https://airflow.apache.org/docs/ (consultat 2026-05-01). Referința oficială pentru orchestrator-ul original, catalogul lui de operatori și integrările Kubernetes.
  • Documentația Prefect, https://docs.prefect.io/ (consultat 2026-05-01). Documentația 3.x acoperă flow-uri, task-uri, deployment-uri și modelul de execuție hibridă.
  • Documentația Dagster, https://docs.dagster.io/ (consultat 2026-05-01). Modelul asset-oriented e inima documentației; integrările dbt și Snowflake sunt puncte de pornire utile.
  • Documentația Argo Workflows, https://argo-workflows.readthedocs.io/ (consultat 2026-05-01). Motorul de workflow nativ Kubernetes, cu referințele YAML și operator-pattern.
  • Maxime Beauchemin, „The Rise of the Data Engineer” și anunțurile originale Airflow pe blogul de inginerie Medium (2017 încoace). Context util despre de ce Airflow există în forma în care e.
Caută