요즘 회사에서 배치를 작업하고 있기때문에 영상 내용 정리하기.
출처는,
https://www.youtube.com/watch?v=_nkJkWVH-mo
우아한 스프링 배치
목차
기본편(전반부) - 활용편을 위한 기본 개념 & 오해 풀기
활용편(후반부) - 실제 업무에서의 스프링 배치
[기본편]
배치 애플리케이션?
배치 처리는 컴퓨터에서 사람과 상호 작용 없이 이어지는 프로그램(작업) 들의 실행이다.
- wikipia
- 사용자와의 상호 작용이 주력인 웹 애플리케이션과는 지향점이 다르다.
Web vs Batch
Web - 실시간 처리/ 상대적인 속도/ QA 용이성
Batch - 후속 처리/ 절대적인 속도/ QA 복잡성
상대적으로 Test Code가 더 중요한 곳은 Batch 이다. 상세한 기능까지 통합 QA 하기가 어렵기 때문이다.
Spring Batch 와 Quartz
- Quartz 는 스케줄링 프레임 워크 ex: 매 시간/ 마지막 주 금요일에 실행
- Batch 는 스케줄링이라는 단어를 쓰지 않는다. 스케줄러, API, Cron tab 에서 실행이 되든 실행 뒤에 사용자와 인터랙션 없이 혼자 돌고 있는 애플리케이션이다.
- 결국 Quarzt 는 Spring Batch 의 보안제 역할이지 대체제가 아니다
배치 애플리 케이션이 필요한 상황
- 일정 주기로 실행되어야 할 때
- 실시간 처리가 어려운 대량의 데이터를 처리 할 때
"대량? 매출 같은 경우에는 한 5억건 있고요. 매출 상세 7-8억건, 검색조건에 인덱스를 아무리 태워도 1초내에 응답이 나오지 않아요.
배치가 매 새벽마다, 스케줄링으로 작동되는게 88개, 통계, 집계, 조회 많은 데이터를 캐시하는등 많은 대량의 데이터를 처리하죠"
- 한달에 한번 실행이 된다는 의미는 한달 동안 쌓인 모든 데이터가 대상이라는 의미
- 즉, 대용량 데이터 처리가 절대적인 요구사항
- 스프링 배치에서는 모든 데이터를 메모리에 쌓지 않는 조회 방식이 기본 방식
(DB 기준) Paging 혹은 Cusor 를 PageSize 만큼만 읽어오고 chunkSize 만큼만 Commit 한다
Spring batch에서는 chunk size 를 commit size 와 동일시 하여 예) 만건씩만 커밋한다. 라는 방식으로 프레임 워크에서 지원이 된다. jpaRepository.findAll() 방식으로 진행해선 안됩니다!
Job/ Step/ TaskLet 등등
- 보통, Reader Processor writer 과 Tasklet 은 전혀 다른 객체라고 생각하지만 실제로 stepBuilderFactory 의 reader, processor, wirter 는 chunkOrientedTasklet, chunkOrientedTasklet 은 Tasklet 의 구현체이다.
- chunkOrientedTasklet 은 니가 reader, processor, writer 넣으면 내가 tasklet 으로 만들어 주겠다.
- 그냥 Tasklet 은 간단하게 사용하고 싶을때 쓴다고 생각하면 된다.
- Tasklet 은 간단한 로그를 찍거나 Validation 로직을 짤때 주로 사용된다.
- 결과적으로, 둘이 서로 다른 개념은 아니다.
@JobScope
@StepScope
JobParameter
JobParameter
- Spring Batch는 외부에서 파라미터를 주입받아 Batch 컴포넌트에서 사용 할 수 있다. 이를 JobParameter 라고 한다.
사용법 : @Value('#{jobParameters[파라미터명]}") 타입 이름
- Step 에서 사용하려면 @JobScope 를 적어줘야 한다. .start(step(null)) -> 실제 실행할때는 외부에서 파라미터를 주입 받는다.
- Step 의 하위 개념인 reader, Processor, wirter, Tasklet 의 함수에는 @StepScope 를 넣어줘야 한다.
.tasklet(scopeStep2Tasklet(null)
- <약간의 문제>
- Spring Batch의 jobParameter 는 Long / String/ Double / Date 타입들을 모두 지원한다.
- Enum / LocalDate / LocalDateTime 은 지원 안된다.
보통 String 으로 받은뒤에 형변환 한다.
LocalDate startDate = LocalDateUtils.toLocalDate(targetStartDate);
LocalDate endDate = LocalDateUtils.toLocalDate(targetEndDate);
매번 귀찮다! 해결 방안,
@Value의 특성을 이용하자
value 는 파라미터가 아닌 어노테이션에도 사용 가능 하다.
23분,, 다시보기
Late Binding
@JobScope @StepScope 는 Late Binding (늦은 할당)
보통의 빈은 application 실행 시점에 환경변수를 모두 끌고 와서 처음으로 Singleton 빈을 만든다. 그걸로 DI 받아서 사용하는데
@JobScope 는 Job이 실행될때
@StepScope 는 Step이 실행 될때 Bean이 생성된다. (애플리케이션 실행 시점이 아님)
애플리케이션 실행 후에도 동적으로 reader / processor / writer bean 생성이 가능하다.
이것을 가지고 활용할 수 있는 방안이 있다.
예를 들면, JobParameter 값에 따라 Reader 와 Processor 를 교체
26..
[활용편]
관리 도구들
Cron (리눅스로 jar 실행)
Spring MVC + API Call (Spring mvc 로 rest Api 구현하고 내부에서 스프링 배치 실행 - 제일 안좋은 방법)
Spring Batch Admin(Deprecated, Spring Cloud Data Flow 로 이전하라 하지만 정보 별로 없음 )
Quartz + Admin (Quartz 를 가지고 admin 만들기, 거기에 나만의 UI 로 붙여서 관리)
Ci Tools (Jenkins / Teamcity 등등)
Jenkins 를 추천한다!
Jenkins 의 장점
1. Integration (Slack. Email 등)
2. 실행 이력/ 로그 관리 / Dashboard
3. 다양한 실행 방법(Rest API/ 스케줄링/ 수동 실행)
4. 계정 별 권한 관리
5. 파이프 라인
6. Web UI + Script 둘다 사용 가능
7. Plugin (Ansible , Github, Logentries 등)
젠킨스에서 스프링 배치를 실행 하는 방법
일반적인 배치 Jar 실행 명령어 (-job.name은 스프링 환경 변수)
java -jar Application.jar \
--job.name = job이름 \
job파라미터이름1=job파라미터값1\
job파라미터이름2=job파라미터값2\
실제 execute shell 내용
java -jar \
-Dspring.profiles.active=beta \
${BATCH_JAR_HOME}/settler-batch.jar \
--job.name=adAccruedBatch \
baseDate=${baseDae} \
version=${VERSION}
이렇게 할경우 문제가 하나 생긴다.
Jenkins 공통 설정 관리 : 모든 Batch Job에서 중복 사용되는 코드가 있다.
java -jar \
-XX:+UseG1GC \
-Dspring.profiles.active=dev \
Application.jar \ 모든 Batch Job의 공통 코드이다. 기본 GC가 Default 가 아니다?
--job.name=job이름 \
job파라미터이름1=job파라미터값1\
job파라미터이름2=job파라미터값2\
만약 jar 파일 위치를 변경한다? 그럼 리눅스에 스크립트 짜서 일괄로 변경 하거니
쉘 스크립트를 직접 다 수정해야한다.
아무튼 말하고 싶은건 Jenkins 에서 공통 설정 코드가 있을텐데 이것들을 다 개별로 등록을 해야하나?
라는 것이다. 이때 사용할 수 있는것
Global properties - Enviroment variables 를 사용하자!
내부에서도 사용 가능하다. Enviroment Variables 변수들끼리도 호출 가능하다.
변수들 끼리호출하고 최종 변수만 넣어 두면 되니 아래 처럼 수정할수 있다.
java -jar \
$BATCH_JAR \
--job.name=job이름 \
job파라미터이름1=job파라미터값1\
job파라미터이름2=job파라미터값2\
- 환경 변수는 $변수명 / ${변수명} 으로 사용할 수 있다.
무중단 배포 40:00