Tag: ETL

  • Airflow로 데이터 파이프라인 오케스트레이션 제대로 하기

    Airflow로 데이터 파이프라인 오케스트레이션 제대로 하기

    데이터 파이프라인이 십수 개를 넘어가면 cron과 셸 스크립트로는 더 이상 감당이 안 됩니다. 어떤 작업이 실패했는지, 무엇이 먼저 끝나야 다음이 도는지, 재실행은 어떻게 하는지를 사람이 일일이 추적해야 하기 때문입니다. Apache Airflow는 이 워크플로를 코드로 정의하고 의존성과 재시도를 자동으로 관리하는 오케스트레이터입니다.

    이 글에서는 Airflow의 핵심 개념인 DAG와 태스크 의존성, 스케줄링 동작, 그리고 멱등성 있는 파이프라인을 만드는 운영 노하우를 다룹니다.

    오케스트레이션이 필요한 이유

    파이프라인은 단순히 스크립트를 시간 맞춰 실행하는 것이 아닙니다. A가 끝나야 B를 시작하고, B가 실패하면 C를 건너뛰며, 특정 작업은 세 번까지 재시도하는 식의 의존성과 조건이 얽혀 있습니다. cron은 이 관계를 표현하지 못합니다. Airflow는 작업 간 관계를 방향성 비순환 그래프(DAG)로 표현해 이 복잡성을 명시적으로 관리합니다.

    DAG와 태스크의 구조

    DAG는 노드(태스크)와 방향성 엣지(의존성)로 이뤄진 그래프입니다. 각 태스크는 오퍼레이터로 구현되며, 비트시프트 연산자로 순서를 선언합니다.

    with DAG("daily_sales", schedule="0 2 * * *",
             start_date=datetime(2026,1,1), catchup=False) as dag:
        extract = PythonOperator(task_id="extract", python_callable=pull)
        transform = PythonOperator(task_id="transform", python_callable=clean)
        load = PythonOperator(task_id="load", python_callable=write)
        extract >> transform >> load

    여기서 catchup=False는 중요한 설정입니다. True로 두면 start_date부터 현재까지의 모든 누락된 실행을 한꺼번에 채우려 들어 시스템에 부하가 집중됩니다. 의도적인 백필이 아니라면 끄는 것이 안전합니다.

    스케줄링과 execution_date

    Airflow 입문자를 가장 혼란스럽게 하는 개념이 실행 시점과 데이터 기간의 분리입니다. 일 단위 DAG는 해당 기간이 끝난 직후에 실행됩니다. 즉 6월 24일 데이터의 처리는 6월 25일 새벽에 트리거됩니다. 이 논리적 기간(data interval)을 기준으로 쿼리를 작성해야 멱등성이 보장됩니다.

    태스크 내부에서는 현재 시각이 아니라 data_interval_start와 data_interval_end를 사용해 처리 범위를 한정하세요. 그래야 재실행이나 백필 시에도 항상 같은 결과를 냅니다.

    운영과 트러블슈팅

    운영에서 가장 자주 마주치는 문제는 태스크 적체입니다. 스케줄러가 태스크를 큐에 넣었는데 워커가 부족하면 queued 상태에서 멈춥니다. 동시성 관련 파라미터를 점검하세요.

    • parallelism: 전체 동시 실행 태스크 상한
    • max_active_runs: 한 DAG의 동시 실행 인스턴스 수
    • pool: 외부 DB 커넥션 등 공유 자원 보호용 슬롯

    또한 멱등성이 깨진 태스크는 재시도 시 데이터 중복을 낳습니다. INSERT보다 파티션 단위 덮어쓰기나 MERGE를 사용해 같은 입력에 항상 같은 출력이 나오도록 설계하세요. 무거운 연산은 Airflow 워커에서 직접 돌리지 말고 Spark나 웨어하우스로 위임하는 것이 안정적입니다.

    Airflow는 작업을 실행하는 도구가 아니라 작업을 지휘하는 도구다. 무거운 연산은 외부 엔진에 맡겨라.

    정리

    Airflow는 파이프라인의 의존성, 스케줄, 재시도를 코드로 관리해 운영 복잡성을 길들입니다. DAG로 관계를 명시하고, data interval 기반으로 멱등성을 지키며, 동시성 파라미터로 자원을 보호하는 것이 안정 운영의 핵심입니다. Airflow는 지휘자 역할에 집중시키고 연산은 전문 엔진에 위임하세요.

  • ETL vs ELT: 어떤 데이터 통합 방식을 선택해야 할까

    ETL vs ELT: 어떤 데이터 통합 방식을 선택해야 할까

    데이터 통합 전략을 논할 때 가장 먼저 마주치는 갈림길이 ETL과 ELT입니다. 글자 순서만 바뀐 듯 보이지만, 변환을 적재 전에 하느냐 후에 하느냐는 아키텍처 전체, 비용 구조, 팀 역할 분담까지 바꿉니다. 클라우드 웨어하우스의 등장으로 무게중심이 ELT로 옮겨갔지만, ETL이 여전히 우월한 영역도 분명히 있습니다.

    이 글은 두 방식의 동작 원리를 비교하고, 비용과 거버넌스 관점에서 어떤 상황에 무엇을 골라야 하는지 정리합니다.

    두 방식의 기본 흐름

    ETL은 추출(Extract) 후 별도의 처리 엔진에서 변환(Transform)을 마친 뒤 정제된 데이터만 웨어하우스에 적재(Load)합니다. ELT는 원본을 먼저 웨어하우스에 그대로 적재한 다음, 웨어하우스의 연산 능력으로 그 안에서 변환합니다.

    이 차이의 핵심은 변환이 일어나는 장소입니다. ETL은 외부 처리 클러스터에서, ELT는 웨어하우스 내부에서 변환합니다. 클라우드 웨어하우스의 연산이 저렴하고 탄력적이 되면서 ELT가 부상한 배경이 여기 있습니다.

    정면 비교

    기준ETLELT
    변환 위치외부 처리 엔진웨어하우스 내부
    원본 보존적재 안 됨그대로 보존
    유연성스키마 사전 고정나중에 재변환 용이
    민감정보적재 전 마스킹 가능적재 후 처리 필요
    적합 환경온프레미스, 규제클라우드 웨어하우스

    ELT가 유리한 경우

    대부분의 클라우드 네이티브 분석 환경에서는 ELT가 기본 선택입니다. 원본을 먼저 보존하므로 비즈니스 로직이 바뀌어도 재추출 없이 다시 변환만 하면 됩니다. dbt 같은 도구가 웨어하우스 내부 변환을 SQL로 관리해주면서 분석가도 직접 변환을 다룰 수 있게 되었습니다.

    또한 변환 로직을 추가하거나 새 지표를 만들 때 파이프라인을 다시 짤 필요 없이 SQL 모델만 더하면 됩니다. 이 민첩성이 ELT의 가장 큰 매력입니다.

    ETL이 여전히 옳은 경우

    반면 개인정보나 결제 정보처럼 원본을 웨어하우스에 그대로 두면 안 되는 규제 환경에서는 ETL이 필요합니다. 적재 전에 마스킹이나 토큰화를 끝내야 하기 때문입니다. 또한 웨어하우스 연산 비용이 비싼 환경이라면, 적재 전 변환으로 데이터 양을 줄여 비용을 통제하는 편이 낫습니다.

    • 규제·컴플라이언스: 적재 전 PII 제거 필요 시 ETL
    • 복잡한 비정형 변환: 웨어하우스 SQL로 표현하기 어려운 로직은 ETL
    • 비용 통제: 적재량을 줄여야 할 때 ETL 사전 필터링

    실무에서는 둘을 섞은 하이브리드도 흔합니다. 민감정보는 ETL로 사전 처리하고 나머지는 ELT로 유연하게 다루는 식입니다. 정답은 하나가 아니라 데이터 성격과 규제 요건에 달려 있습니다.

    정리

    ETL과 ELT의 차이는 변환의 시점과 장소입니다. 클라우드 웨어하우스 환경에서 유연성과 민첩성이 중요하면 ELT, 규제·민감정보·비용 통제가 우선이면 ETL이 적합합니다. 많은 조직은 두 방식을 상황에 맞게 혼합합니다. 데이터의 민감도와 변환 복잡성을 기준으로 선택하세요.

  • 데이터 파이프라인 관측성: 신뢰를 만드는 모니터링 체계

    데이터 파이프라인 관측성: 신뢰를 만드는 모니터링 체계

    전통적인 모니터링은 잡이 성공했는지 실패했는지를 봅니다. 그런데 데이터 세계에는 더 교묘한 문제가 있습니다. 잡은 분명히 초록불로 성공했는데, 실제 데이터는 절반이 비어 있거나 어제보다 10분의 1로 줄어든 경우입니다. 이런 침묵의 장애를 잡으려면 잡 상태가 아니라 데이터 자체를 관측해야 합니다. 이것이 데이터 관측성입니다.

    이 글에서는 데이터 관측성의 다섯 기둥, 구현 방법, 그리고 경보 피로를 피하는 운영 전략을 다룹니다.

    왜 잡 성공만으로는 부족한가

    파이프라인이 성공했다는 신호는 코드가 예외 없이 끝났다는 뜻일 뿐입니다. 원천 API가 빈 응답을 주거나, 업스트림 조인 키가 바뀌어 매칭이 0건이 되어도 코드는 멀쩡히 성공합니다. 비즈니스 대시보드의 숫자가 이상하다고 누군가 제보하기 전까지 아무도 모릅니다.

    실제로 데이터 장애의 상당수는 코드 버그가 아니라 데이터 자체의 변화에서 옵니다. 그래서 관측 대상이 인프라에서 데이터로 확장되어야 합니다.

    데이터 관측성의 다섯 기둥

    업계에서 합의된 관측성의 다섯 축은 다음과 같습니다. 각각이 서로 다른 유형의 장애를 잡아냅니다.

    • 신선도(Freshness): 데이터가 기대한 시점에 갱신됐는가
    • 양(Volume): 행 수가 평소 범위 안에 있는가
    • 분포(Distribution): 값의 범위와 null 비율이 정상인가
    • 스키마(Schema): 컬럼과 타입이 바뀌지 않았는가
    • 계보(Lineage): 어느 업스트림이 어느 다운스트림에 영향을 주는가

    신선도와 양만 잘 잡아도 침묵의 장애 대부분을 조기에 발견할 수 있습니다. 계보는 장애 발생 시 영향 범위를 빠르게 파악하는 데 결정적입니다.

    구현 방법

    가장 단순한 시작점은 핵심 테이블에 품질 검사를 거는 것입니다. dbt test, Great Expectations, Soda 같은 도구로 행 수 임계, null 비율, 고유성, 값 범위를 선언적으로 검증합니다.

    # Soda 체크 예시
    checks for fct_orders:
      - row_count between 9000 and 15000
      - missing_percent(customer_id) < 1%
      - freshness(created_at) < 6h
      - duplicate_count(order_id) = 0

    한 단계 더 나아가면 과거 패턴을 학습해 동적 임계치를 만드는 이상 탐지를 도입할 수 있습니다. 요일별, 시간대별 패턴을 반영하면 고정 임계보다 오탐이 크게 줍니다.

    경보 피로를 피하는 운영

    관측성을 도입하면 처음엔 경보가 폭주합니다. 너무 많은 경보는 곧 무시되고, 무시되는 경보는 없는 것과 같습니다. 따라서 심각도를 계층화하세요. 비즈니스 핵심 테이블의 신선도 장애는 즉시 호출(page), 부차적 테이블의 분포 경고는 일일 다이제스트로 묶는 식입니다.

    • SLA가 정의된 골드 테이블에만 강한 경보를 건다
    • 경보마다 담당자(owner)와 런북을 명시한다
    • 오탐이 잦은 검사는 임계를 조정하거나 제거한다

    데이터 신뢰는 정확한 데이터에서 오는 것이 아니라, 틀렸을 때 가장 먼저 아는 데서 온다.

    정리

    데이터 관측성은 잡 성공을 넘어 데이터 자체의 신선도, 양, 분포, 스키마, 계보를 감시합니다. 핵심 테이블부터 선언적 품질 검사를 걸고, 동적 임계로 오탐을 줄이며, 심각도를 계층화해 경보 피로를 막으세요. 목표는 완벽한 데이터가 아니라, 문제가 생겼을 때 사용자보다 먼저 아는 것입니다.

  • 데이터 적재 품질을 지키는 7가지 실전 원칙

    데이터 적재 품질을 지키는 7가지 실전 원칙

    데이터 품질 논의는 흔히 분석 단계나 대시보드 단계에 집중되지만, 진짜 싸움은 파이프라인 가장 앞단인 적재(ingestion)에서 벌어집니다. 입구에서 오염된 데이터는 하류로 내려갈수록 정화 비용이 기하급수적으로 커집니다. 한 번 잘못 들어간 데이터는 수십 개 다운스트림 테이블을 오염시키고, 추적과 복구에 며칠이 걸립니다.

    이 글에서는 적재 단계에서 품질을 지키기 위한 일곱 가지 실전 원칙을 사례와 함께 정리합니다.

    1. 입구에서 검증하라

    가장 기본은 적재 시점의 스키마와 제약 검증입니다. 필수 필드 존재, 타입 일치, 값 범위를 적재 직전에 확인하세요. 검증을 뒤로 미룰수록 오염 범위가 넓어집니다. 입구에서 거른 한 건이 하류의 백 건 복구를 막습니다.

    2. 멱등성을 보장하라

    파이프라인은 반드시 재실행됩니다. 같은 데이터가 두 번 적재돼도 결과가 같아야 합니다. INSERT 대신 자연 키 기반 MERGE나 파티션 덮어쓰기를 사용하세요. 멱등하지 않은 적재는 재시도 한 번에 중복 폭탄이 됩니다.

    MERGE INTO target t
    USING staging s ON t.event_id = s.event_id
    WHEN MATCHED THEN UPDATE SET *
    WHEN NOT MATCHED THEN INSERT *;

    3. 불량 레코드를 격리하라

    검증에 실패한 레코드를 만났을 때 전체 배치를 통째로 실패시키면 정상 데이터까지 막힙니다. 반대로 조용히 버리면 손실을 모릅니다. 정답은 불량 레코드 격리(quarantine)입니다. 실패한 행을 별도 데드레터 테이블로 보내 정상 흐름은 유지하되 추적은 가능하게 하세요.

    4. 원본을 보존하라

    적재 단계에서 변환을 과하게 하지 마세요. 원본을 거의 그대로 담는 불변 레이어(브론즈)를 두면, 로직 오류를 발견했을 때 원천 재요청 없이 재처리할 수 있습니다. 원본 보존은 가장 값싼 보험입니다.

    5. 메타데이터를 함께 적재하라

    각 레코드에 적재 시각, 원천 식별자, 배치 ID, 파일명 같은 메타데이터를 붙이세요. 문제가 터졌을 때 어느 배치, 어느 파일에서 왔는지 즉시 추적할 수 있습니다. 이 작은 컬럼들이 장애 대응 시간을 시간 단위에서 분 단위로 줄입니다.

    • _ingested_at: 적재 타임스탬프
    • _source_file: 원천 파일 경로
    • _batch_id: 적재 배치 식별자
    • _record_hash: 변경 감지용 해시

    6. 양과 신선도를 감시하라

    적재된 행 수가 평소 범위를 벗어나거나 기대 시각에 데이터가 없으면 즉시 경보하세요. 원천 API가 빈 응답을 줘 0건이 적재돼도 잡은 성공으로 끝나기 때문에, 양 기반 검사가 이런 침묵의 장애를 잡는 마지막 방어선입니다.

    7. 백필을 설계에 포함하라

    과거 데이터를 다시 적재하는 백필은 예외가 아니라 일상입니다. 처음부터 특정 기간을 지정해 재적재할 수 있도록 파라미터화하고, 백필이 운영 트래픽을 방해하지 않도록 자원을 분리하세요. 사후에 백필을 끼워 넣으면 항상 고통스럽습니다.

    품질은 마지막에 검사하는 것이 아니라 입구에서 설계하는 것이다. 쓰레기가 들어오면 쓰레기가 나간다.

    정리

    적재 품질의 핵심은 입구 검증, 멱등성, 불량 격리, 원본 보존, 메타데이터, 양·신선도 감시, 백필 설계입니다. 이 일곱 원칙은 화려하지 않지만, 하류의 수많은 복구 작업을 미리 막아주는 가장 효율적인 투자입니다. 파이프라인 품질은 결국 입구에서 결정됩니다.