배경 및 목표
수시→공채 데이터 구조 변경으로 기존 8만 건에서 56만 건을 새로 생성해야 했습니다. 기존에는 데이터 마이그레이션을 스크립트 형태로 실행하고 있었는데, 여러 문제가 있었습니다.
- 히스토리 부족: 스크립트가 언제, 어떤 파라미터로 실행되었는지 기록이 남지 않음
- 로직 파악 어려움: 일회성 스크립트가 여러 곳에 산재
- 재실행 불안정: 중간 실패 시 어디까지 처리되었는지 알 수 없어 처음부터 재실행
- 서비스 영향 제어 어려움: DB 부하를 제어하기 어려움
목표
- 수시→공채 구조 변경에 따른 8만→56만 건 데이터를 무중단으로 생성한다.
- 실패 지점부터 재시작 가능한 안전한 이관을 보장한다.
해결 방법과 해결 후보군
후보군 비교
| 방식 | 설명 | 한계 |
|---|---|---|
| 일회성 스크립트 | 수동 실행 | 히스토리 없음, 실패 시 처음부터 재실행 |
| 애플리케이션 루프 | 코드로 반복 처리 | 재시작·부하 제어를 직접 구현해야 함 |
| Spring Batch (채택) | Job/청크/체크포인트 | 히스토리 자동, 재시작, 청크 단위 부하 제어 |
1. Spring Batch 도입으로 마이그레이션 체계화
일회성 스크립트 대신 Spring Batch Job으로 구성했습니다.
- 실행 히스토리 자동 기록:
JobRepository가 시작/종료 시간, 파라미터, 성공/실패, 처리 건수를 자동 기록 - 로직 구조화: Reader → Processor → Writer의 명확한 단계로, “무엇을 읽고, 어떻게 변환하고, 어디에 쓰는지”가 코드 구조 자체로 드러남
- 체크포인트 재시작: 장애 시 마지막 커밋 지점부터 재개
2. 청크 기반 처리로 안정성 확보
전체 56만 건을 한 번에 처리하면 메모리 부족이 발생하므로, 청크 단위(100건씩)로 읽기 → 변환 → 쓰기를 반복합니다.
56만 건 중 30만 건 처리 후 장애가 나면, 재실행 시 나머지 26만 건만 처리하면 됩니다.
3. 운영 영향 최소화
듀얼라이트 마이그레이션 전략과 함께 실행되었으므로, 배치가 진행되는 동안에도 서비스는 정상 동작합니다. 배치 전용 DB 커넥션 풀을 분리하여 서비스 쿼리와의 경합을 방지했습니다.
결과
| 지표 | 기존 (스크립트) | 개선 (Spring Batch) |
|---|---|---|
| 실행 히스토리 | 없음 | 자동 기록 |
| 실패 시 복구 | 처음부터 재실행 | 체크포인트 재시작 |
| 로직 파악 | 스크립트 산재 | Reader→Processor→Writer |
| 처리량 | - | 56만 건, 9,300건/분 |
| 성공률 | - | 100% |
모니터링
- 배치 청크별 처리 건수·처리율(건/분)과 실패·재시작 지점을 관측한다.
- 이관 후 원본↔생성 데이터 건수 정합성을 관측한다.