[한국어] Towards a Unified Airflow: Toss Bank’s PoC for Cluster Consolidation (Part 1)

알리는 말

이 글은 Apache Airflow 공식 블로그에 게시된 Towards a Unified Airflow: Toss Bank’s PoC for Cluster Consolidation — Part 1의 한국어 버전입니다.

2026.02.26 제5회 Apache Airflow 한국인사용자모임 밋업 발표한 내용을 다룹니다.

Section 1: Intro

1.1 Toss Bank Data Platform Team: The Heart of Digital Banking

토스뱅크는 한국에서 가장 빠르게 성장하는 디지털 뱅크 중 하나입니다. 24시간 중단 없는 금융 서비스를 제공하기 위해, 데이터 플랫폼 팀은 수천 개의 데이터 파이프라인이 원활하게 작동할 수 있는 기반을 만드는 데 집중하고 있습니다.

저는 이 팀에서 전사 Airflow 플랫폼의 아키텍처 설계와 운영을 담당하고 있습니다. 이전 직장인 LINE Plus에서 대규모 메시징 서비스의 데이터 파이프라인을 관리했던 경험을 바탕으로, 2025년 10월 토스뱅크에 합류하여 '신뢰할 수 있고 확장 가능한 데이터 오케스트레이션 환경’을 구축하는 미션을 수행하고 있습니다.

1.2 클러스터를 분리해야 했던 4가지 이유

토스뱅크의 서비스가 급성장함에 따라 각 팀의 요구사항은 파편화되었습니다. 운영의 편의를 위해 클러스터를 하나씩 추가하다 보니 어느덧 6개의 클러스터를 운영하게 되었습니다. 우리가 단일 플랫폼으로 통합하기 전, 클러스터를 물리적으로 분리할 수밖에 없었던 4가지 핵심 페인 포인트는 다음과 같습니다.

  • Dependency Hell (패키지 충돌): 각 팀마다 필요한 Python 라이브러리와 버전이 달랐습니다. 이를 하나의 공통 Core 이미지에 맞추려다 보니 라이브러리 충돌이 잦아졌고, 이미지는 관리할 수 없을 정도로 비대해졌습니다.

  • Security & Access Isolation (권한 및 보안): 금융권 특성상 특정 팀의 민감한 로직이나 데이터가 담긴 Dag 저장소(Repo)는 타 팀에 노출될 수 없었습니다. 작업 실행 로그나 Spark UI에 대한 접근 권한 역시 팀별로 엄격히 격리해야 했습니다.

  • Starvation (자원 독점 및 스케줄링 간섭): 특정 팀의 무거운 배치 작업이 워커 풀(Worker Pool)이나 쿠버네티스 자원을 독점하면 다른 팀의 작업이 줄지어 지연되는 ‘Noisy Neighbor’ 문제가 발생했습니다. 또한, 방대한 양의 Dag 파일을 파싱하는 부하가 중앙 스케줄러에 집중되어 전체 성능이 저하되었습니다.

  • Monolithic 아키텍처의 한계: Airflow Core 엔진과 유저의 비즈니스 로직 코드가 강하게 결합되어 있었습니다. 이는 플랫폼 팀이 보안이나 성능 개선을 위해 Airflow 버전을 올리고 싶어도, 수천 줄의 유저 레거시 코드를 일일이 검증해야 하는 운영의 병목을 초래했습니다.

1.3 멀티 테넌시를 위한 아키텍처 설계

이 문제를 해결하기 위해 우리는 근본적인 질문을 던졌습니다. “단일 Airflow 클러스터가 모든 팀을 안정적으로 지원할 수 있는가?” 단순히 인프라를 합치는 것을 넘어, 각 팀의 워크로드가 서로 간섭하지 않는 아키텍처 설계가 필요했습니다.

이번 시리즈의 첫 번째 포스팅에서는 단일 클러스터 내에서 Dag의 팀 소속을 명확히 식별하는 메커니즘과 실행 환경을 격리하는 전략에 대해 공유하고자 합니다.

Section 2: 운영의 기로 — ‘DIY’ vs ‘통합 운영’

6개의 클러스터를 마주한 플랫폼 팀은 중대한 결정을 내려야 했습니다. 팀별로 클러스터를 계속 파편화하며 늘려갈 것인가, 아니면 리스크를 감수하고 하나로 응집할 것인가?

2.1 개별 운영 (Do It Yourself): 파편화된 자유와 운영의 역설

팀별로 독립적인 클러스터를 할당하는 방식은 초기에는 매력적인 대안처럼 보였습니다. 하지만 조직이 커질수록 다음과 같은 한계가 명확해졌습니다.

  • 자원의 불균형 (Idle vs. Bottleneck): 어느 팀은 CPU 사용률이 0.1%도 안 되는 유휴 상태인 반면, 다른 팀은 워크로드 급증으로 리소스 부족에 허덕이는 상황이 빈번했습니다. 물리적으로 격리된 인프라 구조에서는 남는 자원을 빌려줄 방법이 없었습니다.

  • 중복되는 인프라 관리 비용: 6개의 스케줄러, 6개의 DB, 6개의 웹 서버… 플랫폼 엔지니어가 동일한 인프라 관리 및 패치 작업을 6번 반복해야 하는 것은 명백한 인력 낭비였습니다.

  • 운영 노하우의 파편화 (Operational Tax): 가장 큰 단점은 각 팀이 Airflow의 복잡한 운영 노하우를 직접 보유해야 한다는 점이었습니다. 데이터 엔지니어가 비즈니스 가치 창출에 집중하는 대신, 스케줄러 튜닝이나 인프라 트러블슈팅에 귀한 엔지니어링 리소스를 쏟아야 하는 '운영세(Operational Tax)'가 발생했습니다.

2.2 통합 운영 (Centralized): 효율과 간섭 사이의 외줄 타기

반면, 모든 워크로드를 하나의 거대한 클러스터로 통합하는 것은 인프라 효율성 측면에서 압도적인 장점이 있습니다. 중앙에서 한 번의 업데이트로 전사의 보안과 성능을 개선할 수 있고, 유휴 자원을 공유해 전체 최적화를 달성할 수 있기 때문입니다.

하지만 문제는 역시 '간섭’이었습니다. "A 팀의 잘못된 코드가 B 팀의 중요한 배치 작업을 멈추면 어떡하지?"라는 공포는 통합을 가로막는 가장 큰 장벽이었습니다.

2.3 우리의 목표: ‘자율성과 통합의 균형을 맞춘 신뢰 플랫폼’

우리는 '안정성’을 위해 '효율’을 포기하거나, '효율’을 위해 '팀의 자유’를 희생하고 싶지 않았습니다. 그래서 우리는 "팀에게는 개별 클러스터를 쓰는 듯한 자율성을 주되, 플랫폼은 통합된 환경의 효율성을 누리는 것"을 최종 목표로 삼았습니다.

이 '불가능해 보이는 균형’을 맞추기 위해 기술적으로 다음 네 가지 핵심 전략을 수립했습니다:

  1. 소속 식별 (Dag Identification): 모든 제어와 자동화의 시작점입니다. 어떤 팀이 어떤 Dag를 소유하는지 명확히 판별하여 팀별 보안 정책이나 리소스 제한을 적용할 수 있는 기반을 만듭니다.

  2. 코드 및 환경 격리 (Logic Isolation): 플랫폼 영역(Core)과 유저 영역(Dag Author)을 완전히 분리하여 상호 의존성을 제거합니다. 이를 통해 플랫폼 업데이트가 유저 코드에 미치는 영향을 최소화합니다.

  3. 리소스 격리 (Physical Isolation): 쿠버네티스 기능을 극한으로 활용해 타 팀이나 중앙 시스템에 대한 자원 간섭을 원천 차단합니다. 특정 팀의 작업 폭주가 전체 시스템의 중단으로 이어지지 않도록 물리적 방화벽을 구축합니다.

  4. 플랫폼 가드레일 (Safety Guardrails): 유저에게 자유를 주되, 시스템 전체를 위협하는 행위는 Cluster Policy를 통해 자동으로 차단하는 안전망을 구축합니다. 복잡한 인프라 설정은 플랫폼이 대신 처리하여 유저가 비즈니스 로직에만 집중하게 돕습니다.

Section 3: 통합 Airflow 클러스터의 청사진 (Part 1)

통합의 대원칙은 "Core(플랫폼)와 User(비즈니스 로직)의 완전한 분리"입니다. 이를 위해 설계한 네 가지 메커니즘 중 우선 두 가지를 먼저 살펴보겠습니다.

3.1 Dag Identification: “이 Dag은 어느 팀 소속인가?”

모든 제어와 자동화의 시작은 Dag의 주인을 아는 것입니다.

3.1.1) 경로 기반 식별의 진화: Airflow 3 ‘Dag Bundles’ 과거에는 디렉토리 경로를 파싱해 팀을 구분했지만, 우리는 Airflow 3의 Dag Bundles 개념을 차용했습니다. 각 팀의 레포지토리를 독립적인 GitDagBundle로 등록하면 {BUNDLE_ROOT}/{team_bundle}/…와 같은 구조가 형성됩니다. 이를 통해 플랫폼은 파일 경로만으로 소속을 구조적으로 신뢰할 수 있으며, 번들별로 독립적인 PYTHONPATH를 지정하여 패키지 이름 충돌을 원천 차단했습니다.

3.1.2) Cluster Policy를 통한 자동화 식별된 정보를 바탕으로 플랫폼 단에서 dag_policy를 활용해 다음 작업을 자동화합니다.

  • Dag ID 충돌 방지: 팀 이름을 접두어(Prefix)로 강제 주입합니다.

  • 가독성 확보: Web UI에서 팀 소속이 바로 보이도록 dag_display_name을 수정합니다.

@hookimpl
def dag_policy(dag: Dag) -> None:
    # 1. Extract team identifier (Prefix) from the file location
    # Note: _get_prefix_from_fileloc is a separate custom logic
    prefix = _get_prefix_from_fileloc(dag.fileloc)
    
    if not prefix:
        return

    # 2. Enforce the team prefix in both Dag ID and Display Name
    dag.dag_id = f"{prefix}_{dag.dag_id}"
    dag.dag_display_name = f"[{prefix.upper()}] {dag.dag_id}"

3.2 Task Env Isolation: 실행 환경과 부하의 격리

플랫폼 팀의 가장 큰 숙제인 '업데이트 시의 의존성 불확실성’을 해결하기 위해, 실행 환경의 생명주기를 Core와 분리하는 PoC를 진행했습니다.

3.2.1) 권고를 넘어선 '강제’의 필요성 이미 많은 조직이 KubernetesPodOperator(KPO)를 사용하지만, 강제성이 없으면 여전히 많은 작업이 중앙 환경에 의존적인 PythonOperator 등으로 작성됩니다. 우리는 이를 구조적으로 강제하여 업데이트 가시성을 확보하고자 했습니다.

3.2.2) 업데이트의 자유: 상호 간섭 없는 독립적 런타임 구축 (Lean Core) 우리는 중앙 Airflow 환경에 최소한의 공통 패키지만 유지하는 ‘Lean Core’ 전략을 채택했습니다. 유저는 자신의 작업에 필요한 라이브러리를 담은 Custom Image를 준비해야 합니다. 이를 통해 플랫폼 팀은 유저 코드와 상관없이 Core 버전을 업데이트할 수 있고, 유저 역시 플랫폼과 무관하게 라이브러리 버전을 변경할 수 있습니다.

3.2.3) 하이브리드 실행 전략 (Executor Separation) 어떤 오퍼레이터를 사용하더라도 중앙 워커 환경에 영향을 주지 않도록 다음과 같은 모델을 테스트했습니다.

  • KPO: 독립적인 Pod로 실행되어 간섭이 거의 없음. CeleryExecutor가 상태 모니터링 담당.

  • 일반 오퍼레이터: PythonOperator 등을 사용하더라도 플랫폼이 내부적으로 KubernetesExecutor 실행을 강제하여 매번 독립적인 워커 Pod를 생성하게 함으로써 중앙 환경을 보호합니다.

@hookimpl
def task_policy(task: BaseOperator) -> None:
    # 1. Assign CeleryExecutor for KPO as it only monitors the pod status
    if isinstance(task, KubernetesPodOperator):
        task.executor = "CeleryExecutor"
    
    # 2. Force KubernetesExecutor for other operators to protect the shared environment
    else:
        task.executor = "KubernetesExecutor"

Conclusion of Part 1: Setting the Foundation

시리즈의 첫 번째 파트에서는 토스뱅크가 왜 파편화된 멀티 클러스터를 떠나 통합을 준비했는지, 그리고 Dag 식별환경 격리를 통해 어떻게 통합의 기반을 다졌는지 살펴보았습니다.

하지만 논리적 격리만으로는 충분하지 않습니다. 특정 팀이 클러스터의 전체 하드웨어 자원을 고갈시키는 것을 어떻게 막을 수 있을까요? 그리고 유저들에게 복잡한 설정 없이도 편리한 “No-Ops” 경험을 어떻게 제공할 수 있을까요?

Part 2에서는 쿠버네티스 레벨의 리소스 제어, 자동화된 플랫폼 가드레일, 그리고 이러한 병목을 해결하기 위한 오픈소스 기여 사례에 대해 심층적으로 다루겠습니다.

4개의 좋아요

와우 성환님, 공유 감사합니다 :raising_hands:

1개의 좋아요

내부 컴플라이언스 승인 절차로 인해 업로드가 늦어졌습니다.

PoC 수행 및 발표 시점으로부터 다소 시간이 지났지만, 큰 맥락에서는 현재 토스뱅크 내부 Production 환경과 유사한 내용입니다.

현재 토스뱅크는 Airflow 3 기반 멀티테넌시 환경으로의 Production 마이그레이션을 진행 중입니다. 글에서 소개된 내용 외에도, 여러 팀이 함께 사용하는 환경인 만큼 권한 관리를 포함한 다양한 고려사항, 금융권 특성상 반드시 짚어야 하는 보안·거버넌스 관련 이슈, 그리고 DAG 1만 개를 목표로 한 부하 테스트까지 — 미처 다루지 못한 내용들이 많습니다.

다음 밋업에서 기회가 된다면, 이러한 고민과 고충을 함께 나눠보겠습니다. 감사합니다.

1개의 좋아요

호오 RBAC 도 어떻게 할지 궁금했는데 기대되네요 ㅎㅎ

1개의 좋아요

성환님~~!! 좋은 글 한글로 공유해주셔서 감사드립니다!!! :flexed_biceps::flexed_biceps::flexed_biceps:

1개의 좋아요

우외 ~!! 밋업때도 너무 흥미롭게 들었던 주제인데 이렇게 다시 정리해주시다니 너무 좋은 인사이트공유 감사합니다!

2개의 좋아요