배경 및 목표

수시→공채 데이터 구조 변경으로 기존 8만 건에서 56만 건을 새로 생성해야 했습니다. 기존에는 데이터 마이그레이션을 스크립트 형태로 실행하고 있었는데, 여러 문제가 있었습니다.

  • 히스토리 부족: 스크립트가 언제, 어떤 파라미터로 실행되었는지 기록이 남지 않음
  • 로직 파악 어려움: 일회성 스크립트가 여러 곳에 산재
  • 재실행 불안정: 중간 실패 시 어디까지 처리되었는지 알 수 없어 처음부터 재실행
  • 서비스 영향 제어 어려움: DB 부하를 제어하기 어려움

목표

  • 수시→공채 구조 변경에 따른 8만→56만 건 데이터를 무중단으로 생성한다.
  • 실패 지점부터 재시작 가능한 안전한 이관을 보장한다.

해결 방법과 해결 후보군

후보군 비교

방식설명한계
일회성 스크립트수동 실행히스토리 없음, 실패 시 처음부터 재실행
애플리케이션 루프코드로 반복 처리재시작·부하 제어를 직접 구현해야 함
Spring Batch (채택)Job/청크/체크포인트히스토리 자동, 재시작, 청크 단위 부하 제어

1. Spring Batch 도입으로 마이그레이션 체계화

일회성 스크립트 대신 Spring Batch Job으로 구성했습니다.

graph LR
    subgraph before["❌ 기존: 스크립트"]
        S1["일회성 스크립트"] --> S2["히스토리 없음"]
        S1 --> S3["실패 시 처음부터"]
        S1 --> S4["부하 제어 어려움"]
    end
    subgraph after["✅ 개선: Spring Batch"]
        B1["Batch Job"] --> B2["실행 히스토리 자동"]
        B1 --> B3["체크포인트 재시작"]
        B1 --> B4["청크 단위 부하 제어"]
    end
  • 실행 히스토리 자동 기록: JobRepository가 시작/종료 시간, 파라미터, 성공/실패, 처리 건수를 자동 기록
  • 로직 구조화: Reader → Processor → Writer의 명확한 단계로, “무엇을 읽고, 어떻게 변환하고, 어디에 쓰는지”가 코드 구조 자체로 드러남
  • 체크포인트 재시작: 장애 시 마지막 커밋 지점부터 재개

2. 청크 기반 처리로 안정성 확보

전체 56만 건을 한 번에 처리하면 메모리 부족이 발생하므로, 청크 단위(100건씩)로 읽기 → 변환 → 쓰기를 반복합니다.

graph TB
    subgraph batch["Spring Batch Job"]
        R["Reader: 기존 데이터 100건 조회"] --> P["Processor: 신규 구조로 변환"]
        P --> W["Writer: 신규 데이터 저장"]
        W -->|"청크 커밋 (체크포인트)"| R
    end

56만 건 중 30만 건 처리 후 장애가 나면, 재실행 시 나머지 26만 건만 처리하면 됩니다.

3. 운영 영향 최소화

듀얼라이트 마이그레이션 전략과 함께 실행되었으므로, 배치가 진행되는 동안에도 서비스는 정상 동작합니다. 배치 전용 DB 커넥션 풀을 분리하여 서비스 쿼리와의 경합을 방지했습니다.


결과

지표기존 (스크립트)개선 (Spring Batch)
실행 히스토리없음자동 기록
실패 시 복구처음부터 재실행체크포인트 재시작
로직 파악스크립트 산재Reader→Processor→Writer
처리량-56만 건, 9,300건/분
성공률-100%

모니터링

  • 배치 청크별 처리 건수·처리율(건/분)과 실패·재시작 지점을 관측한다.
  • 이관 후 원본↔생성 데이터 건수 정합성을 관측한다.