[Spring] Batch Application

건미누·2024년 4월 14일

Spring Study

목록 보기
7/7

Batch 시스템에 대해 작성하게된 계기

취업하게된 회사의 입사교육에서 회사의 서비스를 설명 받았다. Batch를 사용한 서비스를 제공하는 것이 어떠한 장점이 있는지, Batch를 어떻게 설계해서 효과적으로 서비스를 제공하는지에 대해 설명받았고 대용량 데이터를 처리해야하고 해당 내용을 통해 서비스를 제공하는 경우에 굉장히 효과적인 시스템이라는 생각이 들었다.

이전에 Spring Batch 개념을 듣긴했으나 내 프로젝트에는 필요가 없어 크게 관심을 두지 않았었는데 이번에 기술에 대한 관심이 생겨 공부해보고자는 마음이 생겼다.


Batch Applicatioin

개발자가 정의한 작업을 한번에 일괄 처리하는 어플리케이션

대량의 데이터를 읽거나 읽고 난 후 조작을 통해 서비스를 제공하기위해서는 상당한 시간이 걸린다. 따라서 대용량을 처리하는 것은 사용자의 이용이 가장 적은 시간대에 하는 것이 이상적이다.

그러나 이용자가 적은 시간대가 새벽 4시쯤이라 할 때, 매번 개발자가 새벽 4시에 업무를 할 수는 없는 일이다. 이럴 때도 유용한 것이 Batch Application이다.

용어 정리

Job

배치 처리 과정을 하나의 단위로 표현한 것

Job Instance

Job의 실행 단위를 나타낸다. 같은 Job을 실행하더라도 클래스와 같이 각각 다른 Job 인스턴스가 생성된다.

Job Parameters

Job 인스턴스는 Job 파라미터로 구분하게 된다. 그 외에도 Job 인스턴스에 전달되는 매개변수 역할도 하고 있다. 전달 가능한 파라미터는 String, Double, Long, Date 4가지 형식만 지원된다.

Job Execution

Job 인스턴스의 실행 시도에 대한 객체이다. Job 인스턴스의 실행이 실패해 재실행하여도 동일한 인스턴스를 실행시키지만 실행과 재실행에 대한 execution은 개별로 생성된다. 대체로 인스턴스 실행에 대한 상태, 시작, 종료, 생성 등의 정보를 담고 있다.

Step

Step은 Job의 배치 처리를 정의하는 순차적인 단계이다. Job은 최소 1개 이상의 Step으로 이루어져있고 일괄처리를 제어하는 정보가 들어있다.

Step Execution

Step 실행 시도에 대한 객체이다. Job이 여러 개의 Step으로 구성되어 있는 경우 이전 단계의 Step이 실패하면 다음 단계가 실행되지 않음으로 실패 이후 StepExecution은 생성되지 않는다. JobExecution에 저장되는 정보 외에 read 수, write 수, commit 수 등의 정보들이 저장된다.

ExecutionContext

Job에서 데이터를 공유할 수 있는 데이터 저장소이다. JobExecutionContext와 StepExecutionContext 2가지 종류가 제공되지만 두 ExecutionContext는 지정 범위에 차이가 있다. JobExecutionContext는 commit 시점에 저장되는 반면 StepExecutionContext는 실행 사이에 저장된다. ExecutionContext를 통해 Step 간 Data 공유가 가능하고 Job 실패 시 ExecutionContext를 통한 마지막 실행 값을 재구성 가능하다.

Job Launcher

JobLauncher는 Job과 Job 파라미터를 사용해 Job을 실행하는 객체이다.

ItemReader

ItemReader는 Step에서 Item을 읽어오는 인터페이스이다. 모든 항목이 소진된 경우 null을 반환한다.

ItemWriter

ItemWriter는 처리된 데이터를 Write할 때 사용한다. 처리 결과물에 따라 Insert, Update, Send가 된다. Writer는 기본적으로 Item을 Chunk으로 묶어 처리하고 있다.

ItemProcessor

Reader를 통해 읽어온 Item, 비지니스 처리를 담당한다. 항목이 유효하지 않으면 null을 반환한다. 바로 null을 반환하기 때문에 Optional 처리를 하지 않아도 된다.

Chunk

데이터 덩어리로 작업할 때, 각 커밋 사이에 처리되는 row의 수를 의미한다. Chunk 지향 처리라고 하면 한 번에 하나씩 데이터를 읽고 Chunk이라는 덩어리를 만든 뒤, Chunk 단위로 트랜잭션을 다루는 것을 미한다. 실패할 경우 Chunk 만큼만 롤백이 되고, 성공할 경우 Chunk 만큼 반영이 되기 때문에 실패 시 이전 데이터에 대한 안전이 보장된다.

Spring Batch


굉장히 감사하게도 Spring에서는 로깅/추적, 트랜잭션 관리, 작업 처리 통계, 작업 재시작, 건너뛰기, 리소스 관리 등 대용량 레코드 처리에 필수적인 기능을 제공한다. 뿐만 아니라 작업이 실패하여 retry할 경우 실패지점부터 시작할 뿐 아니라 중복처리를 막기위해 이미 성공한 적이 있는 파라미터로 실행할 경우 Exception이 발생한다고 한다.

Spring Batch에서는 JobLauncher와 JobRepository는 제공해주기 때문에 직접 구현하지 않아도 된다. (킹왕짱 Spring) 덕분에 Job과 Step에 주요하게 신경써서 코드를 작성하면 된다.

Tasklet

Job은 Step으로 구성되고 Step은 Tasklet으로 구성된다. tasklet은 익명 tasklet과 chunk oriented tasklet으로 나뉘어지지만 spring batch를 사용하는 경우 대부분 chunk oriented tasklet을 사용한다.

Chunk Oriented Tasklet

Processor 과정을 Chunk 단위로 진행을 한다. read -> process 과정으로 가져온 item이 Chunk단위만큼 쌓였을 때 write 하게 된다.
PrepareStatements의 addBatch 후 executeBatch와 비슷하다.

ItemReader

커서와 Paging 기능을 제공한다.

  • Cursor
    db와 커넥션을 유지한 채 item을 하나씩 가져오는 작업. 지속적으로 DB와 연결해야하기에 연결 위험성과 모든 데이터를 메모리에 저장하기에 메모리 사용량이 많다. (Thread Safe ❌)

  • paging
    한 번 커넥션을 할 때, 정해진 paging size만큼 한번에 item을 가져온다. 여러번 트랜잭션을 타야하지만 Connection Time과 한 번에 사용하는 최대 메모리 용량이 적을 가능성이 크다. (Thread Safe ⭕)

ItemWriter

Chunk 단위만큼 한번에 작업을 수행

  • Paging을 통한 ItemReader 과정
  1. paging시 메모리에 page 사이즈 만큼 데이터를 가져온다.
    • 이 때, ChunkSize와 Page Size를 동일하게 가져오는 것을 권장한다. (ChunkSize보다 PageSize가 적은 경우 여러번 Connection하여 가져와야하기에 성능이 저하된다.)
  2. Chunk를 하나의 트랜잭션에서 처리한다.
    • JPA의 영속성 컨텍스트 사용이 가능

ItemProcessor

선택적으로 구성해서 적용, 데이터를 가공하거나 Filtering하는 기능 (Writer에서도 가능하기에 선택사항)

사용한다면 비즈니스 코드가 섞이는 것을 방지할 수 있으며 유지보수성이 좋아진다. 또한, 처리 실패 시 null 값을 반환하여 writer에 전달되지 않도록 한다.

Step Flow

흐름에 따른 순차적 step 뿐 아니라, 성공과 실패 등 결과 여부에 따라 다음으로 처리할 step을 작성할 수 있다.

주의사항

  1. 테스트 코드를 반드시 작성해라
    • QA하기가 어렵기 때문에 테스트 코드를 통해 안전성을 보장해야한다.
  2. 복잡한 과정을 처리하고 저장하는 작업이기에 통합 테스트가 필요하다. 따라서 단위 테스트를 통해 내부 작업을 검증하고 전체 테스트 코드를 반드시 작성해야한다.
  3. Chunk 최적화

@Scheduler와의 차이?

사실 이 부분은 아직도 이해가 확실하게 되지는 않지만 분명한 것 하나는 Batch와 Scheduler는 다른 시스템이라는 것이다. 이 차이를 설명하기 위해 조건들이 있는데 Batch는 5가지를 만족해야 한다.

  1. 대용량 데이터 처리가 가능해야한다.
  2. 자동화 가능해야한다.
    • 개발자의 개입 없이도 스스로 실행되며 반복적으로 로직을 처리가능해야한다.
  3. 신뢰 가능해야한다.
    • 수행 중 문제 발생 시 Logging 등의 형태로 문제가 된 부분에 대해 Tracking이 가능해야한다.
  4. 견고한 구조
    • 예외상황 발생 시 중단 없이 처리 가능해야한다.
  5. 성능
    • 대용량 데이터 처리 시 예상 시간 내에 로직을 처리하거나 다른 Application이나 비즈니스 로직에 방해되지 않게 실행되어야한다.

5의 경우 Spring Framework를 통해 Web Application을 구동 중이라면 Spring Batch를 통해 Batch Application을 생성해 사용할 수 있다고 한다.

솔직한 생각으로는 Scheduler + @ = Batch Application이라는 생각이 든다. Spring Batch 공식 문서에도 Scheduler는 Batch을 돕는 보조(정해진 시간에 구동시키기 위해)라고 설명되어 있는데 내가 이해하기로는 Scheduler는 Batch를 사용하기 위해 도움을 줄 수 있는 기능이기 때문에 Scheduler와는 개념적으로 다른 느낌이다. (Batch는 대용량 처리를 위해 Scheduler는 정해진 시간에 로직을 실행시키기 위해.)

@Scheduler를 남발하고 api를 여러개 만들어서 Batch 없이도 정해진 시간에 처리하는 로직을 작성은 할 수 있겠지만... 하루 한번 동작하는 로직을 위해 api 작성까지는... 굳이...? 인 느낌.


Spring Batch를 아직 사용해보지는 않아서 아직 Batch를 정확히 어떻게 구성하고 어떻게 해야 서비스에 이용가능한지에 대해서는 감이 오지 않는다.

하지만 실제 현업 서비스에서는 비지니스 서비스 이용에 방해가 되지 않게 따로 실시간 처리와 대용량 처리를 위한 Agenda Server를 따로 구성하여 쓴다고하니 성능을 위해서는 확실히 기본 비지니스 로직에 영향이 가지 않도록 설계해야할 것 같다.

다음에 따로 프로젝트를 통해 서비스를 만들게 될 때 대용량의 데이터를 처리하여 서비스를 진행해야한다면 반드시 한 번 써보고 싶은 기술이다.

참고자료

https://junuuu.tistory.com/611
Youtube 테코톡 라빈의 Spring Batch

profile
꺾여도 해야지

0개의 댓글