ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [우아한테크세미나] 우아한 스프링 배치 후기
    프로그래밍/오늘 공부 2019. 9. 26. 23:30

    우아한 스프링 배치

     

    지난달에 이어서 운 좋게9월 우아한 테크 세미나에도 당첨되어 세미나에 다녀왔습니다.

    취업준비를 할 때 가장 많은 도움을 받은 블로그 이기도 하고, 현재 제가 다니는 회사에 예전에 다니셨다고 하셔서 더 많은 관심이 가는 이동욱님께서 스프링 배치와 관련된 전반적인 개념과 오해들, 또 실무에서의 팁들을 발표해주셨습니다.

    아래 내용은 발표를 들으며 정리한 내용입니다.


    기본 편 - 기본 개념 & 오해 풀기

    배치 애플리케이션?

    • 컴퓨터에서 사람과 상호 작용 없이 이어지는 프로그램 혹은 작업

    • 웹 애플리케이션과는 지향점이 다르다.

      • Web -> 실시간 처리 / 상대적인 속도 / QA가 용이

      • Batch -> 후속 처리 / 절대적인 속도 / QA 복잡 ( 오히려 테스트 코드의 중요성이 더 높음 )

    Spring Batch와 Quartz

    • Quartz는 스케쥴링 프레임워크 ( ex 매일 몇 시에 A를 실행 )

    • 쿼츠는 스프링 배치의 보안제 역할이지 대체제는 아님.

    스프링 배치를 어떠한 상황에 사용할 것인가?

    • 배치가 필요할 때는 일정 주기로 실행되어야 할 때 혹은 실시간 처리가 어려울 정도의 대량의 데이터를 처리할 때

    • 대용량 데이터 처리가 필요한 상황 == 배치가 필요한 상황

    • 스프링 배치에서는 Paging or Cursor기준으로 항상 조회를 함

      • repository.findAll() 절대 사용 X
    • ChunkOrientedTaskletTasklet 의 구현체

      • ChunkOrientedTaskletChunk단위로 구현
      • Tasklet간단한 작업에 사용 ( 로그를 찍는다던가 등등 ...)

    JobParameter

    • @JobParameter @StepParametertasklet에서 메서드로 호출 시 일단 null을 넣고 실행 / 하지만 실제 구동 시에는 파라미터가 들어감.
    • @JobParameter ```는 모두 지원하는 포맷에 제한이 되기 때문에 매번 형 변환이 필요 ( 날짜 같은 경우 )
      • @Value의 특성을 활용해서 JobParameter를 클래스로 따로 빼고 setter에서 주입받고 set 하는 시점에서 형 변환을 해서 적용.
      • 이러한 방식으로 형 변환을 한 번만 해줄 수 있음. ( 현재 내가 진행하는 프로젝트에도 적용하자! )
    • @JobScope, @StepScopeLate Binding 됨.
      • 생성 시점이 애플리케이션 실행 시점이 아니라, Job 혹은 Step이 실행될 때 생성됨.
      • 이를 이용하여 애플리케이션 실행 후에도 동적으로 reader / processor / writerBean 생성이 가능하다.

    활용편 - 실제 업무에서의 팁들

    관리 도구들

    • Cron / API Call / Quartz + Admin / CI Tools ( **Jenkins**, Teamcity 등등...)
      • 스프링 배치 어드민은 deprecated 됐고, Spring Cloud Data Flow로 이전하라고 하는데, 이 선택지는 아직 정보가 많지 않기 때문에 젠킨스 추천
    • 젠킨스로 관리 시 장점
      • 다양한 integration
      • 실행 이력 / 로그 관리 / 대시보드
      • 다양한 실행법 ( REST API / 스케줄 / 매뉴얼 호출 )
      • 계정 별 권한 관리
      • 파이프라인을 이용한 처리
      • 웹과 스크립트 모두 사용 가능
      • 많은 선택지의 Plugin들 ( 직접 만들어서 사용해볼 수도 있음. )
    • 젠킨스에서의 스프링 배치 실행은 커맨드로 등록 가능
      • 각각의 프로파일이나 파라미터는 본인이 등록 가능
    • 모든 배치 실행 시 모든 배치 잡마다 같은 공통 코드가 등록되는 문제가 있음.
      • 이런 문제를 해결하기 위해 젠킨스 설정에서 Global properties를 설정하여 공통 코드를 관리할 수 있다. 환경변수 내에서 다른 환경변수를 물고 있는 하나의 최종적인 환경변수를 생성하여 관리할 수 있음.

    무중단 배포

    • 웹 애플리케이션 같은 경우 대부분 블루/그린 배포 방법을 사용하여 무중단 배포를 구현.
    • 배치 애플리케이션도 무중단 배포가 필요
      • 배치 젠킨스와 배포 젠킨스는 각각 따로 나눠야 함.
      • 기존에 실행되고 있는 배치 jar를 종료하지 않고 배포하는 것이 핵심
      • readlinkln -s 명령어를 활용하여 링크를 변경하는 방식으로 현재 실행 중인 배치에 영향을 끼치지 않고 새로운 배치를 실행시켜줄 수 있음.
      • 이 부분도 공통 설정에 넣어주면 더 편하게 관리 가능.

    파이프 라인

    • 같은 Job인데 파라미터 혹은 스케줄만 다르게 하고 싶을 때? 파이프라인!
    • 여러 Job을 순서대로 실행하지만 가끔은 개별로도 실행이 필요할 때? 파이프라인!
    • 스프링 배치에서 여러 작업을 순차적으로 실행할 때 Step으로 나누기보다는 파이프 라인을 우선 고려!
      • 처음엔 그럴 경우가 없다고 생각하더라도 혹시 이후에 요구사항이 바뀔 수 있으니까 고려해보는 것이 좋음.

    멱등성

    • 연산을 몇 번을 실행하던지 같은 결과를 보여주는 성질
    • 배치에서는 중요한 개념
    • 제어할 수 없는 코드를 직접 생성하는 경우 멱등성이 깨짐.
      • LocalDate.now() 가 대표적인 예임. 오늘 실행과 내일 실행하는 경우가 결과가 달라짐. 이런 경우 이 코드를 수정하고 다시 배포하고 다시 롤백하는 비효율적인 상황을 초래함.
      • 제어할 수 없는 코드 => 제어할 수 있도록 JobParameter로 올리는 것이 미래의 나를 위한 방법...
    • 젠킨스에서는 어떻게 오늘 일자를 보낼 수 있을 까?
      • Date Parameter Plugin이 새로 나왔는데 위에 말한 상황을 해결하게 해 줌!

    테스트 코드

    • ConditionalOnProperty@TestPropertySource 를 사용하여 테스트 코드를 짜는 게 일반적
      • 이렇게 짜다 보니 테스트 코드가 점점 많아지는데.... 정산시스템 같은 경우 1200개 이상이라고 함.
      • 100개가 넘어가다 급격히 느려져서 알고보니, ConditionalOnProperty 가 범인. 프로퍼티가 바뀌니까 자꾸 컨텍스트를 새로 올리고 있었던 거임 ;; ㄴoㄱ
      • @MockBean, @SpyBean , @TestPropertySource, @ConditionalOnProperty 들은 environment가 바뀌면서 컨텍스트가 다시 올라감.
      • 그래서 그냥 처음부터 모든 Config를 로딩한 뒤 원하는 배치 Job BeanapplicationContext.getBean() 으로 찾아서 실행시키기로 했다고 함.
      • 하지만 이런 방법도 트레이드 오프로 빠른 테스트로 빠르게 피드백을 원하는 팀에서는 위와 같이 할수도 있지만, 이런 경우 스프링 컨텍스트가 처음에 한번 올라갈 때 낭비되는 시간이 생길 수 있어서 각 상황에 맞게 팀내에서 잘 결정해야겠다는 말씀을 다른분의 질문에서 답변해주셨다.

    JPA & Spring Batch

    • JPA 쓰는 회사가 많아졌는데 둘이 함께 사용했을 때 이슈가 될만한 내용들이 생각보다 공유가 안되고 있음.
    • JPA N+1문제
      • LazyLoading으로 가져와서 자꾸 쿼리가 비 효율적으로 나가는 것을 말함. ( 프로젝트 할 때 항상 문제 됨... )
      • 이를 해결하기 위해 가장 일반적인게 Join Fetch인데 하위 엔티티가 2개이상일 경우 MultiBagFetchException이 생겨서 문제...
      • 이를 해결하기 위해 또 default_batch_fetch_size 를 설정하면 설정한 값만큼 in절에 설정한 값의 수 만큼 넣어서 조회해서 1000으로 되어있다고 생각했을 때 10000개를 호출하면 10번+1번만 쿼리가 나감.
      • 웹 애플리케이션에서는 이걸로 보통 해결이 되지만 JpaPagingItemReader에서는 이 옵션이 작동이 안되는 문제가 있음.... 😱 Bug라서 직접 PR을 올리셨다고 함. 일단은 대기중...
    • JPA Persist Writer
      • 모든 item에 대해 merge를 수행해서 처음 데이터가 생성될 때도 update 쿼리가 항상 실행되는 문제 발생
      • JPA Persist Writer를 복사하셔서 그대로 복붙하고 중간에 mergepersist 로 바꿔서 사용하고 계신다고 함.
        • 스프링 배치 4.2 에서는 이 persistmerge 를 골라서 사용할 수 있도록 업데이트 될 계획이라고 한다.

    마무리

    • The Definitive Guide to Spring Batch 라는 책이 영문으로 2019.7월 출시 되었음.
    • 내년 상반기에 이 책을 이동욱님과 네이버의 다른 개발자분과 번역해서 출시 예정이라고 함. ㅎㅎ

    후기

    최근 회사에서 스프링 배치를 사용할 일이 있어서 사용해봤었는데, 아무래도 깊게 다룬 건 아니라서 현업에서 실 사용하면서 도움이 될만한 내용을 알고 싶었는데, 이에 대한 점을 많이 알려주셔서 좋았습니다.

    또, 최근 팀내에서 사용할 CI 서버 구축을 위해 젠킨스에 관련해 많이 공부하고 있는데 발표 내용 중에 젠킨스 관련된 내용도 꽤 나와서 많은 공부가 되었습니다. 스프링 배치를 현재 CRON으로 사용하면서 항상 더 나은 방법으로 바꿔야한다고 생각했었는데 이번 기회에 젠킨스 구축하면서, 파이프라인도 적용해보고, 배치용 젠킨스를 하나 더 띄우는 방법도 고려해보면 좋을 것 같다는 생각을 했습니다.

    또한 스프링 배치를 사용하면서 사실 테스트 코드에 소홀한 부분이 있었는데, 발표에서 웹애플리케이션보다도 오히려 배치 애플리케이션이 테스트 코드가 더 중요하다는 말씀을 듣고 테스트 코드를 제대로 짜야겠다는 생각이 들었습니다.

    좋은 발표 해주신 이동욱님 감사드립니다!

    댓글 1

Designed by Tistory.