Study/Spring Batch

Spring Batch 기본 개념

voider 2022. 1. 21. 13:35

배치 프로그램

정해진 시간에 일괄 작업을 처리한다(대체로 대용량)

배치 프로그램은 보이지는 않지만 늘 존재한다.

서비스 운영 관점에서 주기적으로 작업을 처리하려면 배치 프로그램을 사용해야 한다.

배치 프로그램이 필요한 상황

  • 필요한 데이터를 모아서 처리해야 할 때
    • ex. 월별 거래 명세서 생성
  • 일부러 지연시켜 처리할 때
    • ex.주문한 상품을 바로 배송처리 하지 않고 일정 시간 뒤 처리
  • 자원을 효율적으로 활용하기 위해
    • 트래픽이 적은 시간 대에 서버 리소스를 활용

데이터 처리 배치 프로그램 사용 예시

  • 각 서비스의 데이터를 데이터 웨어하우스에 저장할 때
    • ETL(Extract-Transform-Load, 추출 - 변환 - 저장)
  • 아마존에서 연관 상품을 추천하는 것처럼 데이터 모델을 만들 때
  • 유저 리텐션, 액티브 상태 등 마케팅에 참고할 데이터 지표를 집계할 때

서비스 배치 프로그램 예시

  • 메시지, 이메일, 푸시 등을 발송할 때
  • 데이터를 마이그레이션 할 때
  • 실패한 트랜잭션을 재처리할 때
  • 쿠폰, 포인트 등이 만료되었을 때 소진하는 처리
  • 월말 또는 월초에 특정 데이터를 생성할 때 - 월별 거래 명세서

Spring batch?

“A lightweight, comprehensive batch framework designed to enable the development of robust batch applications vital for the daily operations of enterprise systems.”

가볍고 다양한 기능을 가진 배치프레임워크. 견고한 배치 애플리케이션 개발이 가능하도록 디자인 되어있다. 기업 시스템의 메일 운영에 필수적인 수준

Spring batch를 사용하는 이유

Spring 환경

  • 스프링으로 작성된 코드를 재활용할 수 있다. 기존 Spring 프로젝트 코드를 활용하거나 모듈을 이용할 수 있다.
  • 만약 배치용 코드를 새로 작성한다면 Python, Shell script, Go 등 다른 언어로 비슷한 처리를 새로 구현해야 한다.
  • 배치 처리를 위한 로직을 새로 만드는 것보다 스프링 배치에서 제공하는 기능을 이용하는 게 생산성 있는 방법.

다양한 기능 제공

  • 로깅/추적, 트랜잭션 관리, 작업 처리 통계, 재시작, 건너뛰기 등 대용량 처리에 필수적인 기능 제공
  • 멀티 코어 또는 멀티 서버에서 처리를 분산하는 기능을 제공한다.

즉, 스프링 배치 프레임워크가 제공하는 기능을 이해하고 잘 사용하면 된다.

Spring Batch 도메인 언어

스프링 배치가 ‘배치’라는 목적을 위해 어떤 컴포넌트를 가지고 있는지 알아본다.

  • JobLauncher는 Job을 실행하는 컴포넌트
  • Job은 배치 작업을 의미한다. JobRepository는 Job 실행과 Job, Step을 저장
  • Step은 배치 작업 단계다. ItemReader, ItemProcessor, ItemWriter는 데이터를 읽고 처리하고 쓰는 구성
    • ItemReader
      • 데이터를 읽는 컴포넌트
    • ItemProcessor
      • 데이터를 가공/처리하는 컴포넌트
    • ItemWriter
      • 데이터를 쓰는 컴포넌트
    배치 작업을 하면 실제 서비스가 가진 데이터베이스에 있는 데이터를 읽고, 가공해서 새로운 데이터소스에 쓰는 작업을 하게 된다. 이 과정을 추상화 해놓은 것이다.
  • Step의 경우 Reader, Processor, Writer를 각각 하나씩만 가질 수 있다.

레이어

Applcation

Core

Infrastructure

이 세 가지 레이어로 구성되어 있다.

Applicatino Layer

  • 사용자(=우리) 코드와 코어나 인프라 스트럭처를 어떻게 사용할지에 대한 구성이 나타나 있는 것이 애플리케이션 레이어다.
  • 비즈니스, 서비스 로직이 구현되는 곳이 이 레이어다.
  • Core, Infrastructure를 이용해 배치의 기능을 만든다.

Core Layer

  • 배치 작업을 시작하고 제어하는데 필수적인 클래스로 이루어져 있음.
  • Job, Step, JobLauncher가 이 레이어에 속함.

Infrastructure Layer

  • 외부와 상호작용하는 레이어다.
  • ItemReader, ItemWriter, RetryTemplate 등이 이 레이어에 속한다.

각 레이어가 무엇을 가지고 있느냐를 아는 것보다 실제로 스프링 배치는 스프링배치가 제공하는 코어, 인프라스트럭쳐 컴포넌트가 있고, 이것을 활용해서 배치 애플리케이션을 만들어낸다는 것을 이해하는 게 중요하다.

Job

Job은 말 그대로 일이다.

  • 전체 배치 프로세스를 캡슐화한 도메인
  • Step의 순서를 정의한다.
  • JobParateres를 받는다.

Job 옆에 빨간 텍스트를 보면 EndOfDay라는 Job이 정의돼 있다.

실제로 이 Job을 수행하게 되면 JobInstance 가 만들어진다. JobInstance 는 실제로 Job을 수행할 때 바뀌는 파라미터들을 가지고 만들어진다. 계속해서 위 그림에 빗대어 보면 JobParamters인 schedule.data = 2007/05/05 라는 파라미터를 가지고 JobInstance 가 만들어지는 것이다. 이건 실질적으로 Job이 실행되는 객체다. 이 객체는 2007/05/05라는 파라미터를 받아서 EndOfDay라는 Job을 실행하는 인스턴스로 정의된다.

2007/05/05라는 파라미터를 가지고 EndOfDay라는 Job을 첫 번째 실행했을 때 JobExecution이 된다.

Job이라는 건 배치 작업을 실행할 때 필요한 데이터를 파라미터로 받아서, 이걸 가지고 실행이 된다고 간단하게 이해할 수 있다.

Job → Code

@Bean
public Job footballJob() {
	return this.jobBuilderFactory.get("footballJob")
            .start(playLoad())
            .next(gameLoad())
            .next(pla

Step

  • 작업 처리 단위
  • Chunk 기반 스텝, Tasklet 스텝 두 가지로 나뉜다.

Chunk 기반 Step이란?

  • 청크 기반으로 하나의 트랜잭션에서 데이터를 처리하는 것을 의미

위 표처럼 step의 실행부터 종료(읽기-가공-쓰기)까지 하나의 트랜잭션에서 처리가 된다.

commitInterval만큼 데이터를 읽고 트랜잭션 경계 내에서 chunkSize만큼 Write를 한다는 것.

**pseudo code**
List items = new Arraylist();
for (int i = 0; i < commitInterval; i++) {
	Object item = itemReader.read();
	if (item != null)
		items.add(item);
}

List processedItems = new Arraylist();
for (Object item: items) {
	Object processedItem = itemProcessor.process(item);
	if (processedItem != null)
		processedItems.add(processedItem);
}

itemWriter.write(processedItems);
  • chunkSize : 한 트랜잭션에서 쓸 아이템의 갯수
  • commitInterval: reader가 한 번에 읽을 아이템의 갯수
  • chunkSize ≥ commitInterval 하지만 보통 같게 맞춰서 사용하는 게 좋다.
    • 예를 들어 10개를 읽어서 배치 작업을 한다면, 10개를 쓰는 식으로 구성한다.
    • 숫자를 맞춰야 혼돈을 피할 수 있기 때문
@Bean
public Step sampleStep(PlatformTransactionManager transactionManager) {
	return this.stepBuilderFactory.get("sampleStep")
					.transactionManager(transactionManager)
					.<String, String>chunk(10)
					.reader(itemReader())
					.wrtier(itemWriter())
					.build();
}
  • ItemReader, ItemProcessor, ItemWriter 구현체 설정
  • ItemProcessor는 간단한 작업이라면 생략하고 Write에서 처리해도 됨.

Tasklet step

read, process, write은 하나의 트랜잭션에서 모든 데이터를 처리한다. 단순한 처리를 할 때 사용한다.

@Bean Step step1() {
	return this.stepBuildFactory.get("step1")
					.tasklet(myTasklet())
					.build()
}
  • Tasklet 구현체를 설정한다. 내부에 단순한 읽기, 쓰기, 처리 로직을 모두 넣는다.
  • RepeatStatus(반복 상태)를 설정한다. 보통은 RepeatStatus.FINISHED

Spring Batch 스키마 구조

Metadata schema

배치를 실행하고, 관리하기 위한 메타 데이터가 저장된다.

이 메타데이터가 각각의 컴포넌트를 의미한다. 스프링 배치가 실행될 때 각각 클래스를 생성하고 사용하는데, 이걸 데이터베이스에 남긴다.

metadata 스키마 활용

  • Spring Batch Frameworkrk 실행 시 metadata 테이블을 사용하므로 초기 설정이 필요하다
  • 배치 프레임워크에 속하는 부분이므로 수정하지 않고 조회만 한다
  • Job의 이력, 파라미터 등 실행 결과를 조회할 수 있다
  • 배치 결과에 대해 로그, 별도의 실행 이력을 남기는 경우가 대부분이므로 조회할 일이 많지 않다

'Study > Spring Batch' 카테고리의 다른 글

[Spring Batch] Job Lifecycle  (0) 2022.01.31