내일배움캠프

[내일배움캠프] Spring Batch

munsik22 2026. 6. 15. 17:12

🧩 배치 처리가 필요한 이유

배치 처리(Batch Processing)는 사용자의 요청에 즉시 응답하는 작업이 아니라, 정해진 시간이나 조건에 따라 여러 데이터를 모아서 처리하는 방식을 의미한다.

 

배치 처리는 사용자가 응답을 기다리지 않아도 되는 작업을 시스템 내부에서 처리한다. 주로 많은 데이터를 일정 기준에 따라 읽고, 검증하고, 변환하고, 저장하는 업무에 사용된다.

  • 배치 처리가 필요한 상황: 데이터가 많은 경우, 즉시 응답이 필요하지 않은 경우, 정해진 시간에 반복 실행되는 경우(CRON), 실패 시 재실행이 필요한 경우, 처리 이력을 남겨야 하는 경우, 원본 데이터를 다른 형태로 가공해야 하는 경우
  • 배치 처리에 적합한 업무: 일일 주문 정산, 월간 통계 생성, 대량 알림 발송, 데이터 이관, 파일 처리, 검색 색인 생성, Read Model 생성, 이벤트 후처리, 만료 데이터 정리 등

웹 요청 처리와 배치 처리의 차이

구분 웹 요청 처리 (HTTP, TCP, ...) 배치 처리
실행 시점 사용자가 요청한 시점 정해진 시간, 조건, 수동 실행 시점
처리 기준 빠른 응답이 중요 안정적인 처리와 실행 관리가 중요
데이터 양 상대적으로 작은 단위 많은 데이터를 처리하는 경우가 많음
실패 처리 사용자에게 실패 응답을 반환 실패 지점 기록과 재실행이 필요함
실행 이력 별도 구현이 필요한 경우가 많음 JobRepository를 통해 관리
대표 업무 로그인, 주문 요청, 조회 API 등 정산, 통계, 이관, 리포트 생성 등
  • 사용자가 직접 기다려야 하는 기능 → 웹 요청 처리
  • 시간이 오래 걸리거나 데이터가 많은 후처리 업무 → 배치 처리로 분리

단순 반복문의 한계

  • 작은 규모의 데이터라면 단순 반복문으로 처리할 수 있지만 실무 수준에서는 다음과 같은 문제가 발생할 수 있다.
  • 메모리 부담
  • 실패 지점 추적 어려움: 중간에 실패했을 때 어디까지 처리했는지 확인 어려움
  • 재실행 기준 불명확: 전체를 다시 처리할지 일부만 처리할지?
  • 중복 처리 위험
  • 트랜잭션 범위 문제
  • 운영 관찰 부족
  • 업무 단계 혼합

Spring Batch는 이러한 문제들을 해결하기 위해 ① 작업을 Job, Step으로 나누고데이터를 Chunk 단위로 분리해 처리하고 ③ 실행 이력을 JobRepository에 저장한다.

🧩 Spring Batch의 기본 실행 구조

Spring Batch는 배치 작업을 만들기 위한 프레임워크다. 단순히 반복문을 대신 작성해주는 도구가 아니라 배치 실행을 관리하기 위한 구조를 제공한다.

 

Spring Batch의 주요 역할

  • 실행 구조 제공: Job과 Step을 기준으로 배치 작업 구성
  • 실행 이력 관리: JobRepository를 통해 실행 상태 및 결과 저장
  • 재실행 관리
  • 트랜잭션 관리: Chunk 단위로 Commit과 Rollback 관리 가능
  • 대용량 처리 구조 제공: Reader, Processor, Writer 구조로 데이터를 나눠서 처리
  • 운영 확장 지점 제공: Listener를 통해 로그, 알림, 모니터링 연결 가능

Spring Batch 핵심 구성 요소

구성 요소역할
JobLauncher Job 실행을 시작하는 객체
Job 하나의 배치 작업 전체
Step Job을 구성하는 세부 처리 단계
JobRepository Job과 Step의 실행 이력, 상태, 파라미터를 저장
JobParameter 같은 Job의 서로 다른 실행을 구분하는 입력값
ItemReader 데이터를 읽는 역할
ItemProcessor 데이터를 검증하거나 변환하는 역할
ItemWriter 처리된 데이터를 저장하는 역할
Listener 실행 전후에 로그, 알림, 모니터링 같은 부가 작업을 수행

 

Spring Batch 실행 흐름

JobRepository의 역할

JobRepository의 구성요소

저장 정보 설명
JobInstance Job 이름과 식별용 JobParameter로 만들어지는 논리적 실행 단위
JobExecution 실제 Job 실행 시도 한 번
StepExecution 각 Step의 실행 상태와 처리 건수
ExecutionContext 재시작에 필요한 상태 정보
JobParameter 실행 날짜, 파일 경로, 회사 ID 등 실행을 구분하는 값
  • (Q) 첫번째 실행 실패하고 다시 실행해서 성공했다면 jobExecution은 몇 개?
  • (A) 실패해도 jobExecution은 생기므로 2개

Job과 Step

Job은 하나의 배치 업무 전체를 의미한다. Step은 Job을 구성하는 세부 처리 단계이다.

Job과 Step 설계 예시

 

Job을 여러 Step으로 나누는 이유

  • 실패 지점을 명확하게 하기 위해서
  • 재실행 기준을 잘 나누기 위해서
  • 트랜잭션 범위를 분리하기 위해서
  • 코드를 구조화하기 위해서

Step 분리 기준

  • 업무 단계 기준 (예: 검증, 계산, 저장, 알림)
  • 처리 방식 기준: Tasklet과 Chunk가 달라지는 경우 분리 (예: 사전 검증은 Tasklet, 데이터 처리는 Chunk)
  • 실패 복구 기준: 재실행 기준이 달라지면 분리 (예: 파일 검증 실패, DB 저장 실패)
  • 트랜잭션 기준 (예: 데이터 저장, 알림 발송)
  • 데이터 소스 기준 (예: 주문 DB 조회, 결제 DB 조회)

Step 처리 방식

  • Tasklet: Step 안에서 하나의 작업을 직접 실행하는 방식
  • Chunk: 데이터를 일정 개수만큼 나눠서 읽고 처리하고 저장하는 방식
💡 단순 작업은 Tasklet, 대형 데이터 반복 처리는 Chunk 방식으로

Tasklet 방식

Tasklet은 Step 안에서 개발자가 직접 처리 로직을 작성하는 방식이다. 대량 데이터를 반복 처리하기보다는 단순 실행 작업에 적합하다.

 

Tasklet에 적합한 작업

  • 파일 존재 여부 확인
  • 실행 조건 검증
  • 임시 테이블 초기화
  • 오래된 파일 삭제
  • 관리자 알림 발송
  • 단순 상태 변경

Tasklet 실행 흐름

일반적인 Tasklet은 작업을 1번 수행한 뒤 RepeatStatus.FINISHED를 반환한다.

 

Tasklet 코드 예시

@Bean
public Step validateFileStep(JobRepository jobRepository,
                             PlatformTransactionManager transactionManager) {
    return new StepBuilder("validateFileStep", jobRepository)
            .tasklet((contribution, chunkContext) -> {
                String filePath = "/data/orders.csv";
                File file = new File(filePath);

                if (!file.exists()) {
                    throw new IllegalStateException("처리 대상 파일이 존재하지 않습니다.");
                }

                return RepeatStatus.FINISHED;
            }, transactionManager)
            .build();
}

Chunk 방식

Chunk 방식은 대량 데이터를 일정 단위로 나누어 처리하는 방식이다.

 

Chunk의 구성 요소

  • ItemReader: 데이터를 한 건씩 읽음
  • ItemProcessor: 읽은 데이터를 검증하거나 변환함
  • ItemWriter: 처리된 데이터를 Chunk 단위로 저장함

 

Chunk 방식이 필요한 이유

대량의 데이터를 한번에 처리하면 메모리 사용량이 커지고 실패했을 때 복구 비용도 커진다. Chunk 방식은 다음과 같은 장점이 있다.

  • 메모리 부담 감소
  • 트랜젝션 범위 조절: Chunk 단위 Commit 및 Rollback
  • 실패 범위 축소
  • 역할 분리
  • 확장성 확보: Reader, Processor, Writer 교체 또는 확장 쉬움

Chunk 실행 순서

Reader와 Processor는 한 건씩 동작한다. Writer는 지정된 Chunk 크기만큼 데이터가 모였을 때 한 번에 저장한다.

 

Reader, Processor, Writer의 처리 단위

  • ItemReader: 데이터를 1건 씩 읽음
  • ItemProcessor: 읽은 데이터를 1건 씩 검증 또는 변환함
  • ItemWriter: 처리된 데이터를 Chunk 단위로 묶어서 저장함

Chunk 단위 트랜잭션

Chunk 방식에서는 일반적으로 Chunk 1 : 트랜잭션 1

Chunk size 결정 기준

데이터 크기, DB 부하, 트랜잭션 시간, 실패 복구 범위를 함께 고려해야 한다.

  • 데이터 1건의 크기: 데이터 크기가 크면 Chunk size는 작은 것이 안전함
  • DB 쓰기 성능: Writer가 한번에 너무 많은 데이터를 저장하면 DB 부하가 커짐
  • 트랜잭션 시간: 길어지면 락과 장애 가능성 상승
  • 실패 복구 범위
  • 전체 처리 시간
Chunk size 장점 단점
작게 설정 실패 시 재처리 범위가 작습니다. 메모리 부담이 낮습니다. Commit 횟수가 많아져 성능이 떨어질 수 있습니다.
크게 설정 Commit 횟수가 줄어 성능이 좋아질 수 있습니다. 메모리 사용량이 커지고 실패 시 Rollback 범위가 커집니다.

Spring Scheduler와의 차이점

사실 Scheduler 개념이랑 혼동했었다. 물론 Batch에도 일정 주기 반복 작업 기능이 있지만, 둘 사이에는 목적과 사용 방식에 차이가 있다.

  • Spring Scheduler: 정해진 시간(주기)에 특정 작업을 자동으로 실행하는 알람 시계 역할
  • Spring Batch: 대규모 데이터를 효율적이고 안정적으로 일괄 처리(Batch)하는 대형 화물차 역할
구분 Spring Scheduler Spring Batch
주요 목적 시간 기반의 작업 트리거 (정해진 시간에 실행) 대용량 데이터 일괄 처리 (안전하고 안정적인 데이터 처리)
작업 단위 단일 메서드 1회 실행 Job → Step → Tasklet/Chunk 구조의 복잡한 단위
장애 대응 실패 시 자동 재시도 기능 없음 실패 시 재시도(Retry), 건너뛰기(Skip), 로깅 등 강력한 내결함성(Fault-Tolerant) 제공
상태 관리 작업 실행 여부 추적 안 됨 (DB 저장 없음) 실행 결과, 성공/실패 여부, 처리 건수 등을 DB에 메타데이터로 기록
트랜잭션 메서드 단위 (개발자가 직접 제어) Chunk 단위 등 세밀한 트랜잭션 관리 및 롤백 지원
  • Spring Scheduler는 매일 오전 9시에 알림 메일 발송, 5분마다 캐시 갱신 등 간단한 주기성 작업에 적합하다.
  • Spring Batch는 월말 정산, 대량 결제 내역 처리, 수백만 건의 DB 마이그레이션 등 대용량 데이터 처리에 적합하다.

실무에서는 보통 두 기술을 함께 사용한다고 한다: Spring Scheduler가 정해진 시간에 트리거(알람) 역할을 하여 Spring Batch의 Job을 실행시키는 방식으로

 

자세한 내용은 아래 글을 확인하자.

 

스프링 배치와 스케줄러의 차이점 및 활용 사례

이 블로그 포스트에서는 스프링 배치와 스케줄러의 차이점, 주요 구성 요소, 통합 방법 및 실제 사례를 다룹니다. 이를 통해 두 가지 기술을 적절히 활용하여 다양한 작업을 자동화하는 방법을

f-lab.kr