스프링 배치 - 소개 및 도메인 개념

600g (Kim Dong Geun)·2022년 2월 10일
1
post-thumbnail

스프링 배치 소개

https://godekdls.github.io/Spring%20Batch/introduction/#11-background
굉장히 잘 번역되어져 있다.

  • 스프링 배치의 기본 가이드라인, Batch processing 전략등은 두고 두고 봐도 좋을듯.

간단하게 요약하자면, 스프링 배치 프로젝트는 배치를 스프링에 사용할 수 있도록 만든 프레임워크 이다.
프레임워크단에서 프로세싱 작업에 대한 구조를 제공하고 사용자는 비즈니스 로직에 더욱 집중할 수 있다.
재사용도 가능하다. 병렬 프로세싱도 가능하다 등등

나머지는 기본 가이드라인, Batch Processing에서 스프링 배치의 활용이 잘 나와있으니까 읽어보면 된다.

Spring batch의 도메인

JOB

  • 전체 배치 프로세스를 캡슐화한 엔터티

  • XML 기반, 자바 기반 설정 둘다 지원

  • 스프링 배치에서 Job은 단순히 Step 인스턴스의 컨테이너 개념이다. 논리적으로 한 플로우에 속한 여러 Step을 결합한다

  • JOB은 다음과 같은 속성을 정의할 수 있다.
    - JOB의 이름
    - Step인스턴스 정의와 순서
    - Job의 재시작 가능 여부

  • SimpleJob은 스프링 배치에서 디폴트로 제공하는 간단한 Job 인터페이스 구현체로 Job의 일부 표준 기능을 구현한다.

@Bean
public Job footballJob() {
	return this.jobBuilderFactory.get("footboolJob")
		.start(playerLoad())
		.next(gameLoad())
		.next(playerSummarization())
		.end()
		.build();
}

JobInstance

JobInstance는 논리적인 Job 실행을 말한다.
"EndOfDay" Job처럼 하루가 끝날 때마다 한번 실행돼야 하는 배치를 생각해보자. 21일 실행, 22일 실행 각각의 실행이 발생할텐데 이 "실행 1번"을 담당하는 객체가 JobInstance라고 보면된다.

  • 추적이 용이
    JobInstance를 배치해둠으로서 각 배치 작업에 대한 추적이 가능해진다.
    즉 21일 실행이 실패 났을경우 21일 EndOfDay의 JobInstance만 확인하면 된다.

  • Entity
    특정 Job내에서 JobInstance는 식별가능한 Entity 도메인이다.
    다만 1월 1일이 실패 됐을때 재처리를 위해서 1월1일에 해당하는 JobInstance를 재실행할 수 있는데 실행결과는 여럿 가질 수 있지만, 해당 JobParameter에 상응하는 JobInstance는 Job내에 유일해야한다.

    즉 재처리가 됐다하더라도 1월1일에 실행한 동일한 JobInstance가 실행이 된다는 말.

만약 JobInstance를 새로 만들어야 할 경우는 재실행이 아닌 처음부터 시작 이어햐 한다는 것.
이미 있던 Instance를 쓴다는 것은 실패했던 부분 부터 다시 시작을 의미

JobParameters

JobInstance는 다른 JobInstance들과 어떻게 구분하는가를 이야기 할 떄 JobParameter를 이야기 할 수 있다.

JobParameter란 배치 Job을 시작할 때 사용하는 파라미터 셋을 가지고 있는 객체.
따라서 Job을 식별하거나 참조 데이터로도 사용할 수 있다.


따라서 다음과 같은 공식으로 이야기 할 수 있을 것 같다.

$$ JobInstance = Job + 식별 JobParameter $$

다만 모든 Job Parameter가 JobInstance를 식별하는데 사용하지 않는다. 기본적으로는 그렇지만 JobInstance Id에 관여하지 않는 파라미터를 사용할 수 도 있음.

JobExecution

JobExecution의 개념은 Job을 한번 실행하려 했다는 것
하나의 실행은 성공하거나 실패하게 되는데, JobInstance는 실행이 성공적으로 종료되기전까지는 완료하지 않음으로 간주한다.

따라서 EndOfDay의 Job이 실행되고 1월 1일 JobInstance가 만들어진 뒤 JobExecution을 통해 작업을 실행하게 된다. 그러나 만약 첫번째 JobExecution이 실패하게 된다면, JobInstance는 새 JobExecution을 생성하여 작업을 종료하려 할 것이다.
이때 여전히 JobExecution은 1개이다.

위 3개념을 다시 요약해보자면

  • Job : job이 무엇이고, 어떻게 실행되어야 하는지를 정의
  • JobInstance : 올바른 재시작을 위해 실행을 그룹화 하는 순수한 구조적 오브젝트
  • JobExecution : 실제 실행 중에 필요한 기본 스토리지 메커니즘을 제공한다.

JobExeuction은 다음과 같은 Properties 를 가지고 있다.

PropertyDefinition기타
Status실행상태를 나타내는 BatchStatus 오브젝트.BatchStatus#STARTED : 실행중
BatchStatus#FAILED : 실패
BatchStatus#COMPLETED : 성공
startTimejob을 실행할 때의 시스템 시간을 나타냄java.util.Date Type
endTime성공 여부와 상관없이 실행이 종료될 때의 시스템 시간을 나타냄java.util.Date
exitStatus실행 결과를 나타내는 ExitStatus, 호출자에게 리턴하는 종료코드를 가지고 있기 때문에 가장 중요아직 Job이 완료되지 않으면 비어 있음
createTimeJobExecution이 처음 저장될 때의 시스템 시간java.util.Date
lastUpdatedJobExecution이 저장된 마지막 시간을 나타냄java.util.Date
executionContext실행하는 동안 유지해야 하는 모든 사용자 데이터를 담고 있는 Propertybag
failureExceptionsjob실행 중 발생한 예외 리스트,job 실패시 예외가 2개 이상 발생하는 경우 유용하다.

예시

다음은 Spring Batch 가 다음과 같이 Job을 테이블에 관리한다.

Step

Step은 배치 job의 독립적이고 순차적인 단계를 캡슐화한 도메인 객체
모든 Job은 하나 이상의 JobExecution이 존재하듯, Step은 하나이상의 StepExecution을 가지고 있다.

StepExecution

StepExecution은 한 번의 Step 실행 시도를 의미한다.
StepExeuction 은 JobExecution과 유사하게 Step을 실행할 때마다 생성한다. 이전 단계 Step이 실패해서 step을 실행하지 않았다면 exeuction을 저장하지 않는다.

실제 Step이 시작 됐을 때만 StepExecution을 생성한다.

PropertyDefinition기타
Status실행상태를 나타내는 BatchStatus 오브젝트.BatchStatus#STARTED : 실행중
BatchStatus#FAILED : 실패
BatchStatus#COMPLETED : 성공
startTimestep을 실행할 때의 시스템 시간을 나타냄java.util.Date Type
endTime성공 여부와 상관없이 실행이 종료될 때의 시스템 시간을 나타냄java.util.Date
exitStatus실행 결과를 나타내는 ExitStatus, 호출자에게 리턴하는 종료코드를 가지고 있기 때문에 가장 중요아직 Job이 완료되지 않으면 비어 있음
lastUpdatedJobExecution이 저장된 마지막 시간을 나타냄java.util.Date
executionContext실행하는 동안 유지해야 하는 모든 사용자 데이터를 담고 있는 Propertybag
readCount성공적으로 Read한 아이템 수
writeCount성공적으로 Write한 아이템 수
commitCount실행중에 커밋된 트랜잭션 수
rollbackCountStep에서 처리된 트랜잭션 중 롤백된 횟수
readSkipCountread에 실패해서 스킵된 횟수
processSkipCountprocess에 실패해서 스킵된 횟수
filecountItemProcessor에 의해 필터링된 아이템 수
writeSkipCountwrite에 실패해서 스킵된 횟수

ExecutionContext

ExecutionContext는 프레임워크에서 유지/관리하는 키/값 쌍의 컬렉션
StepExecution, JobExecution 객체의 상태를 저장한다.
Execution 상태를 저장하고 있어, 재시작에 용이하다 왜냐하면 실패되기전까지의 Context를 저장하고 있기 때문이다.

예를들어 파일을 읽다가 특정 라인에서 에러가 발생했다. 이를 해결하기 위해서는 ExecutionContext에 특정 라인수를 넣어 다시 실행해주면 된다.
다음 예제와 같이 현재 읽은 라인 수를 컨텍스트에 넣기만 하면 나머지는 프레임워크가 다 처리한다.

executionContext.putLong(getKey(LINES_READ_COUNT), reader.getPosition());

좀 더 자세히 설명하자면 다음과 같은 상태로 JOB이 실패가 났다고 생각해보자.

위 테이블들을 설명하자면 다음과 같다.

  • Step이 30분 동안 실행 됐다.
  • 40321개의 데이터를 처리하고 실패가 났다.

따라서 40322부터 JobExecution을 재실행시켜줘야 하는데 , 마지막 실행을 가리킨 executionContext를 읽어서 다음실행에 넣어줄 수 있게 구현할 수 있다

// executionContext가 마지막으로 읽은 상태가 있는지 확인하고, 재실행할 수 있도록 세팅해주는 코드.

if(executionContext.containsKey(getKey(LINES_READ_COUNT))) {

	log.debug("Initializing for restart. Restart data is: " + executionContext);


	long lineCount = executionContext.getLong(getKey(LINES_READ_COUNT));

	LineReader reader = getReader();

	Object record = "";
    while (reader.getPosition() < lineCount && record != null){
		record = readLine();
	}

}

위 코드를 통해서 중단 됐던 위치로부터 (40322번째) Step을 다시 실행할 수 있다.

JobExecution 당 ExecutionContext가 하나인 것처럼, 모든 StepExecution 마다 ExecutionContext를 하나를 가지고 있다.

ExecutionContext ecStep = stepExeuction.getExecutionContext();
ExecutionContext ecJob = jobExecution.getExecutionContext();

Job Repository

JobRepository는 위에서 언급된 객체의 모든 영속성을 관리해준다.
JobLauncher, Job, Step 구현체에 CRUD 기능을 제공한다.
Job을 실행할 때 레포지토리에서 JobExeuction을 조회하고 실행중에는 StepExecution, JobExecution 구현체를 레포지토리에 넘겨 저장한다.

자바 기반 설정은 @EnableBatchProcessing 어노테이션만 달아주면 JobRepository를 자동으로 컴포넌트로 설정한다 (주입된다)

JobLauncher

JobLauncher는 아래 코드처럼 주어진 JobParameter로 Job을 실행시키는 간단한 인터페이스

public interface JobLauncher {

public JobExecution run(Job job, JobParameters jobParameters)
            throws JobExecutionAlreadyRunningException, JobRestartException,
                   JobInstanceAlreadyCompleteException, JobParametersInvalidException;
}

Item Reader

ItemReader는 Step에서 아이템을 한번에 하나씩 읽어오는 작업을 추상화한 개념, 더이상 읽을 아이템이 없으면 Item Reader는 null을 리턴한다.

Item Writer

ItemWriter는 Step에서 배치나 청크단위로 아이템을 출력하는 작업을 추상화한다. 보통 ItemWriter는 다음에 받을 입력이 무엇인지는 알지 못하고 현재 받은 아이템만 알고있다.

Item Processor

ItemProcessor는 아이템을 처리하는 비즈니스 로직을 나타내는 추상화 개념이다. ItemReade가 아이템을 하나 read하고 ItemWriter가 아이템 묶음을 한다면 ItemProcessor는 데이터 변환이나 다른 비즈니스 처리를 담당한다. 데이터를 처리하던중 아이템이 유효하지 않다고 판단하면 null을 리턴한다.

Reader, Writer, Processor는 추후 자세한 설명이 곁들여 진다고 한다.

후기

도메인 개념만 읽었을 뿐인데, 배치 프로그램 하나는 짤 수 있을 것 같은 출처를 알 수 없는 자신감이 든다.
그만큼 사용하기 쉬운 도메인 설계를 바탕으로 스프링 배치를 만들었다라는 소리가 아닐까 한다.
열심히 공부해보자

출처 : Spring Batch Document
출처 : 토리맘님의 스프링 배치

profile
수동적인 과신과 행운이 아닌, 능동적인 노력과 치열함

0개의 댓글