복잡한뇌구조마냥

[Spring] Spring Batch + Scheduler 정리 본문

BE/Spring

[Spring] Spring Batch + Scheduler 정리

지금해냥 2025. 11. 27. 08:59

실제 서비스를 운영하다 보면 아래 같은 요구가 반드시 생긴다.

  • 매일 0시에 통계 집계 돌리기
  • 예약일 하루 전 알림 보내기
  • 오래된 로그 삭제하기
  • 대량 데이터 업데이트 또는 ETL 실행

이런 작업들은 정상적인 요청/응답 기반 API에서 처리하기 어렵고,
정해진 시점(time-based)에 반복 실행되어야 하는 로직이기 때문에
스케줄러와 배치가 필요해진다.

하지만 개발자들이 헷갈리는 대표적인 질문이 하나 있다.

“스케줄러는 @Scheduled? Quartz? Spring Batch랑은 어떻게 연결하지?
배치랑 스케줄러를 같이 써도 되는 건가?”


1. 🔥 스케줄러와 배치의 본질적인 차이

먼저 개념부터 명확하게 정리하자.

역할 도구 핵심 포인트
언제(When) 실행할 것인가? @Scheduled, Quartz 실행 스케줄 관리
무엇(What)을 어떻게 처리할 것인가? Spring Batch 대량 처리/청크 처리/재시작/로직 관리

👉 스케줄러 = 언제 실행할지 결정
👉 배치 = 실제 비즈니스 로직을 어떻게 실행할지 정의

이 둘은 경쟁 관계가 아니라, 책임을 나눠 갖는 보완 관계다.
서로 필요할 때 함께 쓰는 것이 오히려 정석이다.


2. 🧩 @Scheduled — 가장 간단한 스케줄러

Spring이 기본 제공하는 스케줄러로 가장 사용하기 쉽다.

✔ 설정

 
@Configuration
@EnableScheduling
public class SchedulerConfig {}

✔ 사용 예시

 
@Component
public class SimpleScheduler {

    // 10초마다 실행
    @Scheduled(fixedRate = 10_000)
    public void run() {
        System.out.println("10초마다 실행");
    }

    // 매일 0시 실행
    @Scheduled(cron = "0 0 0 * * *")
    public void runMidnightTask() {
        System.out.println("매일 0시에 실행");
    }
}

✔ 장점

  • 설정 간단
  • 코드만으로 쉽게 가능
  • 작은 규모의 주기 작업에 최적

✔ 단점

  • 멀티 인스턴스 환경에서는 중복 실행될 수 있음
  • 스케줄 시간 변경하려면 코드 수정 + 재배포 필요
  • misfire 처리, 재시도, 잡 이력 관리 없음

👉 단일 서버 + 단순 작업일 경우 매우 좋음.


3. 🧩 Quartz — 스케줄링 자체가 중요한 경우의 끝판왕

Quartz는 독립적인 스케줄링 프레임워크다.
스케줄 자체를 운영과 분리하여 정교하게 관리해야 할 때 유일한 선택지 중 하나다.

✔ 특징

  • Cron 표현식 + Calendar + misfire 정책 지원
  • DB 기반 Job 관리 가능
  • 여러 서버에서도 중복 실행 없이 클러스터링 가능
  • 스케줄을 운영에서 수정 가능

✔ 기본 코드 구조

Job 정의

 
public class SampleJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) {
        System.out.println("Quartz Job 실행");
    }
}

Trigger + JobDetail 설정

 
@Configuration
public class QuartzConfig {

    @Bean
    public JobDetail jobDetail() {
        return JobBuilder.newJob(SampleJob.class)
                .withIdentity("sampleJob")
                .storeDurably()
                .build();
    }

    @Bean
    public Trigger trigger() {
        return TriggerBuilder.newTrigger()
                .forJob(jobDetail())
                .withIdentity("sampleTrigger")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 * * ?"))
                .build();
    }
}

✔ 장점

  • 정교하고 안정적인 스케줄 관리
  • 분산 환경 대응
  • 다양한 트리거 정책
  • 실행 이력 관리 가능

✔ 단점

  • 설정 복잡
  • 작은 프로젝트에서는 과한 선택
  • 스케줄 실행만 책임지고 실제 로직은 직접 작성해야 함

4. 🧩 Spring Batch — “배치 로직”을 담당하는 프레임워크

스케줄러는 단순히 “언제” 실행할지만 결정할 뿐,
배치 작업의 핵심은 대량 데이터 처리 로직 관리이다.

Spring Batch는 아래 같은 기능을 제공한다.

✔ Spring Batch가 해결하는 문제

기능 설명
청크(chunk) 기반 처리 100개씩 읽고 → 처리 → 커밋 형태
재시작(restart) 실패한 지점부터 이어서 처리
skip/retry 정책 오류 허용/재시도 처리
Job / Step / Reader / Processor / Writer 구조 책임 명확
Job Repository 실행 이력, 상태 관리
트랜잭션 관리 대량 처리에서 핵심

즉, 배치 로직을 안정적으로, 대량 데이터를 처리하기 위한 프레임워크이다.


5. 🔗 “배치 + 스케줄러” 같이 쓰는 게 정석인 이유

배치를 실행하기 위해서는 트리거(trigger) 가 필요하다.
즉, 배치 자체에는 “언제”라는 개념이 없다.

그래서:

  • @Scheduled → 배치 Job 실행
  • Quartz → 배치 Job 실행

6. 스케줄러 + 배치 예

🧩 @Scheduled → Spring Batch 실행 (코드 예시)

 
@Component
@RequiredArgsConstructor
public class SampleBatchScheduler {

    private final JobLauncher jobLauncher;
    private final Job sampleJob;

    @Scheduled(cron = "0 0 0 * * *") // 매일 0시
    public void runSampleJob() throws Exception {
        JobParameters params = new JobParametersBuilder()
                .addLong("timestamp", System.currentTimeMillis()) // 재실행 구분자
                .toJobParameters();

        jobLauncher.run(sampleJob, params);
    }
}

🧩 Quartz → Spring Batch 실행 (고급 패턴)

 
@Component
@RequiredArgsConstructor
public class QuartzBatchJob extends QuartzJobBean {

    private final JobLauncher jobLauncher;
    private final Job batchJob;

    @Override
    protected void executeInternal(JobExecutionContext context) {
        JobParameters params = new JobParametersBuilder()
                .addLong("runId", System.currentTimeMillis())
                .toJobParameters();

        try {
            jobLauncher.run(batchJob, params);
        } catch (Exception e) {
            // 실패 관리 가능
        }
    }
}

여러 서버에서 Quartz 클러스터링을 사용하면
→ 배치 실행을 안전하게 단일 실행으로 보장할 수 있다.


8. 🧨 @Scheduled vs Quartz vs Spring Batch 비교표 (핵심 요약)

항목 @Scheduled Quartz Spring Batch
역할 간단 스케줄러 고급 스케줄러 배치 처리 로직
목적 “언제” 실행할지 “언제” + “어떻게 스케줄 관리할지” “무엇을 어떻게 처리할지”
난이도 매우 쉬움 중간~높음 중간
분산 환경
재시작/재실행
대량 처리
실행 이력 관리 DB 저장 가능 JobRepository에서 기본 제공
운영에서 스케줄 수정

📌 Spring Batch 구성요소 정리

✔ Job
Spring Batch의 가장 큰 실행 단위.
여러 Step으로 구성되며 Step들을 순차적으로 실행한다.

✔ Step
Job을 구성하는 실행 단계.
Tasklet 방식 또는 Chunk 방식으로 처리된다.

✔ Tasklet
Step 내부에서 동작하는 최소 실행 단위.
단일 작업(파일 생성, 테이블 초기화 등)에 적합.

✔ Chunk 지향 처리
대량 데이터를 효율적으로 처리하는 방식.
정해진 chunk size만큼 데이터를 읽고(Reader) → 가공(Processor) → 저장(Writer) 한다.

✔ ItemReader
외부 데이터(DB, 파일 등)를 한 건씩 읽어오는 역할.
데이터가 끝나면 null 반환하여 Step 종료.

✔ ItemProcessor
Reader가 읽은 데이터를 가공하거나 필터링하는 역할.

✔ ItemWriter
가공된 데이터를 저장(DB, 파일, 외부 시스템 등).
청크 단위로 커밋되어 성능적으로 유리함.

✔ JobRepository
Job/Step 실행 이력, 상태, 실패 지점 등을 저장하는 저장소.
재시작·재실행 기능이 여기에 기반한다.

✔ JobInstance
Job의 “논리적 실행 단위”.
예: 날짜별로 다른 JobInstance로 취급됨.

✔ JobExecution
JobInstance의 실제 실행 기록(성공/실패/재시작 등).

✔ StepExecution
각 Step의 실행 이력(읽은 데이터 수, 성공/실패 기록 등).

✔ ExecutionContext
Job 또는 Step 실행 중 임시 데이터를 저장하는 공간.
재시작 시 이전 진행 정보를 활용하기 위해 존재.

✔ JobLauncher
코드에서 Job을 실행할 때 사용하는 인터페이스.
스케줄러(@Scheduled, Quartz)가 Job을 실행할 때 호출한다.

✔ JobOperator
Job 중지, 재시작, 실행 이력 조회 등 운영 제어 기능을 제공.


9. 🧩 결론 — "언제"와 "무엇"을 분리해서 생각하면 쉽다

정리하면 이렇게 된다:

  • 스케줄러(@Scheduled / Quartz)
    → “언제 실행할지” 관리하는 도구
  • Spring Batch
    → “비즈니스 로직을 어떻게 처리할지” 관리하는 도구

 

참고자료:

https://ittrue.tistory.com/326#google_vignette

 

[Spring Batch] 스프링 배치란 무엇인가? - 개념, 아키텍처, 구성요소

본 내용은 온라인 강의 사이트 인프런의 정수원 님의 강의 내용이 포함되어 있습니다. 스프링 배치 - Spring Boot 기반으로 개발하는 Spring Batch 스프링 배치 - Spring Boot 기반으로 개발하는 Spring Batch -

ittrue.tistory.com

https://velog.io/@yjc1116/Spring-Batch

 

Spring Batch

이번 취밋 프로젝트를 작업하면서 스케줄 기반으로 처리해야 하는 작업들이 점점 많아지면서 Quartz를 도입하게 되었다. 하지만 Quartz를 설명하기 전에, 먼저 배치 처리의 기본 개념과 Spring Batch가

velog.io

 

LIST