지난번 Devocean OpenLab Kotlin SpringBoot 스터디에 이어서 이번엔 Spring Batch 스터디를 시작하게 되었다. 이번엔 멘토님이신 KIDO 님의 DEVOCEAN 연재글을 보면서 직접 실습, 글 정리하고 매주 화요일마다 랜덤으로 발표한다.
[SpringBatch 연재 01] SpringBatch 빠르게 시작하기
깃허브 : https://github.com/kchabin/spring-batch/tree/main
Batch : 정해진 시간에 대량의 데이터를 일괄적으로 처리하는 방식
일반적인 배치 프로그램의 사용 시나리오
- 데이터베이스, 파일 또는 큐에서 대량의 레코드를 읽는다
- 어떤 방식으로든 데이터를 처리한다.
- 수정된 형태로 데이터를 다시 작성한다.
배치 애플리케이션 충족 조건
대용량 데이터 : 대량의 데이터를 가져오거나, 전달하거나, 계산하는 등의 처리를 할 수 있어야 한다.
자동화 : 심각한 문제해결을 제외하고 사용자의 개입없이 실행되어야 한다.
견고성 : 잘못된 데이터를 충돌 or 중단 없이 처리할 수 있어야 한다.
신뢰성 : 무엇이 잘못되었는지를 추적할 수 있어야 한다. -> 로깅, 알림
성능 : 지정한 시간 안에 처리를 완료하거나 동시에 실행되는 다른 애플리케이션을 방해하지 않아야 한다.
실패 복구 : 처리 중 실패가 발생하면, 실패 지점부터 재시작할 수 있어야 한다. -> batch와 schedule의 차이
Spring Batch는 이러한 기본 batch 반복을 자동화하여 오프라인 환경에서 유사한 트랜잭션을 세트로 처리하는 기능을 제공한다.
- 주기적으로 일괄 처리 수행
- 동시 일괄 처리 : 작업의 병렬 처리
- 단계적 엔터프라이즈 메시지 중심 처리
- 대규모 병렬 일괄 처리
- 실패 후 수동 또는 예약된 재시작
- 종속 단계의 순차적 처리(워크플로 기반 배치로 확장 가능)
- 부분 처리 : 레코드 건너 뛰기(ex: 롤백 시)
- 전체 배치 트랜잭션 (배치 크기가 작거나 기존 저장 프로시저 또는 스크립트가 있는 경우)
- JobLauncher : Job을 실행시키는 컴포넌트
- JobRepository : Job 실행과 Job, Step 저장
- Job : 하나의 배치 실행 단위. 하나 또는 그 이상의 Step으로 구성됨.
- JobInstance : 논리적인 Job 실행을 의미함. 주로 Job에 파라미터를 부여해 다른 JobInstance와 구분할 수 있다.
- Step
- 배치 작업의 독립적이고 순차적인 단계를 캡슐화하는 도메인 객체
- ItemReader, ItemProcessor, ItemWriter는 데이터를 일괄 처리하고 씀
프로젝트 구성
Project : Gradle-Groovy
Language : Java
Spring Boot : 3.2.2
Dependencies : Spring Batch
Packaging : Jar
Java : 17
build.gradle 설정
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.4'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'org.kchabin'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-batch'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.batch:spring-batch-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
//h2
implementation 'com.h2database:h2:2.2.224'
}
tasks.named('test') {
useJUnitPlatform()
}
gradle: bootRun
터미널에서 gradle: bootRun
명령을 실행하면 Failed to start가 뜬다.
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
APPLICATION FAILED TO START
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
FAILURE: Build failed with an exception.
DataSource를 찾지 못해서 실패했고, H2, HSQL 혹은 Derby 중 하나를 설정하라고 한다.
H2 Database
- 특징
- 메모리 데이터베이스 : 주로 테스트 및 개발 전용, 메모리에 데이터 저장
- 경량, 빠른 속도 : 경량의 DB로 높은 성능을 보여줌
- 자체 웹 콘솔 제공 : 웹 기반 콘솔을 통해 DB 관리 가능함.
HSQL
경량 데이터베이스
- 자바기반
- 100% 자바 개발
- Java 애플리케이션의 내장 데이터베이스로 사용 가능
- SQL-92 호환
- 표준 SQL 문법 지원
Apache Derby
- 자바 기반 데이터베이스
- 네트워크 및 임베디드(내장) 모드
- 트랜잭션 지원
- ACID 제공
이중 H2 데이터베이스를 사용한다.
- application.yaml 파일 작성
- 의존성 추가
implementation 'com.h2database:h2:2.2.224'
h2 데이터베이스 연결 후 다시 gradle: bootRun을 실행하면 이번엔 성공적으로 빌드되는 것을 확인할 수 있다.
스프링배치 스키마 구조
- 스프링 배치를 수행하면 자동으로 배치를 위한 스키마가 생성된다.
Job 관련 테이블
BATCH_JOB_INSTANCE Table
- 스키마 중 가장 기본이 되는 테이블
- 배치가 수행되면 Job이 생성되는데, 이때 해당 Job instance에 대해 관련된 모든 정보를 가진 최상위 테이블이다.
CREATE TABLE BATCH_JOB_INSTANCE ( JOB_INSTANCE_ID BIGINT PRIMARY KEY , VERSION BIGINT, JOB_NAME VARCHAR(100) NOT NULL, JOB_KEY VARCHAR(32) NOT NULL );
JOB_INSTANCE_ID
: 인스턴스에 대한 unique ID. JobInstance 객체의 getID로 획득할 수 있다.VERSION
: 버전 정보JOB_NAME
: batch job instance로 획득한 job의 이름. 인스턴스를 식별하기 위해 필요한 값이며 null이 될 수 없다.JOB_KEY
: JobParameter를 직렬화한 데이터값이며, 동일한 job을 다른 job과 구분하는 값. 이 JobParameter는 동일할 수 없으며,JOB_KEY
는 구별될 수 있도록 달라야한다.
BATCH_JOB_EXECUTION_PARAMS Table
- JobParameter에 대한 정보를 저장하는 테이블.
- 하나 이상의 key-value 쌍으로 Job에 전달되며, Job이 실행될 때 전달된 파라미터 정보를 전달한다.
- 각 파라미터는
IDENTIFYING
이true
로 설정되면, JobParameter 생성 시 유니크한 값으로 사용된 경우를 의미한다. - 비정규화된 테이블의 구조는 다음과 같다.
CREATE TABLE BATCH_JOB_EXECUTION_PARAMS (
JOB_EXECUTION_ID BIGINT NOT NULL ,
PARAMETER_NAME VARCHAR(100) NOT NULL ,
PARAMETER_TYPE VARCHAR(100) NOT NULL ,
PARAMETER_VALUE VARCHAR(2500) ,
IDENTIFYING CHAR(1) NOT NULL ,
constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
);
JOB\_EXECUTION\_ID
: BATCH_JOB_EXECUTION으로부터 온 외래키. job 실행 아이디. 각 실행마다 여러 행(키/값)이 저장된다.PARAMETER\_NAME
: 파라미터 이름PARAMETER\_VALUE
: 파라미터 값PARAMETER\_TYPE
: 파라미터의 타입IDENTIFYING
: 유니크한 값이면 true- 기본키가 없는 테이블
BATCH_JOB_EXECUTION Table
- JobExecution과 관련된 모든 정보를 저장한다.
- Job실행될 때마다 JobExecution 객체가 만들어지고 이 테이블의 row 수가 증가한다..
- 다음은 테이블 구조이다.
CREATE TABLE BATCH_JOB_EXECUTION (
JOB_EXECUTION_ID BIGINT PRIMARY KEY ,
VERSION BIGINT,
JOB_INSTANCE_ID BIGINT NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP DEFAULT NULL,
END_TIME TIMESTAMP DEFAULT NULL,
STATUS VARCHAR(10),
EXIT_CODE VARCHAR(20),
EXIT_MESSAGE VARCHAR(2500),
LAST_UPDATED TIMESTAMP,
constraint JOB_INSTANCE_EXECUTION_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ;
JOB\_EXECUTION\_ID
: 배치자 실행 아이디, 실행을 유니크하게 구분할 수 있다. 칼럼의 값은 JobExecution 의 getId메소드로 획득이 가능하다.VERSION
: 버전 정보JOB\_INSTANCE\_ID
: 배치 잡 인스턴스 테이블의 기본키. 하나의 인스턴스에 여러 개의 execution이 있을 수 있다.CREATE_TIME
: execution이 생성된 시간START_TIME
: execution이 시작된 시간.END_TIME
: execution이 종료된 시간. 성공여부 상관없이 남게됨.- 현재 Job이 실행 중이지 않은데, 해당 열의 값이 비어있다면 특정 유형의 오류가 발생했다는 뜻.
- 프레임워크가 실패하기 전 마지막 저장을 수행할 수 없음을 나타냄.
STATUS
: execution의 현재 상태를 문자열로 나타냄. COMPLETED, STARTED 및 기타 -> BatchStatus 나열값EXIT_CODE
: execution의 종료 코드를 문자열로 나타낸다.- 커맨드라인 잡 -> 숫자
EXIT_MESSAGE
: job이 어떻게 종료되었는지를 나타낸다. 가능하다면 stack trace값이 남게 된다.LAST_UPDATED
: execution이 마지막으로 지속된 시간을 나타내는 타임스탬프.
BATCH_JOB_EXECUTION_CONTEXT Table
- Job의 ExecutionContext 에 대한 모든 정보를 저장한다.
- JobExecution마다 정확히 하나의 JobExecutionContext를 가진다. 여기에는 특정 작업 실행에 필요한 모든 작업 수준 데이터가 포함되어 있다.
- 이 데이터는 일반적으로 실패 후 중단된 부분부터 시작될 수 있도록 실패후 검색해야하는 상태를 나타낸다.
CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT (
JOB_EXECUTION_ID BIGINT PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT CLOB,
constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;
- JOB_EXECUTION_ID: job execution 테이블에 대한 아이디. 여기에는 주어진 execution마다 여러개의 row가 쌓인다.
- SHORT_CONTEXT: SERIALIZED_CONTEXT 의 문자 ver
- SERIALIZED_CONTEXT: 직렬화된 전체 컨텍스트이다.
Step 관련 테이블
BATCH_STEP_EXECUTION Table
- BATCH_STEP_EXECUTION Table 은 StepExecution과 관련된 모든 정보를 가진다.
- BATCH_JOB_EXECUTION 테이블과 유사하며 생성된 각 JobExecution에 대한 단계당 항목이 항상 하나 이상이 존재한다.
CREATE TABLE BATCH_STEP_EXECUTION (
STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,
VERSION BIGINT NOT NULL,
STEP_NAME VARCHAR(100) NOT NULL,
JOB_EXECUTION_ID BIGINT NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP DEFAULT NULL ,
END_TIME TIMESTAMP DEFAULT NULL,
STATUS VARCHAR(10),
COMMIT_COUNT BIGINT ,
READ_COUNT BIGINT ,
FILTER_COUNT BIGINT ,
WRITE_COUNT BIGINT ,
READ_SKIP_COUNT BIGINT ,
WRITE_SKIP_COUNT BIGINT ,
PROCESS_SKIP_COUNT BIGINT ,
ROLLBACK_COUNT BIGINT ,
EXIT_CODE VARCHAR(20) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED TIMESTAMP,
constraint JOB_EXECUTION_STEP_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ;
STEP_EXECUTION_ID
: execution에 대해 유니크한 아이디. 이 칼럼은 StepExecution 객체의 getId를 통해 조회가 가능하다.VERSION
: 버전정보- STEP_NAME: execution이 귀속된 스텝의 이름이다.
JOB_EXECUTION_ID
: BATCH_JOB_EXECUTION 테이블에 대한 외래키. 이는 JobExecution에 StepExecution이 속한다. JobExecution에 대해 Step 이름은 유니크해야한다.START_TIME
: execution이 시작된 시간.END_TIME
: execution이 종료된 시간. 현재 수행하지 않는데 이 값이 비어있다면 에러가 발생했거나, 실패하기 전에 마지막 실패전 작업이 저장되지 않았음을 의미한다.STATUS
: execution의 상태를 표현한다. COMPLETED, STARTED 와 기타 정보가 된다. 이는 BatchStatus 에 대한 나열값으로 표현할 수 있다.COMMIT_COUNT
: execution동안 트랜잭션 커밋된 카운트를 나열한다.READ_COUNT
: 이 실행된 동안 읽어들인 아이템 수FILTER_COUNT
: 이 실행동안 필터된 아이템수WRITE_COUNT
: 이 실행동안 쓰기된 아이템수READ_SKIP_COUNT
: 이 실행동안 읽기시 스킵된 아이템수WRITE_SKIP_COUNT
: 이 실행동안 쓰기가 스킵된 아이템수PROCESS_SKIP_COUNT
: 이 실행의 프로세싱 동안 스킵된 아이템의 수ROLLBACK_COUNT
: 이 실행동안 롤백된 아이템수, 재시도를 위한 롤백과 복구 프로시저에서 발생한 건을 저장한다.EXIT_CODE
: 이 실행동안 종료된 문자열이다. 커맨드라인 잡이라면 이 값은 숫자로 변환된다.EXIT_MESSAGE
: job이 종류되는 경우 어떻게 종료되었는지를 나타낸다. 가능하다면 stack trace값이 남게 된다.LAST_UPDATED
: execution이 마지막으로 지속된 시간을 나타내는 타임스탬프이다.
BATCH_STEP_EXECUTION_CONTEXT Table
- Step의 ExecutionContext와 관련된 모든 정보를 가지는 테이블
- StepExecution 마다 정확히 하나의 ExecutionContext 이 있다. 그리고 특정 step execution 에 대해서 저장될 필요가 있는 모든 데이터가 저장된다.
- JobInstance가 중단된 위치에서 시작 할 수 있도록 실패 후 검색해야 하는 상태를 나타낸다.
CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT (
STEP_EXECUTION_ID BIGINT PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT CLOB,
constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
) ;
- STEP_EXECUTION_ID: StepExecution의 키로 외래키. 여기에는 주어진 execution에 연관된 모든 row가 존재한다.
- SHORT_CONTEXT: SERIALIZED_CONTEXT 의 string 버전
- SERIALIZED_CONTEXT: 직렬화된 전테 컨텍스트이다.
Archiving
- 프레임워크는 metadata 테이블을 사용해서 특정 JobInstance가 전에 어떻게 실행되었는지를 결정한다. Job이 재실행이 불가능하면, 예외를 던진다.
- JobInstance의 엔트리가 성공적으로 완료되지 못하고 지워진 경우 프레임워크는 해당 job이 재시작이 아닌 새로운 작업이라고 생각한다.
- 만약 Job이 재시작된다면, 프레임워크는 Job의 상태 복수를 위해 ExecutionContext에 영속되었던 데이터라면 뭐든지 사용한다.
-> 제대로 완료되지 않은 entry를 테이블에서 삭제하면 job이 정확한 포인트에서 재시작하는 것을 방해한다.
SpringBatch Sequences
- 스프링배치는 기본적으로 시퀀스 테이블이 존재한다.
- BATCH_JOB_INSTANCE, BATCH_JOB_EXECUTION, BATCH_STEP_EXECUTION 테이블에 기본키 역할을 하는 ID가 존재하지만 이 테이블들은 키들을 생성하는 DB가 아니고 분리된 시퀀스들에 의해 생성된다.
- 시퀀스를 통해서 Batch_Job_Instance, Batch_Execution, Batch_Step_Execution 의 시퀀스를 배치가 할당하며, 이 값은 중복될 수 없다.
CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ;
CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ;
CREATE SEQUENCE BATCH_JOB_SEQ;
BATCH_JOB_SEQ
- 배치 잡에 대한 시퀀스 테이블이다.
- ID:
- bigint
- batch job의 기본키를 나타낸다.
- UNIQUE KEY
- char(1)
- batch job sequence를 구별하는 유니크 PK
BATCH_JOB_EXECUTION_SEQ
- 배치잡 execution의 시퀀스 테이블이다.
- ID:
- bigint
- batch JobExecution 의 기본키를 나타낸다.
- UNIQUE KEY
- char(1)
- bactch JobExecution 시퀀스를 구별하는 유니크 PK
BATCH_STEP_EXECUTION_SEQ
- 배치 스텝의 execution 시퀀스 테이블이다.
- ID:
- bigint
- batch StepExecution 의 기본키.
- UNIQUE KEY
- char(1)
- batch StepExecution 시퀀스를 구별하는 유니크 PK
'Spring > Spring Batch' 카테고리의 다른 글
SpringBatch(2) : 코드 설명 및 아키텍처 알아보기 (0) | 2024.10.30 |
---|