이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- Batch 실패를 발견했을 때 원인 분석 전에 어떤 영향 범위를 먼저 확인해야 하는가?
- 마지막 정상 실행, 실패 partition, 중복 안전성, 재처리 범위는 어떤 쿼리로 찾는가?
- 재실행 버튼을 누르기 전에 downstream 공개 중단과 owner 알림을 어떻게 결정하는가?
- Batch 복구가 끝났다고 판단하려면 어떤 source-target 검증을 남겨야 하는가?
개요
Batch 실패 대응은 job을 다시 실행하는 일이 아니다.
운영자는 먼저 어떤 데이터가 늦거나 틀렸는지, 사용자가 영향을 받는지, 어디부터 다시 처리할 수 있는지 확인해야 한다.
원인 분석은 중요하지만, 장애 중에는 영향 완화와 재처리 경계가 먼저다.
첫 10분
Batch 실패 알림을 받으면 다음 순서로 본다.
- 실패한 job 이름과 run id.
- 마지막 성공 run.
- 실패한 partition 또는 target range.
- downstream 사용자 영향.
- 자동 retry 중인지, 수동 개입이 필요한지.
- 동일 job의 중복 실행 여부.
- 공개 중단, dashboard banner, downstream pause 필요 여부.
이 순서가 없으면 원인 로그를 보는 동안 잘못된 데이터가 계속 소비될 수 있다.
기본 상태 쿼리
SELECT job_name,
run_id,
status,
target_from,
target_to,
started_at,
finished_at,
error_message
FROM batch_job_runs
WHERE job_name = 'daily_order_mart'
ORDER BY started_at DESC
LIMIT 10;SELECT max(target_to) AS last_success_to
FROM batch_job_runs
WHERE job_name = 'daily_order_mart'
AND status = 'SUCCESS';마지막 성공 지점이 없으면 재처리 범위를 감으로 정하게 된다.
영향 범위 확인
Batch 실패는 항상 같은 영향이 아니다.
SELECT count(*) AS source_orders,
coalesce(sum(paid_amount), 0) AS source_amount
FROM orders
WHERE paid_at >= timestamp '2026-06-30 00:00:00'
AND paid_at < timestamp '2026-07-01 00:00:00';
SELECT count(*) AS mart_orders,
coalesce(sum(paid_amount), 0) AS mart_amount
FROM mart_order_daily
WHERE order_date = date '2026-06-30';count와 sum이 모두 필요한 이유는 row 수가 같아도 금액 계산이 틀릴 수 있기 때문이다.
검색, 추천, 리포트가 같은 batch 결과를 사용한다면 각 downstream의 freshness도 함께 확인한다.
중복 안전성 확인
재실행 전에 target writer가 idempotent한지 확인한다.
안전한 패턴:
- partition 단위 delete 후 insert.
MERGE또는 upsert.- unique key 기반 overwrite.
- run id와 target range 기록.
위험한 패턴:
- 단순 append.
- 같은 source row를 다시 읽으면 target row가 두 배가 되는 구조.
- 이전 실패 결과 일부가 남아 있는데 이어서 insert.
- 외부 side effect를 batch 안에서 직접 호출.
중복 안전성을 모르면 재실행이 장애 복구가 아니라 장애 확대가 된다.
실행 결정
재처리 command에는 범위가 드러나야 한다.
./run-batch daily-order-mart \
--from 2026-06-30T00:00:00+09:00 \
--to 2026-07-01T00:00:00+09:00 \
--mode reprocess \
--requested-by incident-dq-20260630좋은 command는 다음 정보를 남긴다.
- job 이름.
- target range.
- 실행 mode.
- 요청자 또는 incident id.
- dry run 여부.
단순 “rerun latest”는 기록으로 남겨도 다음 사람이 무엇을 다시 처리했는지 알기 어렵다.
Downstream 완화
데이터가 늦거나 틀린 상태라면 복구 전에 공개를 조절해야 한다.
- dashboard에 stale banner를 띄운다.
- 정산 리포트 export를 잠시 막는다.
- recommendation feature update를 pause한다.
- search index가 오래된 값을 보여주면 fallback 기준을 정한다.
- API가 정상이어도 데이터 freshness 공지를 남긴다.
완화 조치는 과잉 대응이 아니다.
잘못된 데이터가 의사결정에 쓰이는 시간을 줄이는 장치다.
완료 검증
Batch가 성공 상태로 끝났다고 복구가 끝난 것은 아니다.
다음 검증을 남긴다.
SELECT q.rule_name,
q.status,
q.checked_at,
q.details
FROM quality_rule_runs q
WHERE q.dataset_name = 'mart_order_daily'
AND q.target_date = date '2026-06-30'
ORDER BY q.checked_at DESC;SELECT 'source' AS side, count(*) AS rows, sum(paid_amount) AS amount
FROM orders
WHERE paid_at >= timestamp '2026-06-30 00:00:00'
AND paid_at < timestamp '2026-07-01 00:00:00'
UNION ALL
SELECT 'mart' AS side, count(*) AS rows, sum(paid_amount) AS amount
FROM mart_order_daily
WHERE order_date = date '2026-06-30';완료 기준은 job status가 아니라 source와 target이 의미 있게 맞는지다.
기록 양식
incident: batch-daily-order-mart-20260630
detected_at: 2026-06-30 09:10 KST
job: daily_order_mart
failed_run: scheduled__2026-06-30
last_success: 2026-06-29 03:18 KST
affected_range: 2026-06-30
mitigation: finance dashboard stale banner
action: reprocess 2026-06-30
validation:
source_count: 183920
mart_count: 183920
source_amount: 128391100
mart_amount: 128391100
follow_up:
- add freshness P2 alert
- add enum contract test이 기록은 회고와 다음 재처리의 시작점이 된다.
운영 지표
batch_failure_to_ack_minutes: 실패 감지부터 담당자 확인까지의 시간.last_success_age: 마지막 성공 run이 얼마나 오래됐는지.reprocess_duration: 재처리 시작부터 검증 완료까지의 시간.duplicate_target_rows: 재처리 후 중복 target row 수.manual_rerun_without_range_count: 범위 없이 수동 재실행한 횟수.
runbook 지표는 장애 대응 순서가 개선되고 있는지 보여준다.
위험 신호!
- 실패 알림을 보고 곧바로 rerun을 누른다.
- 마지막 성공 partition을 모른다.
- target writer가 append인지 overwrite인지 확인하지 않는다.
- dashboard 사용자가 먼저 stale data를 발견한다.
- job success 후 source-target 검증 없이 장애를 닫는다.
확인 질문
확인 질문
- Batch 실패 대응에서 last success와 target range를 먼저 찾는 이유는 무엇인가?
- 재실행 전에 idempotent writer인지 확인하지 않으면 어떤 문제가 생기는가?
- job status가 SUCCESS여도 품질 rule을 봐야 하는 이유는 무엇인가?
- 장애 기록에 실행 command와 검증 SQL 결과를 남겨야 하는 이유는 무엇인가?
참고 문서
- Spring Batch Reference
- Apache Airflow Documentation
- PostgreSQL Documentation
- Martin Kleppmann, Designing Data-Intensive Applications