Spring Batch
Batch Application
종종 어플리케이션에서 필수적인 작업으로 배치 프로세싱이 요구됩니다.
여기서 배치의 의미를 한 번 짚고 가겠습니다.
Batch
: 집단, 무리, 함께 묶다.
Batch는 한 무리를 의미하며, 대부분 그 규모가 큰 것들을 말합니다.
그래서 배치 애플리케이션이라고 하면 개발자가 정의한 작업을 한번에 일괄 처리하는 애플리케이션이라고 정의할 수 있습니다.
그럼 어떨 때 이 배치 애플리케이션이 필요할까요?
예를 들어, 한 기업에서 사전 예약 이벤트를 진행했는데 신청한 유저의 데이터 수는 100만 건이라고 해볼게요.
사전 예약 이벤트를 접수한 모든 유저에게 메일을 보내야합니다.
100만 건의 메일을 어떻게 보내야 할까요?
이 작업은 기존의 웹 애플리케이션을 제작하던 방식과는 다른 관점으로 바라봐야합니다.
사용자와의 인터랙션이 없으며, 대량의 데이터, 복잡한 프로세스, 반복적이고 주기적인 프로세스를 가질 수 있습니다.
위의 예시말고도, 월말 정산을 처리한다거나 따로 적재된 데이터베이스를 통합하는 작업, 은행 점검 등이 있습니다.
이런 작업을 배치 작업이라고 합니다.
배치 작업은 사용자가 개입하지 않는 환경에서 특정 완료 지점까지 실행됩니다.
vs Web Application
일반적으로 클라이언트 또는 웹 앱 같은 GUI 기반 프로그래밍에서의 문제 해결 방식에는 익숙합니다.
보안 문제, 데이터 유효성 검증(valildation), 사용자 친화적 오류 처리, 예측할 수 없는 사용 패턴으로 인한 리소스 사용률 급증 등, 모든 거들을 유저를 가진 소프트웨어를 사용하면 항상 고려해야 하는 문제가 있죠.
그런데, 배치는 기존의 개발 환경과는 다릅니다.
GUI 어플리케이션에서 고려해야 하는 대부분의 문제를 Batch 처리 시에는 고려할 필요가 없습니다.
물론 보안이나 데이터 유효성을 처리해야 하지만, 트래픽 사용량이나 사용자 중심의 에러 처리를 고려하지 않아도 된다는 의미입니다.
확실한 로그와 피드백 용 알림만을 사용해서 정확하게 에러를 인지하기만 하면 되죠.
대신 배치는 다른 면에서 생각해볼 내용들이 있습니다.
Batch's Challenges
보통 소프트웨어는 사용성 usability, 유지보수성 maintainability, 확장성 scalability 등의 속성을 가지고 있습니다.
배치 처리 시에는 기존의 웹 애플리케이션에서 필요로 하는 속성들과 직면한 문제의 방향이 조금씩 다릅니다.
몇 가지 속성에 대해 이야기 해볼게요.
✔️ 사용성
Usability
사용성이라고 하면 어떤 것들이 먼저 생각해보세요.
기존의 웹 애플리케이션의 사용성을 떠올리실 겁니다.
예를 들어 API를 사용하는 유저에 대한 사용성, 해당 웹을 사용하는 편의성등을 생각해볼만하죠.
배치 처리에서의 사용성은 코드와 관련됩니다.
예를들어 오류 처리, 유지 보수성과 관련이 있습니다.
확장성은 좋은지, 단위 테스트가 잘 마련되는지, Job이 실패할 때 디버깅을 얼마나 빠르게 할 수 있을지가 과제로 떠오릅니다.
✔️ 규모 확장성
Scalability
기존의 웹 애플리케이션에서 사용자의 수를 얼마나 고려하나요?
하루에 100만건의 유저가 사용하는 웹사이트에서 개발을 할 경우가 많을까요?
한 웹 페이지를 불러오는데 8초가 걸린다고 생각해볼게요.
10만 개의 트랜잭션을 처리하는 데 약 9일, 100만 건인 경우 3개월 이상이 소요됩니다.
(8 * 100,000) / (60 * 60 * 24) = 약 9.25 일 , (8 * 1,000,000) / (60 * 60 * 24) = 92.6 일
배치를 사용하는 기업에서 밤새 100만 건 이상의 트랜잭션을 처리하는 배치를 갖고 있는 것은 그리 드문 일은 아닙니다.
이 때도 위와 같이 3개월이 걸리면 문제가 크겠죠 ?
은행 점검하는데 3개월이 걸린다고 생각해보세요 ,,, ㅎ
배치 작업은 대규모 데이터의 적절한 대응을 생각해봐야 합니다.
✔️ 가용성
Availability
웹 애플리케이션의 가용성을 먼저 생각해볼게요.
오류가 났을 때에도 사용자는 서비스를 어쨌든 사용할 수 있게 되어야 합니다.
간단한 오류 화면 띄워주기도 될 수 있겠죠.
배치에서의 가용성은 다릅니다.
배치는 항상everyday 처리되지 않고 대부분은 주어진 시간, 혹은 약속된 지점에 실행됩니다.
필요한 리소스를 언제 사용할 수 있을지, 언제 사용해야 리소스를 효과적이고 장애가 나지 않게 사용하는지를 고려해야합니다.
허용된 시간 내에 Job을 실행하면서 다른 시스템에 영향을 미치지는 않게 할 수 있는지를 고려해야합니다.
✔️ 보안
Security
배치를 사용할 때 해킹에 대해 초점을 맞추지 않습니다.
배치 처리에서의 보안은 데이터를 안전하게 저장하는 것입니다.
데이터베이스의 민감한 데이터를 로그로 남기고 있지는 않는지, 중요 데이터를 암호화해서 저장하는지를 확인해볼 필요가 있죠.
혹은 외부 시스템을 불러올 때 자격증명은 적절히 수행되고 있는지를 확인해야 합니다.
Spring Batch ?
이번 포스팅에서는 배치 프로세스를 위한 애플리케이션인 Spring Batch을 다룹니다.
Spring Batch는 엔터프라이즈 시스템의 일상적인 운영에 필요한 배치 애플리케이션을 쉽게 개발할 수 있도록 설계된 강력한 프레임워크입니다.
로깅/추적, 트랜잭션 관리, 작업 처리 통계, 작업 플로우 지정(작업을 재시작하거나 스킵), 리소스 관리 등 대량의 레코드를 처리하는 데 필수적인 기능을 재사용 가능한 형태로 제공합니다.
여기서 주목할 점은 재사용 가능하다는 점입니다.
한 달에 한 번 필요한 배치 프로세스를 오늘 제작한 후 다음 달에 다시 제작하면 세상 비효율적이겠죠.
또, 스프링 배치는 Java-based configuration이 가능합니다.
XML없이도 POJO 기반 개발 접근 방식으로 개발 가능하는 의미입니다.
Versus
배치 프로세스를 제작하는 방법은 다양합니다.
스프링 배치말고 다른 대안책을 생각해볼 수 있습니다.
가장 많이 사용하는 대안은 Hadoop, Talend, Spring Boot, Apache Spark, Kafka 등이 있습니다.
이에 대한 추가적인 설명보다는 StackShare를 참고하시는 게 이해에 도움이 될 듯 하네요.
종종 Quartz나 스케줄러와 이 Spring Batch를 구분하기 어려워하는 분들이 있는데요.
작은 단위의 데이터를 요구하는 스케줄러만으로 작업이 가능한 범위는 쿼츠만으로 간단한 프로세스를 개발할 수 있죠.
Spring Batch는 스케줄러를 대체하는 개념이 아니라, 스케줄러에 의해 동작될 수 있는 개념입니다.
스케줄러가 트리거가 되어서 제작한 Spring Batch를 동작시키도록 합니다.
Spring Batch Architecture
스프링배치 프레임워크는 자바 배치 표준인 JSR-352(3.0.0 버전부터)을 구현한
일반적인 배치 패턴 및 패러다임을 구현하는 표준 기반 방법입니다.
스프링 배치는 레이어 구조로 조립된 세 개의 티어로 이뤄져 있습니다.
아래에서 보여지는 Application, Core, Infrastructure 레이어(컴포넌트)를 각각 알아보도록 하겠습니다.
Application은 스프링 배치를 사용하는 개발자가 만드는 모든 배치 job과 커스텀 코드를 포함합니다.
Batch Core는 job을 실행하고 제어하는 데 필요한 핵심 런타임 클래스를 포함합니다.
Application
가장 바깥쪽에 Application 레이어가 있습니다.
개발자가 개발하는 배치 처리에 사용되는 코드나 컴포넌트가 이 레이어에 포함되는데요.
다시 말해, 업무 로직이나 서비스, 혹은 잡 구조화와 관련된 내용이 Application 레이어에 포함됩니다.
개발자가 개발하는 대부분의 코드가 Core 레이어와 함게 동작하는 Application 레이어지만,
위의 그림은 종종 Reader나 Writer를 커스텀하여 Core 나 Infrastructure의 일부를 만들기도 하기 때문에,
Core와 Infrastructure를 감싸도록 표현했습니다.
Core
배치 Core 에는 배치 작업을 시작하고 제어하는 데 필요한 핵심 클래스가 포함됩니다.
Job, Step, JobLauncher, JobParameters 구현체가 포함됩니다.
Infrastructure
어떤 처리를 수행하려면 파일, 데이터베이스 등으로부터 읽고 쓸 수 있어야 하겠죠.
또, 잡 수행에 실패한 이후 재시도 될 때 어떤 일을 수행할지를 다룰 수 있어야 합니다.
위 기능을 가능하기 위한 레이어 구조가 Infrastructure 내에 포함됩니다.
애플리케이션 개발자나 코어 프레임워크 자체 두 레이어에서 사용할 수 있는 기능들을 제공합니다.
예를 들어 개발자가 사용할 수 있는 ItemReader and ItemWriter와 같은 Reader나 Writer가 포함되어 있으며,
코어에서 사용할 수 있는 기본 Reader나 Writer와 RetryTemplate과 같은 서비스가 포함됩니다.
Key Concepts
Spring Batch의 배치 작업에서 사용되는 Domain Language를 알아보도록 할게요.
각각의 용어를 알아보기 전, Batch Architecture를 살펴볼게요.
Stereotypes
위 다이어그램은 스프링 배치의 핵심 개념을 도메인 언어로 나타내고 있습니다.
Job은 하나 이상의 Step을 가질 수 있고, 각 Step은 ItemReader, ItemProcessor, ItemWriter를 단 하나씩만을 가지며, 현재 프로세스에서 필요한 메타정보들은 JobRespository에 저장됩니다.
더 크게 보면 아래와 같습니다.
https://www.toptal.com/spring/spring-batch-tutorial
그림이 전체적인 설명을 잘해주고 있네요.
Job
하나 이상의 Step들을 단계 별로 구성한 하나의 배치 작업을 의미합니다.
JobInstance
Job Parameter으로 구분되는 Job의 인스턴스로, 논리적인 Job의 실행을 의미합니다.
참고로, Parameter에는 특정 날짜가 포함될 수 있습니다.
JobExecution들의 모음입니다.
JobExecution
하나의 Job의 실행 시도를 의미합니다.
여기서 '시도' 한다는 의미는 해당 Job의 실행이 진행 중일수도, 성공할 수도, 실패하는 상태를 모두 포함하기 때문입니다.
Spring Batch에서 Job의 상태는 두가지가 있습니다.
✔️ BatchStatus
실행의 상태를 의미하며 아래와 같이 정의됩니다.
package javax.batch.runtime;
public enum BatchStatus {STARTING, STARTED, STOPPING,
STOPPED, FAILED, COMPLETED, ABANDONED }
이 중 JobExecution에서는 아래와 같은 코드를 사용합니다.
BatchStatus.STARTED : 실행중
BatchStatus.FAILED : 실패
BatchStatus.COMPLETED : 성공적으로 종료
✔️ ExitStatus
실행의 결과를 의미합니다.
- UNKNOWN : 알수없음 상태. 더 이상 진행 불가
- EXECUTING : 실행중(이므로 추가 작업이 더 이상 필요없음) 상태.
비동기 실행 시 다른 스레드나 프로세스가 처리중이고 결과를 기다릴 필요가 없을 때 사용
- COMPLETED : 프로세스 종료 상태
- NOOP : 처리되지 않은 작업을 나타내는 상태. (e.g. 이미 실행이 완료된 상태)
- FAILED : 에러와 같이 프로세스가 종료된 상태
- STOPPED : 중단(interruped) 상태로 프로세스가 종료된 상태
여기까지 정리하자면 아래 그림과 같습니다.
Step
하나의 Job에서 실행되는 독립적이고 순차적인 하나의 작업 단위입니다.
데이터를 데이터베이스에 저장하는 간단한 단계일 수도, 혹은 굉장히 복잡한 단계일 수도 있습니다.
StepExecution
JobExecution에 따른 Step의 실행 시도를 의미합니다.
마찬가지로 Step의 실행이 진행 중일수도, 성공할 수도, 실패하는 상태를 모두 포함할 수 있습니다.
Spring Batch에서는 StepExecution의 실행의 상태를 나타내는 Status, 종료 상태를 나타내는 ExitStatus를 가집니다.
JobExecution과 동일하게 아래와 같은 코드를 사용합니다.
BatchStatus.STARTED : 실행중
BatchStatus.FAILED : 실패
BatchStatus.COMPLETED : 성공적으로 종료
여기까지 확인해보면 아래의 그림과 같습니다.
ExecutionContext
ExecutionContext는 StepExecution 또는 JobExecution의 실행 범위에서 상태를 저장하기 위해 프레임워크에 의해 유지하고 관리하는 키/값 쌍의 컬렉션입니다.
예를 들어 파일 데이터를 입력으로 받아 각각의 라인을 처리하는 동안의 상태를 저장한다고 했을 때, 그 커밋 시점을 저장할 수 있습니다. 예기치 못하게 종료되거나 오류가 발생해서 중단되어도, ItemReader가 그 상태를 저장해서 그 시점부터 작업을 재진행할 수 있습니다.
더 자세한 내용은 3장에서 다루겠습니다.
JobRepository
배치 도메인 모델 및 관련 상태를 유지하기 위한 영구 저장소로 주로 데이터베이스를 사용합니다.
Job Repository는 위에서 담은 Stereotypes에서 보이듯이, 전반적으로 사용되는 저장소입니다.
주로 배치 수행과 관련된 시작 시간, 종료 시간, 상태, 읽기/쓰기 횟수 등을 저장하여 대부분의 주요 컴포넌트에서 사용됩니다.
처음 Job Launcher, Job 및 Step을 인스턴스로 제작할 때 사용되는 필요한 데이터를 CRUD 형태로 제공합니다.
JobRepository는 데이터베이스 등의 영구 저장소를 의미하면, ExecutionContext는 용어에서 의미하는 대로 JobExecution이나 StepExecution 실행 범위에서 사용되는 실행 시 저장되는 컨텍스트입니다.
위의 그림은 기본적인 설정으로 생성되는 JobRepository입니다.
이상으로 Spring Batch에 대한 개념 이해를 다뤘습니다.
'Study > 개발일지' 카테고리의 다른 글
[백엔드TIL] Java Comparable과 Comparator의 차이 (1) | 2023.10.11 |
---|---|
[백엔드TIL] 자바와 코틀린의 차이 (0) | 2023.10.10 |
[백엔드TIL] 버블정렬과 삽입정렬 (0) | 2023.10.05 |
[백엔드TIL] 후위식 연산 (0) | 2023.10.04 |
[백엔드TIL] 쿠버네티스 환경에 대해 알아보기 (0) | 2023.09.27 |