Multi-Team 자산 이벤트 필터링과 메트릭
Apache Airflow Official Documentation (in-repo snapshot) — Apache Software Foundation core-concepts/multi-team.rst - Team-Based Asset Event Filtering, Team-based Metrics, Important Considerations (L666-1156)
이 모듈을 다 읽으면
- producer_teams와 consumer_teams가 각각 자산의 어느 쪽(소비자/생산자)에서 선언되는지 구분할 수 있다
- 두 opt-in이 AND로 결합된다는 규칙을 판례 표를 근거로 적용할 수 있다
- 팀 없는(teamless) Dag 생산자와 팀 없는 API 사용자가 다르게 취급되는 이유를 설명할 수 있다
Multi-Team 모드에서는 한 팀의 자산 이벤트가 의도치 않게 다른 팀의 Dag run을 트리거하지 않도록, 자산 이벤트가 팀 소속에 따라 필터링된다. 이 모듈은 기본 동작, 소비자·생산자 양쪽에서 각각 선언하는 producer_teams/consumer_teams opt-in과 그 AND 결합 규칙, teamless 생산자·API 사용자의 특수 취급, 그리고 팀 기반 메트릭과 배포 시 주의사항(전역 유일성 등)을 다룬다.
기본 동작: 같은 팀끼리만 자산 이벤트가 전달된다
Multi-Team이 켜지면, 자산 이벤트는 하류 Dag run을 트리거하기 전에 팀 소속에 따라 필터링된다. 이는 한 팀의 Dag가 만든 자산 이벤트가 의도치 않게 다른 팀의 Dag run을 트리거하는 것을 막기 위함이다. 기본 동작으로는, 소비하는 Dag는 같은 팀에 속한 생산자, 또는 팀이 없는(teamless, 글로벌) Dag가 만든 자산 이벤트만 받는다.
핵심 포인트
- 기본적으로 소비 Dag는 자기 팀이 생산한 이벤트, 또는 팀 없는(글로벌) Dag가 생산한 이벤트만 받는다
- 이 필터링의 목적은 한 팀의 자산 이벤트가 의도치 않게 다른 팀의 run을 트리거하는 것을 막는 것이다
producer_teams와 consumer_teams — 두 방향의 opt-in
producer_teams는 소비자(consumer) 쪽 — 즉 Dag의 schedule에 쓰이는 자산 정의 — 에서 AssetAccessControl로 선언한다. 이 소비자가 자기 팀 이벤트 외에 추가로 받아들일 생산자 팀 목록을 나열하며, 생산자 쪽 자산에 allow_global=False가 설정되어 있으면 팀 없는 Dag 생산자는 이 소비자를 트리거할 수 없다.
consumer_teams는 생산자(producer) 쪽 — 즉 태스크의 outlet에 쓰이는 자산 정의 — 에서 선언하며, 그 특정 태스크가 만든 이벤트를 어떤 소비자 팀들이 받을 수 있는지를 제어한다. 기본값 None은 빈 리스트([])와 다르다: None(기본값, 또는 필드 생략)은 소비자-팀 제한이 전혀 없다는 뜻으로, 크로스팀 전달은 오로지 각 소비자 자신의 producer_teams opt-in에 의해서만 결정된다. 명시적인 빈 리스트([])는 전달을 생산자의 자기 팀(과 allow_global에 따른 teamless 소비자)로만 제한한다 — 이는 producer_teams로 opt-in한 소비자라도 포함해 모든 크로스팀 소비자를 차단한다. ["team_x", ...]처럼 팀을 나열하면 그 팀들에게 추가로 전달된다.
consumer_teams는 자산 단위가 아니라 '생산 태스크' 단위로 스코프된다. 같은 자산 이름에 대해 여러 태스크가 이벤트를 만든다면, 각 태스크의 consumer_teams는 그 태스크가 만드는 이벤트에만 독립적으로 적용된다.
두 필터는 논리적 AND로 결합된다. 소비 Dag가 큐잉되려면 producer_teams 검사(소비자 자신의 opt-in: "나는 어떤 생산자 팀의 이벤트를 받아들이는가?")와 consumer_teams 검사(생산자 자신의 opt-in: "나는 어떤 소비자 팀에게 전달하는가?") 둘 다 통과해야 한다.
핵심 포인트
- producer_teams는 소비자 쪽 자산 정의에, consumer_teams는 생산자 쪽(태스크의 outlet) 자산 정의에 선언한다
- consumer_teams=None(기본, 미지정)은 제한 없음을, consumer_teams=[](명시적 빈 리스트)는 자기 팀 외 모든 크로스팀 소비자 차단을 의미한다 — 이 둘은 다르다
- producer_teams와 consumer_teams는 AND로 결합되므로, 소비자가 큐잉되려면 두 조건을 모두 통과해야 한다
- consumer_teams는 자산이 아니라 '생산 태스크' 단위로 스코프된다 — 같은 자산이라도 태스크마다 다르게 설정할 수 있다
Teamless 생산자/소비자와 API 트리거의 특수 규칙
팀이 없는(글로벌) Dag 생산자는 allow_global=True(기본값)일 때, consumer_teams가 추가로 제한하지 않는 한 팀과 무관하게 모든 소비자를 트리거할 수 있다. allow_global=False면 팀에 소속된 소비자를 트리거하는 것이 차단된다. 팀 없는 소비자는 생산자 쪽 자산에 allow_global=False가 설정되지 않은 한, 소스(Dag든 API든)와 팀 여부·consumer_teams 내용과 무관하게 어떤 이벤트든 받아들인다.
API로 트리거된 이벤트: REST API로 사용자가 자산 이벤트를 만들면, 그 사용자의 팀은 auth manager로부터 해석된다. 같은 필터링 규칙이 적용되지만 한 가지 중요한 차이가 있다 — 팀이 없는 API 사용자는 팀이 없는 소비자만 트리거할 수 있다(팀이 없는 Dag 생산자는 글로벌로 취급되어 어떤 소비자든 트리거할 수 있는 것과 다르다). 그 이유는, 팀 없는 Dag는 플랫폼 운영자가 배포한, 의도적으로 공유되는 존재인 반면, 팀이 없는 API 사용자는 검증된 팀 소속이 없으므로 팀 전용 파이프라인에 대한 무분별한 접근을 막기 위해 팀 없는 소비자로 제한된다는 데 있다.
REST API는 자산 이벤트를 만들 때 요청 본문에 선택적 access_control 객체를 받는다: consumer_teams(list[str] | null, 태스크 레벨 consumer_teams와 동일한 규칙 — 생략하거나 null이면 소비자-팀 필터링 없음), allow_global(bool, 기본 true — 팀 없는 소비자가 이 이벤트를 받을 수 있는지). Multi-Team이 꺼져 있으면 access_control 파라미터는 받아들여지지만 무시된다.
핵심 포인트
- 팀 없는 Dag 생산자는 allow_global=True(기본)일 때 모든 소비자를 트리거할 수 있는 '글로벌'로 취급된다
- 팀 없는 API 사용자는 Dag 생산자와 달리 팀 없는 소비자만 트리거할 수 있다 — 검증된 팀 소속이 없기 때문이다
- REST API로 자산 이벤트를 생성할 때도 access_control(consumer_teams, allow_global) 필드를 넘길 수 있다
팀 기반 메트릭과 배포 시 주의사항
3.3.0부터 Multi-Team이 켜지면 Airflow는 많은 운영 메트릭에 team_name 태그를 추가해, 각 메트릭이 관련된 리소스를 소유한 팀을 식별할 수 있게 한다. 이는 메트릭 백엔드에서 팀별로 활동을 분해해 볼 수 있게 해준다. 이 태그는 태그를 지원하는 메트릭 백엔드(태깅이 켜진 StatsD — 예: Datadog나 InfluxDB 방언 — 또는 OpenTelemetry)가 있어야 의미가 있다. 태그는 팀 소유 리소스에만 붙는다 — 글로벌 풀, 팀 없는 Dag, 글로벌 컴포넌트는 태그 없이 동일한 메트릭을 낸다. Multi-Team이 꺼져 있으면 team_name 태그 자체가 전혀 붙지 않아, 단일 팀 Airflow 환경에서 항상 그래왔던 것과 동일하게 동작한다.
team_name 태그가 붙는 컴포넌트로는(예시일 뿐 전체 목록은 아님): Triggerer(heartbeat, capacity, blocked-main-thread, trigger-queue delay, trigger-outcome 메트릭), Executors(실행기 슬롯 게이지, 스케줄러가 관측하는 실행기 heartbeat 타이밍), Scheduler(팀 스코프 풀의 풀 슬롯 게이지, 태스크·자산 스케줄링 카운터), Dag runs(타이밍·생명주기 메트릭), Task instances(시작·종료·결과 카운터), Dag processing(파일별 파싱·콜백 메트릭), Callbacks(콜백 실행 카운터), Connection tests(팀 소유 커넥션 테스트의 요청·리퍼 메트릭 — 인스턴스 전체 큐 게이지는 태그 없이 유지)가 있다.
중요 고려사항: Multi-Team은 여전히 실험적 기능이며 아직 완전하지 않다. 사용자 피드백에 따라 예고 없이 바뀔 수 있다. 3.4+ 이후 릴리스에 예정된 미완성 기능으로는 일부 UI 요소의 팀 인식 미비, 팀 기반 설정에 대한 명령/시크릿 기반 조회 미지원, 플러그인 지원 미비가 있다. 전역 유일성: Dag ID, Variable 키, Connection ID는 어느 팀이 소유하든 관계없이 배포 전체에서 유일해야 한다 — 이는 S3 버킷 이름이 모든 AWS 계정에 걸쳐 전역적으로 유일해야 하는 것과 비슷하다. 이름 충돌을 피하려면 조직 안에서 네이밍 컨벤션(예: 식별자 앞에 팀 이름 접두사 붙이기)을 세워야 한다.
핵심 포인트
- team_name 메트릭 태그는 태그를 지원하는 백엔드(StatsD 태깅 방언 또는 OpenTelemetry)에서만 의미가 있다
- 글로벌 풀·팀 없는 Dag·전역 컴포넌트의 메트릭에는 team_name 태그가 붙지 않는다
- Dag ID, Variable 키, Connection ID는 팀과 무관하게 배포 전체에서 유일해야 한다 — 이름 충돌을 막으려면 팀 접두사 같은 네이밍 컨벤션이 필요하다
- Multi-Team은 3.3 시점에도 UI 전체 팀 인식, 커맨드/시크릿 기반 팀 설정 조회, 플러그인 지원 등이 아직 미완성이다