본문 바로가기

카테고리 없음

[Log] 우아한 스프링 배치 by 우아한 형제들 이동욱님

요즘 회사에서 배치를 작업하고 있기때문에 영상 내용 정리하기. 

출처는,

 

 

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 등등

 

https://www.youtube.com/watch?v=_nkJkWVH-mo

- 보통, 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

반응형