예제코드
github.com/AcornPublishing/definitive-spring-batch
배치 아키텍처
- 애플리케이션 레이어: 개발자가 작성한 코드. 대부분 코어 레이어와 상호작용한다.
- 코어 레이어: 배치 영역을 구성하는 실제적인 컴포넌트들(Job, Step, JobLauncher, JobParameters)
- 인프라스트럭쳐 레이어: ItemReader, ItemWriter, Repeat
Job과 Step
- Job은 상태를 수집하고, 이전 상태에서 다음 상태로 전환된다. State Machine. 가장 일반적인 상태의 형태는 Step이다.
- Step은 Job을 구성하는 작업 단위이다.
- Step의 유형
- Tasklet 기반 Step
- 구조 간단
- Tasklet interface를 구현한다.
- Step이 중지될 때 까지 execute 메소드가 반복적으로 수행된다. execute를 호출할 때 마다 독립적인 트랜잭션이 시작된다.
- 용도: 초기화, 저장 프로시저 실행, 알림 전송 등
- Chunk 기반 Step
- 약간 더 복잡
- 아이템 기반의 처리에 사용
- ItemReader, ItemProcessor, ItemWriter라는 3개의 주요 부분으로 구성될 수 있다. ItemProcessor는 필수가 아니다.
- Tasklet 기반 Step
[표] 배치 잡을 구성하는 인터페이스
인터페이스 | 설명 |
org.springframework.batch.core.Job | ApplicationContext 내에 구성되는 잡 객체 |
org.springframework.batch.core.Step | ApplicationContext 내에 구성되는 스텝을 나타내는 객체 |
org.springframework.batch.core.step.tasklet.Tasklet | 트랜잭션 내에서 로직이 실행될 수 있는 기능을 제공하는 전략 인터페이스 |
org.springframework.batch.item.ItemReader<T> | 스텝 내에서 입력을 제공하는 전략 인터페이스 |
org.springframework.batch.item.ItemProcessor<T> | 스텝 내에서 제공받은 개별 item에 업무 로직, 검증 등을 적용하는 역할을 하는 인터페이스 |
org.springframework.batch.item.ItemWriter<T> | 스텝 내에서 아이템을 저장하는 전략 인터페이스 |
Job 실행
JobRepository
- 스프링 배치 내의 대부분의 주요 컴포넌트에서 공유된다.
- 배치 수행과 관련된 수치데이터(시작/종료 시각, 상태, 일기/쓰기 횟수 등)와 Job의 상태를 유지 관리한다.
JobLauncher
- 잡을 실행하는 역할을 한다 - Job.execute 메소드 호출
- 잡의 재실행 가능 여부를 판단한다 - 모든 잡이 재시작 가능한 것은 아님
- 잡의 실행하는 방법을 결정한다 - 현재 스레드에서 수행할지, 스레트 풀을 사용해서 실행할지 등
- 파라미터의 유효성을 검증한다.
- 스프링 부트에서는 잡을 실행할 수 있는 기능을 제공하므로 직접 다룰 필요는 없다.
Job의 실행
- 각 스텝을 실행한다.
- 각 스텝이 실행되면 JobRepository는 현재 상태를 기록한다 - 실행된 스텝, 현재 상태, 읽은 아이템 수, 처리된 아이템 수 등
- Step의 실행
- 청크의 처리가 스텝 내에서 완료될 때 JobRepository 내에 있는 JobExecution 또는 StepExecution을 현재 상태로 갱신한다 - 현재 까지의 커밋 수, 시작 및 종료 시각 등
JobInstance
- 잡의 논리적인 실행
- 식별: 잡의 이름 + 잡 파라미터의 조합
JobExecution
- 잡의 실제 실행 - 잡을 구동할 때마다 새로운 JobExecution
- 실패한 잡을 동일한 파라미터로 실행하면 JobInstance는 기존과 동일하고 JobExecution은 새로운 인스턴스가 생성된다.
StepExecution
- 스텝의 실제 실행
- JobExecution은 1개 이상의 StepExecution과 연관된다.
병렬화
잡을 병렬화하는 방법에는 다음 다섯 가지가 있다:
- 멀티 스레드 스텝
- 전체 스텝의 병렬 실행
- 비동기 ItemProcessor/ItemWriter의 구성
- 원격 청킹
- 파티셔닝
멀티 스레드 스텝 (Multithreaded Steps)
- 스프링 배치에서 잡은 일감을 청크라는 블록 단위로 처리되도록 구성되며, 각 청크는 독립적인 트랜잭션으로 처리된다.
- 각 청크를 서로 다른 스레드를 사용하여 처리하면 처리량을 이론상 선형적으로 증가시킬 수 있다.
병렬 스텝 (Parallel Steps)
- 디펜던시가 없는 스텝을 병렬로 실행할 수 있다.
비동기 ItemProcessor/ItemWriter
- 스텝 내의 ItemProcessor가 느려서 병목이 발생하는 경우(복잡한 계산 or 원격 서비스 호출 등) 이런 단계를 병렬화할 수 있다.
- AsynchronousItemProcessor는 자신이 가지고 있는 스레드를 사용하여 ItemProcessor가 실행되도록 해 주는 데코레이터이다. ItemProcessor 호출결과를 반환하는 대신 각 호출에 대해 Future를 반환한다.
- 현재 청크 내에서 반환된 Future 목록은 AsynchromousItemWriter로 전달된다.
- AsynchronousItemWriter는 Future를 이용해 실제 결과를 얻어내어 지정된 ItemWriter에 위임한다.
리모트 청킹
- 마스터 노드에서 표준 ItemReader를 사용해서 input이 생성된다.
- input은 신뢰성 있는 통신(메시지 브로커)을 사용하여 리모트 워커 ItemProcessor로 전송된다.
- 리모트 워커인 ItemProcessor는 메시지 기반의 POJO를 처리한 후 처리결과를 마스터 노드로 보내서 기록되게 하거나 자신이 직접 기록한다.
- 네트워크 사용량이 많아질 수 있다 - 마스터에서 데이터를 읽은 후 리모트로 전송하고, 리모트 워커가 처리한 다음 다시 마스터로 전송하므로
- 리모트에서 처리하는 비용에 비해 I/O가 적은 시나리오에 적합하다.
파티셔닝
- 스프링 배치는 리모트 파티셔닝(마스터와 리모트 워커를 사용)과 로컬 파티셔닝(워커의 멀티 스레드를 사용)을 모두 지원한다.
- 리모트 청킹과 원격 파티셔닝의 차이는 내구성 있는 통신 방법이 필요하지 않으며, 마스터 노드는 워커 스텝들의 묶음에 대한 컨트롤러 역할만 한다는 것이다.
- 각 워커 스텝은 독립적으로 동작하며, 로컬에 배포된 것과 동일하게 구성된다. 유일한 차이점은 워커 스텝이 잡이 아니라 마스터노드에서 일감을 전달받는다는 것이다.
- 모든 워커가 일감을 완료하면 마스터 스텝이 완료된 것으로 간주된다.
프로젝트 초기 설정
스프링 배치 내려받기
- Spring Initializer 사용
- Spring Boot Version: 2.4.x
- Dependencies: Batch, H2, JDBC, lombok
- Java 8
HelloWorldApplication
@Slf4j
@RequiredArgsConstructor
@EnableBatchProcessing
@SpringBootApplication
public class HelloWorldApplication {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Bean
public Step step() {
return stepBuilderFactory.get("step1")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) throws Exception {
log.info("Hello, World!");
return RepeatStatus.FINISHED;
}
})
.build();
}
@Bean
public Job job() {
return jobBuilderFactory.get("job")
.start(step())
.build();
}
public static void main(String[] args) {
SpringApplication.run(HelloWorldApplication.class, args);
}
}
- @EnableBatchProcessing
- 배치 인프라스트럭처를 부트스트랩한다.
- 대부분의 배치 인프라스트럭처를 스프링 빈으로 제공하므로 개발자는 다음 컴포넌트를 bean으로 정의할 필요가 없다.
- JobRepository: 잡의 상태를 기록
- JobLauncher: 잡을 구동
- JobExplorer: JobRepository를 사용해 읽기 전용 작업을 수행
- JobRegistry: 특정한 런처 구현체를 사용할 때 잡을 찾는 용도
- PlatformTransactionManager: 잡 진행 과정에서 트랜잭션을 다루는데 사용
- JobBuilderFactory: 잡을 생성하는 빌더
- StepBuilderFactory: 스텝을 생성하는 빌더
- JobRepository와 PlatformTransactionManager는 필요시 데이터소스를 사용한다.
- 스프링 배치는 구동시에 클래스패스에 H2가 있는지 감지해서 내장(embedded) 데이터소스를 생성한다.
- @SpringBootApplication은 @ComponentScan과 @EnableAutoConfiguration을 결합한 메타 애너테이션이다.
- JobBuilderFactory와 StepBuilderFactory의 인스턴스가 DI된다. @EnableBatchProcessing을 적용하면 자동으로 제공된다.
- 스텝을 bean으로 생성한다.
- StepBuilderFactory를 사용한다.
- 스텝 이름과 태스크릿을 지정한다.
- 태스크릿은 실제 처리를 수행한다.
- 처리를 완료한 후에는 RepeatStatus.FINISHED를 반환한다.
- RepeatStatus.FINISHED를 반환하면 태스크릿이 완료됐다는 것을 의미하며 태스크릿이 종료된다.
- RepeatStatus.CONTINUABLE을 반환하면 스프링 배치는 태스크릿을 다시 호출한다.
- Job을 bean으로 생성한다.
- JobBuilderFactory를 사용한다.
- 잡 이름과 시작할 스텝을 지정한다.
잡 실행하기
- 기본적으로 스프링 부트는 기동시에 ApplicationContext 내에서 찾은 모든 잡을 실행한다.
- 스프링 부트의 JobLauncherCommandLine 컴포넌트는 스프링 배치가 사용되는 경우 기동시 로딩되며, JobLauncher를 사용해 ApplicationContext에서 찾은 모든 잡을 실행한다.
o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=job]] launched with the following parameters: [{}]
o.s.batch.core.job.SimpleStepHandler : Executing step: [step1]
my.batch.HelloWorldApplication : Hello, World!
o.s.batch.core.step.AbstractStep : Step: [step1] executed in 10ms
o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=job]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 22ms
'잡다구리' 카테고리의 다른 글
Redis Cluster 구성 테스트 (0) | 2022.08.12 |
---|---|
redis docker (0) | 2021.08.24 |
날짜와 시간 (0) | 2021.07.31 |
스프링 배치 완벽 가이드 - 6. 잡 실행하기 (0) | 2021.05.09 |
스프링 배치 완벽 가이드 - 5. JobRepository와 메타데이터 (0) | 2021.05.06 |
스프링 배치 완벽 가이드 - 4. 잡과 스텝 이해하기 (0) | 2021.05.02 |
스프링 배치 완벽 가이드 - 3. 예제 잡 애플리케이션 (0) | 2021.05.02 |
7장 마이크로서비스 쿼리 구현 (Implementing queries in a microservice architecture) (0) | 2021.04.25 |
댓글