옌의 로그

(충격) 지금까지 배치 서버를 써본 줄 알았는데… 아니었음 본문

스터디/기타

(충격) 지금까지 배치 서버를 써본 줄 알았는데… 아니었음

dev-yen 2025. 8. 26. 09:00

1. 시작은 ‘배치 서버’라는 이름이었다

예전에 PHP로 서비스 개발을 하던 시절, 특정 시간마다 돌아가는 작업을 “batch”라고 불렀다.

보통 crontab에 등록해두고, 새벽 1시에 포인트 정산, 3시에 푸시 발송 같은 걸 처리했는데

그때는 이게 배치 작업이고, 이걸 돌리는 서버니까 배치 서버인 줄 알았다.

 

Spring Boot로 넘어온 이후에도 마찬가지였다.

Spring에서 @Scheduled만 붙이면 시간마다 메서드가 실행되니까 그걸 띄워두는 서버를 그냥 “배치 서버”라고 불렀다.

 

 

2. 나는 “스케줄링”만 했지, 진짜 “배치 처리”는 안 해봤다

 

Spring Batch를 공부하면서 놀랐다.

내가 해왔던 건 단순히 “정해진 시간에 실행하는 작업”이었고,

진짜 배치 시스템은 훨씬 더 복잡하고 구조화되어 있었다.

 

- 스케줄러는 “언제 실행할지”를 책임지고,

- 배치는 “어떻게 실행할지”를 책임진다.

 

예를 들어 내가 @Scheduled(cron = "0 0 2 * * *") 으로 포인트 정산을 돌렸을 때:

  • 에러 나면? 그냥 실패
  • 몇 명 처리했는지? 로그 봐야 알 수 있음
  • 중간에 꺼지면? 처음부터 다시 해야 됨
  • 데이터 많아지면? 성능 저하

 

이런 걸 하나하나 직접 해결하려고 로직을 넣었었는데,

Spring Batch는 애초에 그런 기능들을 구조화해서 제공한다는 걸 알게 되었다.

 

 

3. 진짜 배치 시스템이 필요한 순간은 언제일까?

상황 Scheduler Batch
단순 반복 작업 ✅ 적합 ❌ 오버스펙
대량 데이터 처리 ❌ 부적합 ✅ 체크포인트, 청크 등 내장
실패 복구 필요 ❌ 직접 구현 ✅ 기본 제공
병렬 처리, 트랜잭션 관리 ❌ 직접 구성 필요 ✅ 구성 요소 분리
처리 이력 관리 ❌ 로그로만 가능 ✅ DB 테이블 자동 생성

 


 

4. Spring Batch의 기본 구조는 어떻게 생겼을까?

Spring Batch는 다음과 같은 구조화된 처리 단계로 구성되어 있다.

 

Job

  • 하나의 배치 작업 단위
  • 여러 Step으로 구성될 수 있음
@Bean
public Job sampleJob(JobBuilderFactory jobBuilderFactory, Step step1) {
    return jobBuilderFactory.get("sampleJob")
        .start(step1)
        .build();
}

 

 

 

Step

  • Job을 구성하는 실행 단위
  • 각각의 Step은 Reader → Processor → Writer 흐름을 가짐
@Bean
public Step step1(StepBuilderFactory stepBuilderFactory,
                  ItemReader<String> reader,
                  ItemProcessor<String, String> processor,
                  ItemWriter<String> writer) {
    return stepBuilderFactory.get("step1")
        .<String, String>chunk(100)
        .reader(reader)
        .processor(processor)
        .writer(writer)
        .build();
}

 

 

 

Reader / Processor / Writer

컴포넌트역할

ItemReader 데이터를 어디서 가져올지 (DB, CSV, API 등)
ItemProcessor 데이터를 어떻게 가공할지 (검증, 변환 등)
ItemWriter 데이터를 어디에 저장할지 (DB, 파일 등)

 

예시:

@Bean
public ItemReader<String> reader() {
    return new FlatFileItemReaderBuilder<String>()
        .name("stringItemReader")
        .resource(new ClassPathResource("input.txt"))
        .lineMapper(new DefaultLineMapper<>())
        .build();
}

 

 

Chunk 처리

  • 데이터를 묶음 단위로 처리해서 성능을 높임
  • 예: 1000건 중 100건 단위로 커밋
.chunk(100)

 

 

배치 메타 테이블

Spring Batch는 실행 이력을 자동으로 관리하기 위해 다음과 같은 테이블을 사용한다:

  • BATCH_JOB_INSTANCE
  • BATCH_JOB_EXECUTION
  • BATCH_STEP_EXECUTION

 

실행 이력 추적, 실패 지점 복구, 재시작 처리를 위해 반드시 필요한 구조다.

 

 

 

5. 난 지금까지 왜 Batch를 안 썼을까?

  • 시스템 규모가 작았고
  • 데이터량이 많지 않았고
  • 장애 시 재처리 요구가 없었고
  • cron + scheduler만으로 충분히 “돌아는 갔기 때문...

 

즉, 작은 규모 + 낮은 복잡도에서는 스케줄러로 충분했던 것이다.

 

하지만 이제는

  • 정산, 포인트, PDF 생성, 발행 등 복잡한 작업이 많아지고,
  • 대용량 사용자 대상의 반복성 있는 작업도 늘어나면서,
  • “진짜 배치 시스템”이 필요한 시점이 된 것 같다.

 


 

마무리하며...

 

나는 지금까지 배치 작업을 하고 있다고 생각했지만,

사실은 정해진 시간에 메서드를 실행하는 스케줄링 작업만 하고 있었던 것이었다.

 

Spring Batch는 단순한 시간 기반 실행이 아닌,

대용량 처리, 장애 복구, 실행 이력 관리, 병렬 처리까지 가능한 진짜 배치 프레임워크다.

 

물론 프로젝트 상황에 맞게 기술을 도입해야 하는 것이지만, 기회가 된다면 spring batch를 도입해서 사용해보고 싶다!

Comments