ETL과 파이프라인 엔지니어링 원칙
50 Python Interview Questions for Data Engineers (2026) — DataCamp (blog) Section 4: ETL & Pipeline Engineering (pp.11-13)
이 모듈을 다 읽으면
- 멱등성 설계가 파이프라인 재실행 전략에 왜 필수적인지, 이를 구현하는 구체적인 기법을 설명할 수 있다
- 스키마 드리프트를 방어하는 검증 레이어 설계를 판단할 수 있다
- 파라미터화 쿼리를 이용해 SQL 인젝션을 방지하는 이유를 설명할 수 있다
- 배치 처리와 스트림 처리의 트레이드오프를 상황에 맞게 선택하고, 관련 라이브러리 생태계의 최신 동향을 파악할 수 있다
멱등성과 데이터 품질 게이트, 스키마 드리프트 방어, 안전한 DB 연결, 데이터 레이크/웨어하우스와 스테이징 테이블, 오케스트레이션, 데이터 리니지, API 레이트 리밋 대응, 배치/스트림 처리를 다룬다. 배치/스트림 처리 절에서는 원문이 예시로 든 Faust 라이브러리의 2026년 현재 생태계 위상을 갱신해 보충한다.
멱등성과 데이터 품질 게이트
멱등(idempotent) 파이프라인이란 동일한 입력으로 여러 번 실행해도 중복 데이터나 부작용 없이 항상 같은 결과를 내는 파이프라인을 말한다. 파이프라인은 네트워크 문제나 시스템 크래시로 실패하는 일이 잦기 때문에 이 성질이 중요하다. 멱등성이 있으면 실패한 잡을 데이터베이스를 수동으로 정리할 필요 없이 그냥 '재실행'하면 된다.
보충: 원문은 멱등성의 정의만 제시하는데, 실무에서 이를 구현하는 구체적 기법으로는 (1) 자연 키에 대한 UPSERT/MERGE 문 사용(같은 키로 재실행해도 덮어쓰기만 될 뿐 중복이 쌓이지 않음), (2) 특정 파티션을 통째로 덮어쓰는 INSERT OVERWRITE(append 대신 partition overwrite) 방식, (3) 처리된 레코드의 워터마크나 오프셋을 별도로 기록해 이미 처리한 범위를 건너뛰는 방식이 있다. 어떤 기법을 쓰든 핵심은 '추가(append)'가 아니라 '치환(replace)' 관점으로 쓰기 연산을 설계하는 것이다.
데이터 품질 검증에는 '서킷 브레이커(Circuit Breaker)' 패턴을 쓴다. 스크립트 시작 시 품질 체크(예: '행 개수가 0보다 큰가', '"Price" 컬럼에 음수가 있는가')를 수행하고, 이 체크가 실패하면 스크립트가 오류를 일으켜 파이프라인을 멈춤으로써 나쁜 데이터가 프로덕션 웨어하우스에 도달하기 전에 막는다.
핵심 포인트
- 멱등 파이프라인은 여러 번 재실행해도 같은 결과를 내며 부작용이 없어, 실패 시 별도 정리 없이 그냥 재실행할 수 있다.
- 멱등성은 UPSERT/MERGE, 파티션 단위 overwrite, 처리 범위 워터마크 기록 등 '치환' 관점의 쓰기 설계로 구현한다 — 보충.
- 서킷 브레이커 패턴은 파이프라인 시작 시 데이터 품질을 체크해, 실패하면 즉시 멈춰 나쁜 데이터가 웨어하우스에 닿기 전에 차단한다.
스키마 드리프트 방어
스키마 드리프트는 소스 시스템이 예고 없이 데이터 구조를 바꿀 때(새 컬럼 추가, 데이터 타입 변경 등) 발생한다. 이를 다루려면 Pydantic이나 Great Expectations 같은 도구로 검증 레이어를 구현하거나, 새로운 필드에 동적으로 적응할 수 있는 '스키마 온 리드(schema-on-read)' 로직을 설계해야 한다.
핵심 포인트
- 스키마 드리프트는 소스 시스템의 무통보 구조 변경으로 발생한다.
- Pydantic/Great Expectations 같은 검증 레이어나 schema-on-read 설계로 방어한다.
안전한 DB 연결
SQLAlchemy나 psycopg2 같은 라이브러리를 사용한다. 결정적으로, f-string이나 문자열 연결 대신 파라미터화 쿼리(%s나 ? 플레이스홀더 사용)를 반드시 써야 한다. 파라미터화 쿼리는 데이터베이스 드라이버가 이스케이프 처리를 담당하도록 해 SQL 인젝션 공격을 방지한다.
핵심 포인트
- SQL 문자열을 직접 조합하지 않고 파라미터화 쿼리를 쓰면, 이스케이프 처리를 드라이버가 담당해 SQL 인젝션을 막을 수 있다.
데이터 레이크 vs 웨어하우스, 스테이징 테이블
데이터 레이크(S3, Azure Data Lake 등)는 원본, 비정형 또는 반정형 데이터를 자연스러운 형식 그대로 저장한다. 데이터 웨어하우스(Snowflake, BigQuery 등)는 분석 쿼리에 최적화된, 고도로 구조화되고 정제된 데이터를 저장한다. Python은 종종 '변환(Transformation)' 단계에서 레이크의 데이터를 웨어하우스로 옮기는 데 쓰인다.
스테이징 테이블은 변환되기 전 원본 데이터의 임시 착지 공간 역할을 한다. 이를 통해 소스 시스템에서 빠르게 데이터를 추출해(소스 시스템의 부하를 최소화하면서) 최종 'gold' 테이블의 무결성을 해치지 않으면서 복잡한 정제 로직을 수행할 안전한 공간을 확보할 수 있다.
보충: 원문이 사용한 'gold' 테이블이라는 표현은 브론즈(원본 그대로)→실버(정제·표준화)→골드(비즈니스 집계) 3단계로 나누는 '메달리온 아키텍처(medallion architecture)'에서 온 용어다. 스테이징 테이블은 대체로 브론즈 계층에, 이번 절에서 다룬 검증·정제 로직은 실버 계층에 해당한다.
핵심 포인트
- 데이터 레이크는 원본 그대로, 웨어하우스는 정제·구조화된 형태로 저장하며 Python은 그 사이 변환을 담당한다.
- 스테이징 테이블은 소스 부하를 줄이고 정제 로직을 안전하게 수행할 임시 공간이다.
- 브론즈/실버/골드로 나누는 메달리온 아키텍처 용어로 보면 스테이징은 브론즈, 정제된 결과는 실버·골드에 해당한다 — 보충.
오케스트레이션과 스케줄링
cron은 단순한 작업에는 통하지만, 전문적인 환경에서는 Apache Airflow, Prefect, Dagster 같은 오케스트레이터를 쓴다. 이 도구들은 복잡한 의존성(예: Job A가 성공하기 전까지는 Job B를 실행하지 않음)을 정의하고, 재시도 로직을 제공하며, 모든 데이터 흐름의 상태를 모니터링할 수 있는 UI를 제공한다.
핵심 포인트
- cron은 단순 스케줄링에는 충분하지만, 잡 간 의존성·재시도·모니터링이 필요한 프로덕션 환경에서는 Airflow/Prefect/Dagster 같은 오케스트레이터가 필요하다.
데이터 리니지 추적
데이터 리니지는 데이터가 어디서 왔고, 어떻게 변환되며, 어디로 향하는지를 보여주는 '지도'다. Python 파이프라인에서는 각 단계마다 메타데이터를 로깅하거나, 코드와 통합되어 데이터 이동을 자동으로 캡처하는 OpenLineage 같은 전문 도구를 사용해 리니지를 추적하는 경우가 많다.
핵심 포인트
- 데이터 리니지는 원본→변환→목적지의 경로를 추적하는 메타데이터다.
- 단계별 로깅이나 OpenLineage 같은 도구로 자동 캡처할 수 있다.
API 통신 — 레이트 리밋과 지수 백오프
'지수 백오프(Exponential Backoff)' 로직을 구현해야 한다. API가 429(Too Many Requests) 오류를 반환하면 스크립트는 짧은 시간(예: 1초) 대기한 뒤 다시 시도해야 한다. 다시 실패하면 대기 시간을 두 배로 늘린다(2초, 4초, 8초...). tenacity 같은 라이브러리는 데코레이터로 이를 쉽게 구현할 수 있게 해준다.
핵심 포인트
- 429 응답에는 지수적으로 대기 시간을 늘려가며 재시도하는 지수 백오프 전략이 필요하다.
- tenacity 같은 라이브러리는 데코레이터 한 줄로 재시도/백오프 로직을 구현하게 해준다.
배치 처리 vs 스트림 처리
배치 처리는 일정 기간(예: 한 시간, 하루) 동안 데이터를 모아 한 번에 처리하는 방식이다. 스트림 처리는 데이터가 도착하는 즉시 각 조각을 처리하는 방식이다. Python은 둘 다 다룰 수 있다 — 배치에는 Pandas/Spark를, 실시간 스트림에는 Faust나 PySpark Streaming 같은 라이브러리를 쓴다.
— 정정/보충: 원문이 스트림 처리 예시로 든 Faust(원래 Robinhood에서 만든, Kafka Streams와 유사한 개념을 Python으로 구현한 라이브러리)는 2026년 현재 활발한 유지보수가 이뤄지지 않고 있어, 신규 프로젝트에서는 첫 선택지로 권하기 어렵다. 실무에서 더 널리 쓰이는 대안은 PySpark Structured Streaming, 또는 Bytewax·Quix Streams 같은 비교적 최근에 나온 Python 네이티브 스트리밍 라이브러리, 혹은 confluent-kafka-python으로 Kafka 컨슈머 API를 직접 다루는 방식이다.
핵심 포인트
- 배치는 일정 기간 데이터를 모아 한 번에, 스트림은 도착 즉시 처리하는 방식이다.
- 원문이 예시로 든 Faust는 2026년 현재 유지보수가 활발하지 않아, PySpark Structured Streaming이나 Bytewax/Quix Streams 같은 대안이 더 권장된다 — 정정.