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로 정리한 내용입니다.
메소드 리턴값
컨트롤러의 반환값은 단순 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: 테스트에서 가장 좋은 성능을 보였음(조건에 따라 유리)
(원문 문서에 상세한 성능 표가 포함되어 있습니다.)
최종결론
권장 조합(요약):
MyBatisCursorItemReader / MybatisBatchItemWriter
일반 환경에서는 MyBatis Cursor가 빠름. 저장은 MybatisBatchItemWriter로 Batch Insert/Update 권장.
MyBatisPagingItemReader / MybatisBatchItemWriter
페이징을 항상 첫 페이지(offset 0)만 조회하도록 구성할 수 있다면 메모리 사용 적고 빠름(비즈니스 로직에 따라 유용).
QueryDslZeroOffsetItemReader / MybatisBatchItemWriter
단일 테이블, PK가 시퀀스 형태인 경우 QueryDSL 기반 Zero-Offset Reader가 매우 우수한 성능을 보임. 단점은 쿼리를 QueryDSL로 변경해야 함.
마지막 업데이트