- Netflix가 대규모 Data/ML 워크플로우용 수평 확장 오케스트레이터 Maestro를 오픈소스로 공개했고, 내부에서는 수십만 개 워크플로우를 최소 중단으로 이전해 운영 중임
- DAG 중심 오케스트레이터와 달리 비순환·순환 워크플로우를 함께 다루며, foreach 루프·서브워크플로우·조건 분기를 엔진 수준 패턴으로 제공함
- 지난 1년간 실행 작업 수가 87.5% 증가했고, 현재 하루 평균 수천 개 워크플로우 인스턴스와 약 50만 개 작업을 실행하며 바쁜 날에는 약 200만 개 작업을 완료함
- JSON 기반 정의에 실행 전략, 파라미터, SEL 표현식, 신호, 브레이크포인트, 타임라인, 재시도 정책, 롤업을 결합해 운영 제어와 디버깅을 지원함
- Netflix처럼 데이터 테이블이 단일 데이터 웨어하우스에 모인 환경에서는 워크플로우를 여러 클러스터로 나누면 조정 비용과 사용자 경험 저하가 커져, 단일 오케스트레이터가 전체 흐름을 맡는 구조가 중요함
Maestro 공개와 Netflix 내 운영 규모
- Netflix는 Maestro GitHub repository를 통해 Maestro 소스 코드를 공개함
- Maestro는 데이터 파이프라인과 머신러닝 모델 학습 파이프라인 같은 대규모 Data/ML 워크플로우를 관리하는 수평 확장 워크플로우 오케스트레이터임
- 워크플로우의 시작부터 종료까지 전체 수명주기를 관리하며, 재시도·큐잉·컴퓨트 엔진으로의 작업 분배를 처리함
- 사용자는 비즈니스 로직을 Docker 이미지, 노트북, bash 스크립트, SQL, Python 등 다양한 형식으로 패키징할 수 있음
- Netflix는 기존에 소개한 뒤 수십만 개 워크플로우를 Maestro로 이전했고, 전환 과정에서 사용자 중단을 최소화함
- 최근 운영 규모:
- 지난 1년 동안 실행 작업 수가 87.5% 증가
- 하루 평균 수천 개 워크플로우 인스턴스 실행
- 하루 평균 약 50만 개 작업 실행
- 바쁜 날에는 약 200만 개 작업 완료
단일 오케스트레이터로 확장성과 다양성 지원
- Maestro는 Netflix 내부에서 수천 명의 최종 사용자, 애플리케이션, 서비스에 Workflow-as-a-Service를 제공하는 완전 관리형 오케스트레이터임
- ETL 파이프라인, ML 워크플로우, AB 테스트 파이프라인, 여러 스토리지 간 데이터 이동 파이프라인을 지원함
- 수평 확장 구조는 많은 워크플로우 수와 단일 워크플로우 내부의 많은 작업 수를 모두 처리하도록 설계됨
- Netflix의 워크플로우는 서로 촘촘히 연결되어 있어, 작은 그룹으로 나눠 여러 클러스터에서 관리하면 추가 조정 메커니즘이 필요하고 사용자 경험이 떨어짐
- 데이터 테이블이 단일 데이터 웨어하우스에 있으므로, 여기에 접근하는 모든 워크플로우를 단일 오케스트레이터가 처리해야 한다는 판단임
워크플로우 정의 모델
- Maestro의 워크플로우 정의는 JSON 형식으로 작성됨
- 사용자 제공 필드와 Maestro 관리 필드를 결합해 오케스트레이션 정의를 구성하며, 예시는 Maestro repository wiki에 있음
- 워크플로우 정의는 크게 두 영역으로 나뉨
- properties: 작성자·소유자 정보와 실행 설정 포함
- versioned workflow: 워크플로우 메타데이터와 그래프 정의 포함
- properties는 워크플로우 버전이 바뀌어도 작성자·소유자 정보, 실행 전략, 동시성 설정 같은 핵심 속성을 보존함
- 소유권이 바뀐 경우 새 워크플로우 버전을 만들지 않고 새 소유자가 기존 워크플로우 소유권을 가져올 수 있음
- versioned workflow는 고유 식별자, 이름, 설명, 태그, 타임아웃 설정, 우선순위화를 위한 criticality 수준 low·medium·high를 포함함
- 워크플로우 변경은 새 버전을 만들며, 기본적으로 활성 버전이나 최신 버전이 사용됨
- 워크플로우는 사용자가 정의한 그래프의 노드인 step으로 구성됨
- step은 작업, subworkflow step을 통한 다른 워크플로우, foreach step을 통한 루프를 나타낼 수 있음
- step에는 고유 식별자, step 유형, 태그, 입출력 파라미터, 의존성, 재시도 정책, 실패 모드, step 출력 등이 포함됨
- 오류 유형별로 설정 가능한 재시도 정책을 지원함
실행 순서를 제어하는 Run Strategy
- Maestro는 사전 정의된 run strategy로 새 워크플로우 인스턴스를 실행할지 결정함
-
Sequential Run Strategy
- 기본 전략이며, FIFO 순서로 한 번에 하나씩 실행함
- 이전 실행의 성공 여부와 무관하게, 인스턴스가 성공 또는 실패 같은 종료 상태에 도달하면 큐의 다음 인스턴스를 시작함
-
Strict Sequential Run Strategy
- 트리거된 순서대로 실행하지만, 이전 인스턴스 이력에 blocking error가 있으면 실행을 막음
- 실패한 인스턴스를 수동으로 재시작하거나 unblock 처리할 때까지 새 인스턴스는 큐에 남음
- 시간 민감도는 낮지만 비즈니스 중요도가 높은 워크플로우에 유용함
-
First-only Run Strategy
- 실행 중인 워크플로우가 완료되기 전에는 새 인스턴스를 큐에 유지하지 않음
- 현재 실행 중인 인스턴스가 있으면 새로 큐에 들어온 인스턴스를 제거해 큐잉을 사실상 끔
- 새 인스턴스를 쌓지 않아 멱등성 문제를 피하는 데 도움됨
-
Last-only Run Strategy
- 항상 가장 최근 트리거된 인스턴스가 실행되도록 함
- 기존 실행 중 인스턴스가 있으면 중단하고 새로 트리거된 인스턴스를 실행함
- 매번 전체 테이블의 최신 스냅샷을 처리하는 워크플로우처럼 최신 데이터만 필요한 경우에 유용함
-
Parallel with Concurrency Limit Run Strategy
- 사전 정의된 동시성 한도 안에서 여러 인스턴스를 병렬 실행함
- 많은 데이터를 제한 시간 안에 처리하도록 실행을 fan-out하고 분산할 수 있음
- 오래된 데이터 백필이 일반적인 사용 사례임
파라미터와 SEL 표현식
- Maestro에서 파라미터는 실행 로직 제어, 워크플로우와 step 간 상태 공유, 업스트림과 다운스트림 step 간 상태 공유에 쓰임
- Maestro는 코드 주입을 동반한 동적 파라미터를 지원해 복잡한 파라미터화 워크플로우를 정의할 수 있게 함
- 코드 주입은 보안과 안정성 위험을 만들 수 있음
- 사용자가 무한 루프를 작성해 배열에 계속 항목을 추가하면 서버가 OOM으로 중단될 수 있음
- 주입 코드를 비즈니스 로직 안으로 옮기면 사용자 부담이 늘고 워크플로우 정의와 비즈니스 로직이 강하게 결합됨
- Netflix는 이를 완화하기 위해 자체 표현식 언어인 SEL(Simple, Secure, and Safe Expression Language) 을 개발함
- SEL은 Java Language Specifications의 문법과 구문을 따르되 Maestro 사용 사례에 맞춘 부분집합을 지원함
- SEL은 Maestro 파라미터 타입의 데이터 타입, 오류 발생, 날짜·시간 처리, 사전 정의 유틸리티 메서드를 지원함
- 안정성을 위해 루프 반복 제한, 배열 크기 검사, 객체 메모리 크기 제한 같은 런타임 검사를 포함함
- SEL 문서는 Maestro GitHub documentation에 있음
출력 파라미터와 파라미터화 워크플로우
- Maestro는 callable step execution을 통해 사용자 실행 결과를 출력 파라미터로 시스템에 돌려줄 수 있음
- 출력 데이터는 Maestro REST API를 통해 전달되며, step 런타임이 Maestro 데이터베이스에 직접 접근하지 않음
- 정적 워크플로우는 단순하지만 작은 차이를 반영하려면 같은 워크플로우를 여러 번 복제해야 할 수 있고, 파라미터 없이는 워크플로우와 작업이 상태를 공유할 수 없음
- 완전 동적 워크플로우는 관리와 지원이 어렵고, 디버깅·문제 해결·재사용도 힘듦
- 파라미터화 워크플로우는 사용자 정의 파라미터를 기반으로 런타임에 step별로 초기화되어, 실행 시점 제어의 유연성과 관리 가능성을 함께 제공함
- Maestro의 파라미터 지원은 백필 데이터 파이프라인 같은 복잡한 파라미터화 워크플로우 생성을 가능하게 함
엔진 수준의 워크플로우 실행 패턴
- Maestro는 공통 데이터플로우와 워크플로우 패턴을 엔진에서 직접 지원함
- 엔진 직접 지원으로 패턴 최적화와 일관된 구현 방식이 가능해짐
-
Foreach
- foreach 패턴은 원래 워크플로우 정의 안의 전용 step으로 모델링됨
- foreach 루프의 각 반복은 내부적으로 별도의 워크플로우 인스턴스로 처리됨
- foreach 정의 블록 안의 step 실행, 즉 sub-graph 실행은 별도의 워크플로우 인스턴스에 위임됨
- foreach step은 각 반복을 담당하는 워크플로우 인스턴스 상태를 모니터링하고 수집함
- 반복별로 다른 파라미터로 같은 작업을 실행하는 데이터 백필이나 머신러닝 모델 튜닝에 자주 사용됨
- 사용자가 수십만 개 반복을 워크플로우 정의에 직접 작성하지 않아도 되며, foreach 범위가 바뀔 때 새 워크플로우를 만들 필요도 줄어듦
-
Conditional Branch
- 조건 분기는 업스트림 step의 특정 조건이 충족될 때만 이후 step을 실행하게 함
- 조건은 SEL 표현식으로 정의되고 런타임에 평가됨
- 감사 체크 step이 실패했을 때 복구 작업을 수행한 뒤 다시 작업을 실행하는 흐름을 구성할 수 있음
-
Subworkflow
- subworkflow는 하나의 워크플로우 step이 다른 워크플로우를 실행하게 해 공통 기능을 여러 워크플로우에서 공유할 수 있게 함
- “workflow as a function” 형태로 워크플로우 그래프를 구성할 수 있음
- Netflix에서는 여러 팀이 제공하는 subworkflow를 조합해 수백 개 테이블의 데이터를 처리하는, 수백 개 subworkflow로 구성된 복잡한 워크플로우도 관찰됨
- foreach, 조건 분기, subworkflow는 함께 조합할 수 있음
- subworkflow 집합을 루프로 처리할 수 있음
- 중첩 foreach 루프를 실행할 수 있음
- 조건 분기와 subworkflow를 함께 사용해 오류를 처리하고 작업을 자동 재시도하는 자동 복구 워크플로우를 만들 수 있음
Step Runtime과 파라미터 병합
- Maestro는 실행 시점의 작업을 설명하기 위해 step runtime을 사용함
- step runtime 인터페이스는 두 가지 정보를 정의함
- step 인스턴스의 실행 동작을 제어하는 기본 API 집합
- step 런타임 상태와 실행 결과를 추적하는 단순 데이터 구조
- Maestro는 foreach step runtime, subworkflow step runtime 같은 구현을 제공함
- 각 구현은 start, execute, terminate 동작에 대한 자체 로직을 정의함
- 런타임 상태는 step의 다음 상태 전이를 결정하고 실패 또는 종료 여부를 판단하는 데 사용됨
- 실행 결과는 step 아티팩트와 step 실행 이력 타임라인을 담으며, 이후 step에서 접근할 수 있음
-
Step Parameter Merging
- Maestro는 step 동작을 동적으로 제어하기 위해 runtime parameter와 tag 주입을 지원함
- step parameter map은 처음에는 비어 있고, 다음 순서로 병합됨
- Default General Parameters:
workflow_instance_id,step_instance_uuid,step_attempt_id,step_id같은 모든 step의 기본 파라미터이며 Maestro 내부 예약값으로 사용자가 전달할 수 없음 - Injected Parameters: step runtime에서 동적으로 생성되는 파라미터이며, step 유형별 schema에 따라 달라질 수 있음
- Default Typed Parameters: 특정 step 유형에 관련된 기본 파라미터로, foreach step의
loop_params,loop_index등이 해당함 - Workflow and Step Info Parameters:
workflow_id같은 step과 워크플로우 관련 식별 정보 - Undefined New Parameters: 워크플로우 인스턴스 시작 또는 재시작 시 사용자가 새로 지정한 step 파라미터
- Step Definition Parameters: 정의 시점에 사용자가 작성한 step 파라미터
- Run and Restart Parameters: 시작 또는 재시작 시 사용자가 기존 정의 파라미터를 덮어쓰기 위해 제공한 값이며, 가장 마지막에 병합됨
Step Dependencies와 Signal
- Maestro 워크플로우 그래프의 step은 step dependency로 실행 의존성을 표현할 수 있음
- step dependency는 step 실행에 필요한 데이터 관련 조건을 지정함
- 조건은 보통 signal을 기반으로 정의됨
- signal은 파라미터 값 같은 정보를 담은 메시지이며, step 출력이나 SNS·Kafka 같은 외부 시스템을 통해 발행될 수 있음
- signal은 trigger 패턴과 publisher-subscriber 형태의 signal dependency 패턴에 모두 사용됨
- 하나의 step은 출력 signal을 발행해 해당 signal에 의존하는 여러 step의 실행을 풀 수 있음
- signal definition은 매핑된 파라미터 목록을 포함하며, Maestro는 일부 필드만으로 signal matching을 수행할 수 있음
- Maestro는 signal 파라미터 값에 대해
<,>같은 signal operators를 지원함 - Netflix는 signal 개념 위에 여러 추상화를 구축함
- ETL 워크플로우가 테이블을 갱신하고 signal을 보내면, 해당 데이터에 의존하는 다운스트림 워크플로우 step이 실행될 수 있음
- signal lineage는 과거 signal 인스턴스와 해당 signal을 발행하거나 소비한 워크플로우 step을 탐색할 수 있게 함
- signal trigger는 하나 또는 조인된 signal 집합을 구독하는 워크플로우에 대해 exactly-once execution을 보장함
- 지정된 signal 조건이 충족될 때만 워크플로우나 step을 실행하므로 리소스를 절약할 수 있음
디버깅과 실행 가시성
-
Breakpoint
- Maestro는 워크플로우 step에 브레이크포인트를 설정할 수 있음
- 워크플로우 인스턴스가 브레이크포인트가 걸린 step에 도달하면 해당 step은 paused 상태가 됨
- 사용자가 수동으로 재개할 때까지 워크플로우 그래프 진행이 멈춤
- 같은 워크플로우 step의 여러 인스턴스가 브레이크포인트에서 멈춘 경우, 하나를 재개해도 해당 인스턴스만 영향을 받고 나머지는 paused 상태로 유지됨
- 브레이크포인트를 삭제하면 멈춰 있던 모든 step 인스턴스가 재개됨
- 초기 워크플로우 개발 중 step 실행과 출력 데이터를 점검하는 데 유용함
- foreach 패턴에서 단일 step에 브레이크포인트를 걸면 모든 반복이 해당 step에서 멈춰 디버깅할 수 있음
- 실행 중 사람의 개입이나 실행 중 step 상태 변경 지원에도 사용할 수 있음
-
Timeline
- Maestro는 step 실행 타임라인을 포함하며, 상태 머신 변경과 그 이유 같은 주요 이벤트를 기록함
- 예시 이벤트에는
Created,Evaluating params같은 전이가 포함됨 - 구현된 step runtime은 최종 사용자에게 실행 정보를 보여주기 위해 타임라인 이벤트를 추가할 수 있음
- 타임라인 예시는 sample-step-instance-failed.json에 있음
재시도, Aggregated View, Rollup
-
Retry Policies
- Maestro는 실패로 종료 상태에 도달한 step에 대해 재시도 정책을 지원함
- 사용자는 재시도 횟수, 재시도 간 지연, 고정 간격 재시도, exponential backoff 전략을 설정할 수 있음
- 재시도는 두 유형으로 구분됨
- platform retry: 사용자 로직과 무관한 플랫폼 수준 오류 대응
- user retry: 사용자 정의 조건에 따른 재시도
- 각 유형은 별도 재시도 정책을 가질 수 있음
- 자동 재시도는 사용자 개입 없이 해결 가능한 일시적 오류 처리에 유용함
- 멱등성이 없는 step은 재시도를 피하기 위해 재시도 횟수를 0으로 설정할 수 있음
-
Aggregated View
- 하나의 workflow instance가 여러 run을 가질 수 있으므로, 사용자가 모든 step의 집계 상태를 볼 수 있어야 함
- aggregated view는 기본 aggregated view와 현재 run의 step 상태를 병합해 계산됨
- 예를 들어 첫 실행에서 step1·step2는 성공, step3는 실패, step4·step5는 시작 전인 경우 재시작은 step3부터 시작하고 step1·step2는 이전 성공 상태 때문에 skip될 수 있음
- 모든 step이 성공하면 aggregated view는 전체 step의 run 상태를 보여줌
-
Rollup
- rollup은 workflow instance의 상위 수준 요약을 제공하며, 각 step 상태와 상태별 step 수를 나타냄
- 현재 인스턴스와 subworkflow·foreach 같은 중첩 non-inline workflow의 step을 펼쳐 집계함
- 성공한 workflow가 세 step을 갖고, 그중 하나가 다섯 step짜리 subworkflow라면 rollup은 성공 step 수를 7개로 표시함
- rollup에서는 leaf step만 집계하며, 다른 step은 구체적 워크플로우를 가리키는 포인터로 취급됨
- 성공하지 않은 step의 참조도 보존해, 중첩 워크플로우 안의 문제 step으로 이동할 수 있게 함
- aggregated rollup은 현재 run의 runtime data와 base rollup을 결합해 계산됨
- subworkflow step의 rollup은 subworkflow instance의 rollup을 그대로 반영함
- foreach step의 rollup은 이전 실행에서 재시작 대상 반복을 제외한 base rollup과 현재 실행 중 반복들의 rollup을 결합함
- 이 과정 때문에 rollup 모델은 eventually consistent이며, 중첩 foreach와 subworkflow가 여러 단계로 들어가면 계산이 복잡하고 재귀적일 수 있음
이벤트 발행과 외부 연동
- 워크플로우 정의, workflow instance, step instance가 변경되면 Maestro는 이벤트를 생성하고 내부 처리 후 외부 시스템에 발행함
- Maestro 이벤트는 내부 이벤트와 외부 이벤트로 나뉨
- internal event: workflow, workflow instance, step instance 수명주기 내부 변경을 추적하며 내부 큐에 발행됨
- external event: 다운스트림 서비스가 소비할 Maestro 상태 변경 정보를 담아 SNS·Kafka 같은 외부 큐로 전송됨
- Maestro event processor는 내부 큐를 구독해 internal event를 가져오고, 이벤트 유형에 따라 처리한 뒤 필요하면 external event로 변환함
- 마지막 단계의 notification publisher가 외부 이벤트를 발행해 다운스트림 서비스가 소비할 수 있게 함
- 다운스트림 서비스는 대부분 이벤트 기반이며, Maestro event는 Maestro의 다양한 변경을 감지하는 데 필요한 메시지를 담음
- 변경 유형은 크게 두 범주로 나뉨
- workflow change: 워크플로우 정의나 properties 변경 같은 워크플로우 수준 동작
- instance status change: workflow instance 또는 step instance의 상태 전이
시작 방법
- Maestro 코드는 github.com/Netflix/maestro에서 확인할 수 있음
- 질문, 의견, 코멘트는 Maestro 저장소의 GitHub issue로 남길 수 있음
- Netflix는 Maestro가 제공하는 확장성과 사용성이 Netflix 외부의 워크플로우 개발도 빠르게 할 수 있기를 기대함