Job
- 배치 계층 구조에 최상위 개념으로 하나의 배치 작업 자체를 의미
- ex) "elasticsearch에 저장된 로그를 RDB로 옮기는 배치" -> Job
- 배치 작업을 어떻게 구성하고 실행할 것인지 전체적으로 설정하고 명세해 놓은 객체
- 반드시 한 개 이상의 Step을 구성
- Spring Batch가 기본 구현체 제공
- SimpleJob
- FlowJob
JobInstance
- Job이 실행될 때 생성되는 Job의 논리적 실행 단위 (실행되는 시점)
- 하루에 한 번씩 배치 Job이 실행될 경우 매일 실행되는 각각의 Job을 JobInstance로 표현
- 따라서, Job과 JobInstance는 1:N 관계
- JobInstance 생성 및 실행 기준
- Job과 JobParameter 조합이 신규일 경우 새로운 JobInstance 생성
- 이전과 동일한 Job과 JobParameter 조합일 경우 기존에 생성된 JobInstance 반환
- 이때 JobParameter는 해싱을 통해 JobKey로 변환되어 spring-batch-core 라이브러리에서 생성해 주는 BATCH_JOB_INSTANCE 테이블에 저장됨
- 따라서, JOB_NAME과 JOB_KEY 칼럼의 조합을 기준으로 JobInstance 생성할지 판단
JobParameters
- Job을 실행할 때 함께 포함되어 사용되는 파라미터를 가진 도메인 객체이며 JobInstance와 1:1 관계
- 하나의 Job에 존재할 수 있는 다수의 JobInstance를 구분하기 위한 파라미터
- 코드 단에서는 JobParameterBuilder를 통해 생성 가능
- 어플리케이션 실행 시 주입하여 SpEL 문법을 이용할 수 있음
- spring-batch-core 라이브러리에서 생성해 주는 BATCH_JOB_EXECUTION_PARAMS 테이블에 저장
JobExecution
- JobInstance에 대한 한번의 시도를 의미하는 객체로서 Job 실행 중에 발생한 정보들을 저장하고 있는 객체
- ex) 배치 시작 시간, 종료 시간, 종료 상태 등등
- JobExecution은 "COMPLETED", "FAILED"와 같은 Job의 실행 결과 상태를 가지고 있음
- JobExecution의 실행 상태 결과가 COMPLETED일 경우 JobInstance 실행이 완료된 것으로 간주하여 재 실행 불가
- JobInstanceAlreadyCompleteException 예외 발생
- JobExecution의 실행 상태 결과가 FAILED일 경우 JobInstance 실행이 완료되지 않다고 판단하여 재 실행 가능
- JobParameter가 동일한 Job 즉, 같은 JobInstance여도 재 실행 가능
- 따라서, COMPLETED가 될 때까지 하나의 JobInstance 내 여러 JobExecution이 생성 가능 (1:N 관계)
- spring-batch-core 라이브러리에서 생성해 주는 BATCH_JOB_EXECUTIO 테이블에 저장
Step
- Job을 구성하는 독립적인 하나의 단계
- 배치 작업을 어떻게 구성하고 실행할 것인지에 관한 Job의 세부 작업을 Task 기반으로 설정하고 명세한 객체
- 앞서 언급했듯이 모든 Job은 최소 하나 이상의 step으로 구성
- Spring Batch가 기본 구현체 제공
- TaskletStep
- PartitionStep
- JobStep
- FlowStep
StepExecution
- JobExecution과 유사한 객체로 Step 실행 중에 발생한 정보들을 저장하고 있는 객체
- 시작 시간, 종료 시간, 상태, commit count, rollback count 등의 속성을 지님
- Step이 시도될 때마다 생성되므로 Step과 StepExecution은 1:N 관계
- 각 StepExecution은 하나의 JobExecution을 부모로 가짐
- 정리하자면 Job : JobExecution = 1 : N, JobExecution : StepExecution = 1 : N
- Job이 FAILED 처리됨에 따라 재시작되더라도 이미 성공한 Step은 skip이 되고 실패한 Step만 재 실행
- 이전 단계 Step이 실패함에 따라 현재 Step이 실행되지 않았다면 현재 step에 대한 StepExecution은 생성 X
- Job 내 Step들의 StepExecution이 하나라도 실패할 경우 JobExecution은 실패 처리
- spring-batch-core 라이브러리에서 생성해주는 BATCH_STEP_EXECUTION 테이블에 저장
StepContribution
- Chunk 프로세스의 변경 사항을 버퍼링 후 StepExecution 상태를 업데이트하는 도메인 객체
- ExitStatus의 기본 종료코드 외 사용자 정의 종료코드를 생성해서 저장 가능
ExecutionContext
- Map 객체와 같은 key-value 컬렉션으로 JobExecution 혹은 StepExecution 객체의 상태를 저장하는 공유 객체
- ConcurrentHashMap
- spring-batch-core 라이브러리에서 생성해주는 BATCH_JOB_EXECUTION_CONTEXT, BATCH_STEP_EXECUTION_CONTEXT 테이블에 저장
- 공유 범위
- Job 범위 - 각 Job의 JobExecution에 저장되며 Job 간에는 공유가 안되지만 해당 Job의 Step 간에는 서로 공유 됨
- Process 내 Thread끼리 힙 메모리 공유하는 것과 비슷한 개념?
- Step 범위 - 각 Step의 StepExecution에 저장되며 Step마다 독립적, Step 간 공유 안됨
- Job 범위 - 각 Job의 JobExecution에 저장되며 Job 간에는 공유가 안되지만 해당 Job의 Step 간에는 서로 공유 됨
- 실패한 Job에 대해 재 실행 시 이미 처리한 Row 데이터는 건너뛰고 처리하지 않은 Row를 수행할 때 상태 정보를 활용
JobRepository
- 배치 작업 중의 정보를 저장하는 저장소
- 배치 작업의 수행과 관련된 모든 메타데이터를 저장
- JobLauncher, Job, Step 구현체 내부에서 CRUD 기능을 처리
JobRepository 설정
- @SpringBootApplication 어노테이션이 선언된 클래스에 @EnableBatchProcessing 어노테이션만 선언하면 JobRepository가 자동으로 Bean으로 생성됨
- BatchConfigurer 인터페이스를 직접 구현 혹은 BasicBatchConfigurer를 상속해서 JobRepository 설정 커스터마이징 가능
- JDBC 방식으로 설정 - JobRepositoryFactoryBean
- In Memory 방식으로 설정 - MapJobRepositoryFactoryBean
- JobRepositoryFactoryBean
- 내부적으로 AOP 기술을 통해 트랜잭션 처리
- 트랜잭션 isolation의 default 값은 SERIALIZABLE로 최고 수준
- 일반적인 서비스에서는 성능 저하 요인이나 배치의 경우 동시 접근이 이루어지는 케이스가 적기 때문에 괜찮음
- READ_COMMITED, REPEATABLE_READ로 변경 가능
- 메타 테이블의 Table Prefix를 BATCH_에서 다른 값으로 변경 가능
- MapJobRepositoryFactoryBean
- PoC 개발과 같이 빠른 개발이 필요할 때 사용
- 굳이 DB에 저장하고 싶지 않을 경우에 사용
예시 코드
* factory.getObject를 반환하면 Proxy 객체가 생성되며 이를 통해 AOP 기술 적용 가능
JobRepository 설정을 위와 같이 변경 후 JobRepositoryListener를 생성한 뒤 JobBuilderFactory에 listener를 지정하면 변경된 설정이 적용됩니다.
JobLauncher
- 배치 작업을 실행시키는 역할
- Job과 JobParameters를 매개변수로 받으며 요청된 배치 작업을 수행한 후 최종 client에게 JobExecution 반환
- SpringBoot Batch에서는 JobLauncherApplicationRunner가 자동적으로 JobLauncher를 실행
- 동기적 실행 (sync)
- taskExecutor를 default 값인 SyncTaskExecutor로 설정할 경우
- JobExecution을 획득하고 배치 처리를 최종 완료한 이후 Client에게 JobExecution을 반환
- 배치 처리 시간이 길어도 상관없는 Scheduler에 의한 배치 처리에 적합
- 비동기적 실행 (async)
- taskExecutor를 SimpleAsyncTaskExecutor로 설정할 경우
- JobExecution을 획득한 후 Client에게 바로 JobExecution을 반환하고 배치처리 완료 (JobExecution EXIT_CODE 칼럼이 처리 중에는 UNKNOWN)
- 배치 처리 시간이 길 경우 response가 늦어지지 않아야 하는 HTTP 요청에 의한 배치 처리에 적합
예시 코드
실행한 job 내 step에서 5초 정도 걸리는 로직이 수행된다고 가정하고 Thread.sleep(5000); 추가한 뒤 동기 api와 비동기 api를 호출하면 확연한 차이를 보입니다.
동기 api의 경우 5초 뒤에 응답이 오고 비동기 api의 경우 응답은 바로 오지만 JobExecution 테이블 내 EXIT_CODE가 UNKNOWN이였다가 5초 뒤 COMPLETED로 바뀌는 것을 확인할 수 있습니다.
비고
spring-batch-core에서 생성해주는 테이블 DDL은 아래 경로에서 확인 가능합니다.
spring-batch-core jar 파일 > org.springframework.batch.core > *.sql
저는 MySQL을 사용하고 있으므로 schema-mysql.sql을 사용하였고 DDL은 아래와 같습니다.
보다 자세한 내용은 아래 블로그를 참고하시는 것을 추천드립니다!
참고
스프링 배치 - Spring Boot 기반으로 개발하는 Spring Batch (정수원 강사님)
반응형
'Spring' 카테고리의 다른 글
[Spring Batch] TaskletStep 아키텍처 (0) | 2023.07.11 |
---|---|
[Spring Batch] SimpleJob 아키텍처 (0) | 2023.07.10 |
[Spring] 트랜잭션 전파 정리 (0) | 2023.04.30 |
[Spring] @Transactional 적용 시 주의 사항 (0) | 2023.04.18 |
@Transactional 동작 원리 (0) | 2023.03.29 |