[Spring Batch] Intro - 스프링 배치 기본 개념 익히기

스프링 배치 강좌 목록: https://www.fwantastic.com/p/spring-batch.html



스프링 배치스프링을 만든 Pivotal의 프로젝트 중 하나이다. 미국에 Accenture (이제는 아련한 나의 전 직장...) 라는 아주 큰 규모의 컨설팅 회사가 정부 프로젝트를 하며 얻은 비즈니스 로직과 노하우에 Pivotal이 가진 기술로 협력하여 만들어낸 결과물이다. 배치 작업을 위해 만들어진 프레임워크으로 가볍고, 빠르고, 실행 도중 문제가 생기면 그 지점부터 재시작할 수 있다는 점이다 (Restartability). 스프링 배치를 하려면 스프링을 알고있어야 하기 때문에 모른다면 스프링을 먼저 공부하는것을 추천한다.



스프링 오피셜 가이드: https://spring.io/guides

스프링은 웹 프로젝트를 하면서 많이 쓰이는데 배치란 개념은 약간 생소할 수도 있다. 구글님께서 Batch processing 뜻이라 검색하니 일괄 처리라는 답변을 준다. 좀 더 이해하기 쉽도록 간단한 예를 들어보자.

서울에 Capital One이라는 은행이 있다. 손님이 돈을 입금하면 핸드폰에서 바로 확인이 가능한데, 입금 즉시 event가 발생하여 처리가 끝나는 실시간 트랜잭션이기 때문이다. 하루가 끝나거나 월말에 보통 정산이나 마감과 비스름한 작업이 있다. 이러한 작업은 실시간으로 할 필요가 없이 정해진 시간에 사람의 개입이 필요 없이 자동으로 진행되는 것들이다. 이런걸 Batch라고 볼 수 있다.

이제 스프링 배치의 관점에서 생각해보자. Capital One 은행은 매일 오후 10시에 당일 지점을 방문한 고객 리스트를 만들어 본사로 보내야 한다.

Capital One 은행 서울 지점의 DB를 조회
-> 필요한 정보만 따로 추출 후 가공
-> 파일에 저장
-> FTP를 사용해 파일을 본사 서버로 전송


위와 같이 배치는 프로그래밍의 method/function과 같다. 어떻게 InputOutput을 정의하느냐에 따라서 거의 모든 작업을 스프링 배치화 시킬 수 있다.

자주 쓰이는 예들:
  • 파일 -> DB
  • 파일 -> 파일
  • DB -> 파일
  • DB -> DB
  • DB -> 메일 발송
  • API -> DB

그럼 왜 스프링 배치일까. 일단 스프링 계열로써 안정성을 믿을 수 있다. 또한 스프링을 접해보았다면 스프링 배치를 배우는데 Learning curve가 작다고 할 수 있겠다. 그 외에 위에 언급한 핵심적인 Restartability가 있다. 100기가의 파일을 처리하던 도중 55% 즈음에 예상치 못한 에러로 배치가 종료되었어도 재시작을 하여 종료되었던 55% 지점부터 이어서 작업을 할 수 있다.


What is Spring Batch와 Why should we use Spring Batch를 살펴보았으니 다음은 How로 넘어가자.



스프링 배치 Job의 구성

JobRepositoryJobLauncher는 일단 제쳐두고 제일 먼저 이해해야 할 것이 Job의 구성이다. 관련 용어들을 살펴보자.



Job

Job = 배치 작업이다. 혹은 Flow라고도 부른다.  최소 하나의 Step을 가져야 하며 엄청나게 복잡한 Job이 아닌 이상 2-10개의 Step을 권장한다 (솔직히 10개도 너무 많다). 만약 Step 개수가 10개 이상이면 일반적인 코드 리팩토링처럼 여러 개의 Job으로 쪼개서 하나의 Job에 너무 많은 책임들(Responsibilities)이 몰리게 하지 말자. 프로그램을 만드는 것도 중요하지만 유지보수와 관리, 모니터링도 그만큼 중요하니까.



Step

Step읽기 -> 가공하기 -> 쓰기의 묶음이다. 이 묶음을 Chunk processing이라고 부르는데 하나의 트랜잭션으로 이해하면 된다. 바로 이 Chunk processing이 위에 언급한 재시작의 핵심이다.

다음은 스프링 공식 문서에서 가져온 Chunk processing의 컨셉트를 보여주는 예제이다. 한꺼번에 다 읽어서 쓰는 게 아닌 commitInterval 만큼 읽고 쓰기 때문에 재시작이 가능한 것이다.


List items = new Arraylist();

for(int i = 0; i < commitInterval; i++){

    Object item = itemReader.read()

    Object processedItem = itemProcessor.process(item);

    items.add(processedItem);

}

itemWriter.write(items);


더 나아가서 필요에 따라 여러 개의 ItemReader를 거쳐 여러 개의 ItemProcessor를 거쳐 여러 개의 ItemWriter를 사용하게 할 수도 있다.



ItemReader

ItemReader는 말 그대로 데이터 읽기를 담당한다. 정확히는 인터페이스이며 T read() 메소드를 가지고 있다.

ItemReader 정의
public interface ItemReader<T>

공식 페이지에서 T read() 메소드의 Java Doc을 보자.

Reads a piece of input data and advance to the next one. Implementations must return null at the end of the input data set. In a transactional setting, caller might get the same item twice from successive calls (or otherwise), if the first call was in a transaction that rolled back.

요약하면, 읽어드린 데이터를 반환한다. 만약 null을 리턴 할 경우 읽어야 하는 총 데이터의 마지막임을 나타낸다. DB로 치면 하나의 row를, 파일로 치면 한 line을, JSON Array로 치면 하나의 element를 반환한다고 생각하면 쉽다. ItemReader 구현 방식에 따라 훨씬 복잡한 구조의 데이터도 처리 할 수 있다.

read 메소드의 반환 값은 ItemProcessorInput으로 사용된다.


아래는 스프링 배치가 제공하는 자주 쓰이는 ItemReader 구현체들인데 굳이 직접 만들지 말고 왠만하면 out of the box 부품들을 사용하도록 하자.
  • FlatFileItemReader
  • HibernateCursorItemReader
  • JdbcCursorItemReader
  • JsonItemReader
  • MongoItemReader

ItemReader 공식 문서: https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/item/ItemReader.html






ItemProcessor


ItemProcessorItemReader에게서 Object를 넘겨받아 원하는 방식으로 가공 후에 ItemWriter에게 넘겨주는 역할을 하며, 한 번에 하나의 아이템을 처리한다.

ItemProcessor 정의
public interface ItemProcessor<I,O>

ItemReader와 마찬가지로 인터페이스이며 InputOutput을 지정해주어야 한다. InputItemReader에게서 넘겨받는 타입이고 OutputItemWriter에게 넘겨줄 타입이다.

한마디로 ItemReader<T>T와 ItemProcessor<I,O>I는 같은 타입이어야 하고

ItemProcessor<I,O>O와 ItemWriter<T>T가 같은 타입이어야 한다.


O process(I item)
process 메소드로 넘겨받은 item을 가공하여 수정된 item을 그대로 넘기거나 새로운 객체를 만들어 넘길 수 있다.

참고로 ItemProcessor가 꼭 필요한 건 아니다. 데이터를 가공할 필요가 없는 경우엔 ItemReader -> ItemWriter로 바로 넘겨도 상관없다.


ItemProcessor 공식 문서: https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/item/ItemProcessor.html




ItemWriter


ItemWriter 정의
public interface ItemWriter<T>

void write(java.util.List<? extends T> items)

ItemReader 혹은 ItemProcessorItemWriter로 데이터를 넘겨주면 리스트에 차곡차곡 쌓아놓는다. 이때 commit-interval 프로퍼티의 정의된 개수만큼 데이터가 모이면 write 메소드를 실행하게 된다. commit-intervalStep에 설정할 수 있다. (정확히는 Step 안에 Chunk에)

ItemReader와 마찬가지로 스프링 배치에서 제공해주는 자주 쓰이는 ItemWriter 구현체들이다.
  • CompositeItemWriter 
  • FlatFileItemWriter
  • HibernateItemWriter
  • JdbcBatchItemWriter
  • JsonFileItemWriter
  • MongoItemWriter

ItemWriter 공식 문서: https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/item/ItemWriter.html





다음 스텝


영어로 돼 있어서 힘들겠지만 역시 공식 문서가 짱짱맨이다.


이 포스트에서 다루지 않은 중요한 것들도 많으니 차근 차근 배워보자.


다음 글

[Spring Batch] 스프링 배치 강좌 1. 프로그래밍의 꽃. 스프링 배치 Hello World!