Batch 개발 가이드

본 문서에서는 X2BEE 배치 시스템 구성 및 Spring Boot Batch에 대해 설명합니다.

먼저, Cronicle 스케줄러의 작성 방법과 소스 코드 작성 절차를 설명하고, 이를 토대로 간단한 배치 작업을 수행하는 샘플 프로그램 목록을 제공합니다.


X2BEE 배치 시스템 구성

다음은 배치 시스템 전체 구성도 입니다.

구분
설명

배치서비스

배치 업무를 수행하는 프로그램입니다. 스케줄러에 의해 정해진 주기로 기능이 실행되거나 즉시 실행될 수 있습니다. 데이터 저장소의 데이터를 조회하여 처리 후 다시 데이터 저장소에 저장하는 것이 주요 업무입니다. Spring batch를 사용하여 구현되며, Web 서비스로 동작하여 HTTP 요청을 통해 배치 잡(job)을 실행할 수 있습니다.

스케줄러

배치 잡(job)과 그 실행주기를 등록하고 관리합니다. 실행 주기가 되었을 때 배치 잡이 실행되도록 배치 서비스에 HTTP 요청을 보내고, 필요에 따라 즉시 실행 기능을 제공합니다. 실행 결과 로그를 남기고 실행 결과 통계를 UI를 통해서 제공합니다. 공개소프트웨어를 사용합니다.

BO배치관리

필요에 따라 보다 세부적인 배치 관리 기능을 BO 시스템에 커스텀으로 구현합니다. 데이터 처리 및 통계 및 즉시 중지 기능 등을 제공합니다.

데이터저장소

대상 데이터는 제한이 없으며 DB, File, S3, Queue 등을 사용할 수 있습니다.


Spring boot batch 설명

배치 서비스는 Spring Batch를 사용하여 개발합니다.

Spring Batch는 로깅/추적, 트랜잭션 관리, 작업 처리 통계, 작업 재시작, 건너뛰기 및 리소스 관리와 같이 대량의 레코드를 처리하는 데 필요한 재사용 가능한 핵심 기능을 제공합니다. 또한 최적화 및 파티셔닝 기술을 활용하여 고성능 배치 작업을 효과적으로 수행할 수 있는 고급 기술과 기능을 제공합니다.

Spring Batch 프로그램 구조

Spring Batch 프로그램 구조는 Tasklet 기반과 Chunk 기반으로 나뉩니다.

Chunk 기반

  • 한 번에 고정된 양의 레코드(Chunk)를 읽고 처리하는 방식입니다.

  • Chunk 단위로 트랜잭션을 수행하기 때문에 실패 시 해당 Chunk만 롤백됩니다.

  • 페이징 크기와 커밋 간격(Chunk Size)을 일치시키는 것이 권장됩니다.

  • 사용 예: 대량 데이터 변경 작업

중요 개념:

  • Job, Step: 작업의 최소 단위. 하나의 Job은 하나 이상의 Step으로 구성됩니다.

  • Chunk: 트랜잭션의 관리 단위.

  • reader/processor/writer: 데이터를 읽고/가공하고/저장하는 컴포넌트

Tasklet 기반

  • 단일 태스크를 수행하는 방식입니다. execute 메서드를 반복 호출하여 작업을 수행합니다.

  • 초기화, 저장 프로시저 실행, 알림 전송 등에서 사용됩니다.

  • 간단한 배치는 Tasklet으로 쉽게 구현되지만, 대량 처리는 복잡해질 수 있습니다.


cronicle 설명

cronicle은 웹 기반 프런트 엔드 UI를 갖춘 다중 서버 작업 스케줄러 및 실행기입니다. 실시간 통계 및 라이브 로그 뷰어를 통해 여러 슬레이브 서버를 대상으로 예약된 작업, 반복 작업 및 주문형 작업을 처리합니다.

기능 요약:

  • 단일 또는 다중 서버 설정

  • 백업 서버에 대한 자동 장애 조치

  • 근접 서버 자동 검색

  • 라이브 로그 뷰어

  • 다양한 시간대에 이벤트 예약

  • 이벤트 대기열 관리(옵션)

  • CPU 및 메모리 사용량 추적

  • 과거 통계 및 성능 그래프

  • 웹후크 지원

  • 이벤트 예약 및 실행을 위한 REST API

cronicle 이벤트 작성

로그인 후 Schedule 탭 하단의 Add Event를 통해 이벤트를 생성합니다.

주요 속성:

  • Event Name: 이벤트 이름

  • Category: 이벤트 카테고리

  • Plugin: 실행될 플러그인

  • Target: 실행 서버 대상

  • Timing: 실행 주기(일일, 시간별 등)

타이밍은 시각적 다중 선택기 위젯을 사용하여 다양한 날짜/시간 예약이 가능합니다. Crontab 설정을 사용하려면 [ Import… ] 링크를 통해 입력할 수 있습니다.


컨트롤러 작성

HTTP 요청을 통해 배치 Job을 기동하는 데 사용됩니다. 공통 Controller(BatchJobController)를 사용하면 별도 컨트롤러를 작성하지 않아도 됩니다. 별도의 기능이 필요한 경우에만 컨트롤러를 작성합니다.

클래스 어노테이션

클래스 레벨에 다음 어노테이션을 사용합니다.

어노테이션
설명

@RestController

REST 컨트롤러임을 표시 (@ResponseBody + @Controller 역할)

@RequestMapping

컨트롤러 클래스 수준의 공통 URI 지정

@Slf4j

lombok 로그 어노테이션

@RequiredArgsConstructor

lombok 생성자 주입 편의 어노테이션

예시:

매핑 URI 형식

@RequestMapping의 path 파라미터 형식: /batch/<mbod,gddp>/<resource명 복수형>/<배치Job명>

  • /batch/<mbod,gddp>: context-path로 지정 (프로그램에서 지정하지 않음)

  • resource명 복수형: 클래스 레벨 @RequestMapping에서 지정

  • 배치Job명: resource명을 Job명 앞에 붙이는 형식

예:

  • context-path: /batch/gddp

  • 클래스 레벨 RequestMapping: @RequestMapping("/categories")

  • 개별 매핑 예:

    • @GetMapping("/categoryRankPopularJob")

    • @GetMapping("/categoryRankPopularGoodsJob")

메소드 파라미터 어노테이션

어노테이션
설명

@PathVariable

JobName은 PathVariable 형식을 사용

@RequestParam

파라미터는 QueryString 또는 FormData 방식 사용

예시 시그니처:

기본 소스코드 (예시)

아래는 위 예시의 주요 단계들을 stepper로 정리한 내용입니다.

1

Job 멤버 선언 및 DI

  • Job을 클래스 멤버로 선언하고 의존성 주입(DI) 처리합니다.

2

중복 실행 허용 및 파라미터 준비

  • incrementer를 통해 중복 실행 관리.

  • JobParametersBuilder로 필요한 파라미터를 추가합니다.

3

Job 실행

  • JobLauncher.run(job, jobParameters)으로 Job을 실행합니다.

  • 실행 결과는 Spring Batch repository에서 확인합니다.

메소드 리턴값

컨트롤러의 반환값은 단순 String을 사용합니다. 호출 결과만 리턴하고, 상세 실행 결과는 Spring Batch repository에서 확인합니다.


Job Configuration 클래스 작성

Job Configuration 클래스는 Spring Batch에서 Job, Step, Reader/Writer/Processor 등의 Bean을 정의하는 클래스입니다.

요약:

  • Java 17 이상에서 지원

  • 기존의 StepBuilderFactory, JobBuilderFactory는 더 이상 권장되지 않음. 대신 JobRepository와 PlatformTransactionManager를 명시적으로 사용

  • @EnableBatchProcessing은 더 이상 사용하지 않아도 됨(권장하지 않음)

예시는 CompositeItemWriter 방식으로 작성되었습니다.

클래스 레벨 어노테이션

어노테이션
설명

@Configuration

Job, Step 등 Bean 선언용

@Slf4j

lombok 로그

@RequiredArgsConstructor

lombok 생성자 주입 편의

예시:

Job 생성 (예시)

설명:

  • 일반적으로 하나의 Step을 구성하고 필요시 nextStep을 추가

  • incrementer로 중복 실행 관리 가능

  • JobParametersValidator를 사용해 실행 파라미터 검증 가능

Step 생성 (Chunk 기반 예시)

  • reader: 데이터를 조회

  • processor: 필요시 데이터 가공(선택)

  • writer: 처리된 데이터를 저장(Insert/Update/Send 등)

  • chunk 및 transactionManager를 통해 트랜잭션 단위를 지정

Chunk 기반의 reader/processor/writer 예시:

Tasklet 기반의 Step 작성 예시:

Tasklet 구현 예시:


샘플 프로그램 목록

배치 프로젝트(gddp)의 샘플 패키지에 포함된 샘플 목록과 설명:

배치프로그램명
파일
설명

simpleComposItemWriterJob

SimpleJobConfig.java

CompositeItemWriter를 사용한 reader/writer 2단계 구성, processor 생략 샘플

sampleFileJob

SampleFileJobConfig.java

FlatFileItemReader를 이용한 CSV 파일 읽기 샘플

sampleCompositeWriterJob

SampleCompositeWriterJobConfig.java

CompositeItemWriter로 Insert/Update/Send 등의 복합 작업 처리 샘플

sampleMyBatisCursorJob

SampleMyBatisCursorJobConfig.java

MyBatis Cursor Reader와 MyBatis Batch Writer 사용 샘플 (ParameterConverter 포함)

sampleJdbcJob

SampleJdbcJob.java

JdbcCursorItemReaderBuilder와 JdbcBatchItemWriterBuilder 사용 샘플

sampleJdbcPagingJob

SampleJdbcPagingConfig.java

JdbcPagingItemReaderBuilder 사용 샘플

간단한 일부 샘플 설명:

simpleComposItemWriterJob

  • CompositeItemWriter를 사용하여 여러 writer를 Delegates로 구성.

sampleFileJob

  • FlatFileItemReader로 CSV 파일을 읽음.

sampleCompositeWriterJob

  • Processor를 포함하여 Input 타입(SampleRequest) → Output 타입(SampleResponse)으로 변환하는 샘플.

sampleMyBatisCursorJob

  • MyBatis Cursor Reader와 MyBatis Batch Writer 사용 예시:

sampleJdbcJob (JdbcCursor, JdbcBatch 예시)

  • JdbcCursorItemReaderBuilder 및 JdbcBatchItemWriterBuilder 사용. BoundSql에서 SQL을 가져와 PreparedStatementSetter 설정 등.

sampleJdbcPagingJob

  • JdbcPagingItemReaderBuilder와 SqlPagingQueryProviderFactoryBean을 이용한 페이징 처리 예시.


Spring Boot Batch 성능을 최적화하기 위한 Reader

Reader는 데이터를 효율적으로 읽어오고 처리 속도를 최적화하도록 구성해야 합니다. 아래는 주요 Reader 및 특징입니다.

  • JdbcPagingItemReader

    • 페이지별로 데이터를 읽어 메모리 사용 효율적

    • 뒤로 갈수록 성능 저하 발생 가능

  • JdbcCursorItemReader

    • 커서 기반으로 필요 시마다 데이터를 읽음

    • 메모리 효율적이며 대량 데이터 처리에 적합

  • MyBatisPagingItemReader

    • MyBatis를 사용한 페이징 Reader

  • MyBatisCursorItemReader

    • MyBatis와 커서 기반 통합 Reader

커스텀 Reader: QuerydslNoOffsetPagingItemReader

  • QueryDSL을 사용해 offset 없이 페이징(Zero-Offset) 처리

  • 장점: offset 성능 이슈 해결, 빠른 페이징

  • 단점: Spring Batch에서 공식 지원하지 않음, 복잡한 쿼리에는 비권장

예시(요약):


실제 예제와 테스트 (요약)

테스트 대상:

  • 데이터 총 건수: 200k, 700k, 1,000k 건

  • Chunk 크기: 1000 (모든 테스트에서 동일)

  • 테스트 환경: 12th Gen Intel Core i7-1260P / LPDDR5 16GB

  • 모든 ItemWriter는 동일하게 MyBatisBatchItemWriter 혹은 JdbcBatchItemWriter 사용

테스트 결과 요약(문서의 상세 표를 참조):

  • Tasklet 기반: 가장 빠른 성능을 보였으나 메모리 사용량이 가장 높음(OOM 가능성)

  • Chunk 기반: Tasklet보다 메모리 사용량 적음(Chunk 단위 트랜잭션)

  • MyBatisCursor / JdbcCursor: 초기 Cursor Open 비용 존재, 이후 좋은 처리 성능

  • JdbcPaging: 초반에는 빠르나 뒤로 갈수록 느려짐(Offset 증가 영향)

  • QuerydslNoOffset: 테스트에서 가장 좋은 성능을 보였음(조건에 따라 유리)

(원문 문서에 상세한 성능 표가 포함되어 있습니다.)


최종결론

권장 조합(요약):

Reader / Writer
내용

MyBatisCursorItemReader / MybatisBatchItemWriter

일반 환경에서는 MyBatis Cursor가 빠름. 저장은 MybatisBatchItemWriter로 Batch Insert/Update 권장.

MyBatisPagingItemReader / MybatisBatchItemWriter

페이징을 항상 첫 페이지(offset 0)만 조회하도록 구성할 수 있다면 메모리 사용 적고 빠름(비즈니스 로직에 따라 유용).

QueryDslZeroOffsetItemReader / MybatisBatchItemWriter

단일 테이블, PK가 시퀀스 형태인 경우 QueryDSL 기반 Zero-Offset Reader가 매우 우수한 성능을 보임. 단점은 쿼리를 QueryDSL로 변경해야 함.

마지막 업데이트