---
type: knowledge
domain: data
status: active
last-reviewed: 2026-07-27
---

# 데이터 파이프라인·배치 실전

> 한 줄 정의
> 데이터 파이프라인의 품질 기준은 하나다 — **몇 번을 다시 돌려도 같은 결과가 나오고, 안 돌았으면 반드시 티가 나는 것.** 큐·스케줄러·재시도 메커니즘은 [[백그라운드 작업과 스케줄링]], 알림 설계는 [[에러 처리와 로깅 실전]] — 여기는 데이터를 옮기고 적재하는 로직 자체의 규율이다.

## 멱등 적재 — 재실행 = 같은 결과

파이프라인은 반드시 다시 돈다(실패 재처리·소급 재적재·운영자 수동 실행). **INSERT-only 적재는 재실행 = 중복**이므로 설계 자체가 결함이다.

| 기법 | 방식 | 맞는 경우 |
|------|------|----------|
| UPSERT (키 기준 갱신) | 자연 키로 있으면 갱신, 없으면 삽입 | 행 단위 갱신, 대상이 마스터성 데이터 |
| 파티션 교체 (delete-insert) | 대상 구간(예: 해당 일자)을 지우고 통째로 재적재 | 일 단위 집계·이벤트성 데이터 — **구간 전체가 원자적으로 갈린다** |
| 스테이징 → 원자적 전환 | 임시 테이블에 적재 후 rename/swap | 전체 재생성, 적재 중 조회가 반쪽 데이터를 보면 안 될 때 |

- 파티션 교체가 배치의 기본값으로 무난하다 — "이 배치의 재실행 단위는 무엇인가"(일자·소스 파일·파티션)를 먼저 정하면 기법이 따라온다.
- 재실행 단위와 삭제 범위가 어긋나면 사고다: 일자 파티션 교체인데 소스가 이틀치를 담고 있으면 하루가 증발한다.

## 검증 게이트 — 적재 전후로 숫자를 맞춘다

"돌았다"와 "맞다"는 다르다. 게이트는 적재 **전**(쓰레기 유입 차단)과 **후**(결과 대사) 두 겹이다.

| 시점 | 검사 | 실패 시 |
|------|------|--------|
| 적재 전 | 필수값 누락·타입 불일치·도메인 위반(음수 금액 등)·중복 키 | 해당 행 격리(불량 행 테이블) 또는 배치 중단 — **기준을 배치마다 미리 정한다** |
| 적재 후 | 소스 대비 건수 대사·금액 등 합계 대사·"0건 적재" 탐지 | 성공 마킹 금지 — 검증 실패는 실패다 |

- **0건은 성공이 아니라 경보다** — 소스가 비어서 0건인지, 추출이 깨져서 0건인지 파이프라인은 모른다. "평소 대비 건수 급감(예: 50% 미만)"을 게이트에 넣는다.
- 불량 행 격리는 무덤이 되기 쉽다 — 격리 건수를 지표로 노출하고, 재처리 경로를 만든다 ([[백그라운드 작업과 스케줄링]] DLQ와 같은 원리).
- 집계 로직 자체의 검증(fan-out·중복 집계)은 [[데이터 분석 원리]] Sanity Check를 적재 후 게이트에 차용한다.

## 실패 구간 재처리 — 전체 재실행 vs 증분

- 판단 기준: **전체 재실행 시간이 배치 윈도우 안에 들어오는가.** 들어오면 전체 재실행이 단순하고 안전하다(상태 관리 불요). 안 들어오면 증분 — 단, 증분은 "어디까지 성공했나"의 기록(워터마크: 마지막 처리 일자·키·파일명)이 정확해야 하고, 그 기록 갱신과 적재가 원자적이어야 한다.
- 워터마크 갱신을 적재보다 먼저 하면 실패 구간이 영구 누락되고, 나중에 하면 재실행 시 중복이다 — **후자를 선택하고 멱등 적재로 중복을 흡수**하는 것이 표준 조합이다.
- 다단계 파이프라인(추출→변환→적재)은 단계별 재시작 지점을 둔다 — 3시간짜리를 처음부터 다시 사는 구조는 [[백그라운드 작업과 스케줄링]] "거대 작업 하나" 안티패턴 그대로다. DB 쓰기 청크 규율은 [[DB 접근과 트랜잭션 실전]] 대량 처리에 위임.

## 소스 변경 감지 — 스키마 드리프트

소스 시스템은 예고 없이 바뀐다(컬럼 추가·타입 변경·코드 값 신설). 파이프라인의 대표 무성 실패는 "에러 없이 틀린 데이터"다.

- **명시적 컬럼 매핑**만 사용 — `SELECT *` 추출은 소스 컬럼 추가가 곧 스키마 불일치 사고다.
- 처음 보는 코드 값은 버리지도, 아무 값으로 뭉개지도 않는다 — `UNKNOWN`류로 적재하고 **경보를 올린다**. 신규 코드가 조용히 기타 처리되면 집계가 소리 없이 틀어진다.
- 소스 스키마 스냅샷을 주기 비교해 드리프트를 탐지한다. 외주 지점: 소스가 발주사의 타 시스템이면 **변경 통지 절차를 계약·운영 합의에 명시**한다 — "그쪽이 바꿨다"는 통지 체계 없이는 반드시 사후에 안다.

## 배치 윈도우와 지연 전파

- 배치 체인(A→B→C)은 **선행 완료 신호 기반**으로 연결한다 — "A는 새벽 2시에 끝나니까 B는 3시"는 A가 늦어지는 첫날 B가 반쪽 데이터로 돈다. 시각 기반 연결은 지연이 아니라 **오염**을 전파한다.
- 각 배치의 소요 시간을 기록·추이 감시한다 — 데이터는 자라고 윈도우는 고정이다. 윈도우를 넘기기 전에 추이가 먼저 알려준다.
- 지연 데이터(늦게 도착하는 소스)의 처리 방침을 배치마다 결정한다: 다음 주기에 합류시키나, 소급 재적재하나. 미결정이 곧 누락이다.

## 무성 실패 금지 — 안 돌았음을 아는 구조

> [!WARNING] "어제 배치가 안 돌았음을 오늘 아는 구조" 금지
> 스케줄러가 죽으면 에러 로그조차 없다. 실행 실패 알림만으로는 부족하고, **"마지막 성공 시각이 임계를 초과하면 경보"** — 침묵 자체를 감시해야 한다 ([[백그라운드 작업과 스케줄링]] 관측 절이 정본).

- 배치 실행 이력 테이블(배치명·구간·시작/종료·건수·상태)은 파이프라인의 최소 관측 장치이자 외주 검수·운영 이관 문서의 근거다 — 발주사가 "이 배치가 어제 돌았나"를 조회로 확인할 수 있어야 한다.
- 알림 기준·수신자 설계는 [[에러 처리와 로깅 실전]] 알림 예산에 위임 — 배치 특유의 신호는 "실패"보다 **"성공 소식의 부재"** 다.

## 안티패턴

- **INSERT-only 적재** — 재실행이 곧 중복. "재실행 안 하면 되지"는 계획이 아니다.
- **검증 없는 성공 마킹** — 0건 적재·합계 불일치인 채 status=success. 검수에서 "미발견 결함"으로 돌아온다.
- **시각 기반 배치 체인** — 선행 지연이 후행 오염으로 전파되는 구조.
- **수동 보정의 상시화** — "깨지면 내가 지워서 다시 돌리면 돼"는 그 사람이 없는 날 무너진다. 재처리는 절차·도구로 만들고, 운영 문서에 남긴다 — 데이터·로그는 발주사 소유이므로 보정 작업 이력도 발주사 환경에 남아야 한다.

## 관련 문서

- [[00_데이터 허브]] — 07_데이터 진입점
- [[데이터 원리]] — 저장소·파티셔닝·수명주기 원칙
- [[백그라운드 작업과 스케줄링]] — 스케줄러 함정·재시도·DLQ·마지막 성공 시각 감시 (실행 기반)
- [[에러 처리와 로깅 실전]] — 알림 예산·구조화 로깅
- [[DB 접근과 트랜잭션 실전]] — 대량 처리 청크·재개 가능 설계
- [[데이터 분석 원리]] — 집계 검증·Sanity Check
- [[데이터 이관 실전]] — 일회성 대량 이동은 별도 규율
