> For the complete documentation index, see [llms.txt](https://real-dev.gitbook.io/real-library/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://real-dev.gitbook.io/real-library/spring-batch/readme/2..md).

# 2. 스프링 배치

<br>

### 배치 아키텍처

* 애플리케이션 레이어: 개발자가 개발한 영역
* 코어 레이어: 배치 영역을 구성하는 실제적인 컴포넌트로 이뤄진 영역
* 인프라스트럭처 레이어: ItemReader, ItemWiter를 비롯해 재시작과 관련 문제를 해결할 수 있는 클래스, 인터페이스 영역

<br>

### 잡과 스텝

* 스프링 배치 잡은 상태 기계에 지나지 않는다. 다수의 스텝을 포함하는 묶음으로서의 역할만 있을 뿐
* 실제적인 동작은 스텝에서 이뤄진다. 스텝의 종류는 크게 두 가지로 간단한 태스클릿과 좀 더 복잡한 청크 기반 스텝이 있다.
* 태스클릿은 `execute()`메서드를 계속해서 반복하고, 매번 새로운 트랜잭션으로 관리한다.
* 청크 기반은 `ItemReader, Processor, Writer`로 구성되며, 청크 단위별로 트랜잭션을 관리한다. 이 중 `ItemProcessor`는 포함되지 않을 수도 있다. (마이그레이션에선 리더랑 라이터만 있어도 되기 때문)
* 이런 구조의 장점은 각 스텝이 서로 독립적으로 처리될 수 있도록 분리한 점이다. 낮은 결합성은 대체로 옳다.
* 스텝 또한 스프링 빈으로 관리되므로, 재사용이 간단하다.

<br>

### 잡 실행

* `JobRepository`는 스프링 배치 아키텍처 내부에서 공유되는 컴포넌트다. 해당 컴포넌트에서 잡의 상태와 배치 수행에 관련된 여러 수치 데이터 (시작시간, 종료시간, 읽기/쓰기 횟수 등)를 관리한다.
* `JobRepository`는 DB를 사용하여 스프링 배치 내의 대부분의 주요 컴포넌트가 공유한다.
* `JobLauncher`는 잡의 실행을 담당한다. 얘가 Job.execute를 실행함. + 잡의 재실행 여부를 검증하고, 잡의 실행 방법 (기존 스레드 혹은 신규스레드에서 작동), 파라미터 유효성 검증 등의 처리를 수행한다.
  * 단 스프링 부트를 사용하면, 스프링 부트가 즉시 잡을 실행하는 기능을 제공해서 일반적으론 다루지 않는다.
* 잡이 실행되면, 그 안에 포함된 스텝들이 실행된다. 각 스텝이 실행되면 `JobRepository`는 현재상태로 갱신된다. 즉 실행된 스텝, 현재 상태, 읽은 아이템 및 처리된 아이템 수 등이 모두 `JobRepository`에 기록된다.
* 여러 아이템으로 이뤄진 청크의 처리가 스텝 내에서 완료되면 `JobRepository` 안에 있는 `StepExecution`이나 `JobExecution`이 최종 상태로 업데이트된다.
* `JobInstance`는 스프링 배치 잡의 논리적인 실행 단위다. 어떤 역할이냐면 딱 `JobName+JobParameter`로 엮어서 유니크한 식별자 역할. 때문에 동일한 잡+동일한 파라미터 조합이면 해당 잡이 다시 실행되더라도, `JobInstance`가 새로 생성되지 않는다. 이 경우 새로운 `JobExecution`만 생성된다.
* StepExecution은 실제 스텝의 실행 자체를 의미하고, StepInstance는 존재하지 않는다. 보통 하나의 JobExecution이 여러 개의 StepExecution을 포함한다.

<br>

### 병렬처리

~~솔직히 이 파트는 이해 못했다. 일단 굵직한 내용들만 보고 추후 실습과 함께 이해해보도록 하자. 못할수도 있지… 나중엔 이해할거야…~~

* 다중 스레드 스텝
  * 청크 단위 별로 스레드를 분할하여 멀티 스레드 방식으로 구동하는 방법.
* 병렬 스텝
  * 스텝 자체를 병렬로 실행하는 방법. 하나의 잡에 포함된 다수의 스텝이 딱히 상관 관계가 없을 경우 이를 동시에 수행하고, 모든 병렬 스텝이 완료되었을 때 다음 스텝으로 넘어가는 방식
* 비동기 ItemProcessor/ItemWriter
  * 스탭 내의 ItemProcessor에서 병목을 유발할 수 있는데, 이런 일부 스텝을 병렬화하는 기능. `SynchronousItemProcessor`는 동기식으로 `AsynchronousItemProcessor`는 비동기적으로 스텝을 수행하게 해준다. 후자는 `Future` 객체를 반환하고, `AsynchronousItemWriter`로 전달되어 작업이 종료된 이후 수행된다.

<br>

**처리 일부분을 여러 JVM으로 분산하여 수평 확장을 가능하게 하는 방식**

* 원격 청킹
  * 입력은 마스터 노드에서 표준 ItemReader를 사용해서 이뤄지며, RebbitMQ같은 메시지 큐를 이용해 메시지 기반 POJO로 구성된 원격 워커 ItemProcessor로 전송된다. 이게 뭐라는거지 젠장. 워커는 스프링 배치 컴포넌트인가 아니면 메시지큐의 일부분인가…
  * 마스터에서 데이터를 읽고, 원격 워커에서 처리한 다음 다시 마스터로 전송하므로 네트워크 비용이 커지는 단점이 있다.
* 파티셔닝

  * 마스터가 워커의 스텝 수집을 위한 컨트롤러 역할을 하고, 여러 워커에서 마스터로부터 일을 전달받아 수행하는 방식. 워커의 스텝은 독립적으로 동작하고, 로컬에서처럼 돌아가지만 워커의 스텝이 잡이 아닌 마스터 노드로부터 전달받는 점.
  * 솔직히 이해는 못하겠지만, 원격 청킹에 비해 복제된 작업이 없고, 모든 작업이 완료되었음이 보장되므로 내구성 있는 지속적인 통신이 불필요하다.

  <br>

<br>
