스프링 배치 개선하기 정리

2024. 9. 10. 22:51·개발/Spring Batch
반응형

스프링 배치 성능에 관한 아래 두 영상을 간략하게 정리한 글입니다.

 

Batch Performance 극한으로 끌어올리기

https://www.youtube.com/watch?v=2IIwQDIi3ys&t=589s

Spring Batch 애플리케이션 성능 향상을 위한 주요 팁

https://www.youtube.com/watch?v=VSwWHHkdQI4&t=1011s

 

 

Batch Performance 극한으로 끌어올리기 영상 정리

대량 데이터 READ

  • batch 성능 개선에서 제일 중요한 것은 Reader를 개선하는 것이다.
  • 일반적으로 Read의 복잡한 조건으로 인해 Write보다 성능의 더 큰 영향을 받는다.
  • 읽을 때 항상 Chunk 프로세싱이다. 예를 들어 천 만개를 1000개씩 나누어 1만번 처리한다.
  • JpaPagingItemReader, RepositoryItemReader는 대량 처리에 매우 부적합하다.
  • Limit Offset이 가지는 태생적인 한계 때문이다. Offset은 커질수록 느려지기 때문
  • 영상에서 ZeroOffsetItemReader를 도입함. pk를 기준으로 정렬하여 데이터를 가져온다. 무한 스크롤 방식과 비슷
  • 즉 limit offset이 아니라 cursor 방식을 활용하면 된다.
  • JpaCursorItemReader는 활용할 수 없다. 데이터를 모두 읽고 서버에서 직접 커서하는 방식이라 OOM을 유발할 수 있다.
  • JdbcCursorItemReader, HibernateCursorItemReader을 활용할 수 있다. MySQL의 Cursor를 활용하여 일정 개수만큼 Fetch하는 방식이라 안전하다.
  • 다들 Jdbc를 자주 사용하나 타입 안전성과 세련된 방식으로 Exposed를 제시.
  • 배치 모니터링에서 Querydsl, Exposed를 사용한 Reader가 안정적인 모습을 보인다.

 

 

결론

  • cursor 방식을 사용하자.
  • offset 방식이 아닌 cursor를 활용하자.
  • 타입 안정성을 원하면 Kotlin에서는 Querydsl, Exposed를 활용할 수 있고 Java는 Querydsl 을 활용하자.

 

데이터 Aggregation 처리

  • 통계를 만들 때 배치로 개발한다면 group by와 sum을 활용한 쿼리를 생각한다.
  • 위 사고 방식은 데이터가 적을 때는 합리적인 방식이지만 데이터가 많아지면 그렇지 않다.
  • 여러 테이블을 조인하고 group by하면 잘못된 실행 계획이 등장하며, 쿼리 튜닝이 까다로워진다.
  • join, group by, sum을 활용한 쿼리를 사용하면 아래와 같은 문제가 생긴다.
    • 연산 과정이 쿼리에 의존적이라 DB 부하가 증가한다.
    • 데이터 누적으로 인해 데이터 중복도(카디널리티)가 변경되고 쿼리 실행 계획이 변경되면서 쿼리 튜닝 난이도가 증가한다.
    • 쿼리 튜닝을 위한 과도한 인덱스를 추가하며 저장 용량이 증가하고 결국 insert, update 속도가 느려진다.
  • 결론은 Group By와 Sum을 포기하고 애플리케이션에서 Aggregation을 진행하는 방식을 채택
  • 그러나 애플리케이션에서 50만 개의 데이터를 위한 메모리 할당은 불가능하다. OOM이 발생할 수 있다.
  • 결론은 새로운 아키텍쳐가 필요한데, 이는 Redis를 활용하는 방식
    • 천만 개의 데이터를 1000개로 나누어 만 개의 청크를 만든다.
    • sum 연산 요청을 통해 redis가 sum 연산을 진행
    • 반복해서 합산을 진행하면 레디스에 50만개의 데이터가 들어가고
    • 이를 데이터 최종 저장소에 반영한다.

  • Aggregation Tool로 Redis를 선택한 이유
    • 연산 명령어 지원(메모리 수준에서 합산)
    • 50만개를 저장할 수 있는 넉넉한 메모리. 보통 수십 기가바이트에서 수백 기가바이트로 레디스를 구축한다.
    • 인메모리 데이터베이스이므로 빠른 저장이 가능하기 때문(영구 저장 X)
  • Redis를 도입해도 해결되지 않는 문제
    • 네트워킹의 레이턴시는 해결되지 않음
    • 1000만번 sum 요청은 1000만번의 네트워크 I/O와 같다
    • 요청 한 번당 1ms * 1000만번이면 3시간이다.
    • Redis Pipeline으로 처리해서 이 문제를 해결했다.
    • Redis Pipeline은 다수의 커맨드를 한 번에 묶어서 처리할 수 있는 방식이다.
    • 한 개의 청크에서 한번씩 연산 요청을 해 천만번의 네트워킹을 만 번으로 줄여서 어그리게이션을 진행
    • Spring Data Redis에서는 Redis Pipeline을 지원하지 않아 별도 라이브러리를 개발

대량 Write

  • Read할 때부터 Projection을 사용해 더티체킹을 사용 X (더티체킹과 영속성은 배치 insert에서 성능 저하가 크므로 사용 X, 큰 성능 저하)
  • update할 때 불필요한 컬럼도 update하면 동적 쿼리를 생성하므로 Dynamic Upate 사용 X (소폭 성능 저하)
  • JPA도 Batch Insert를 지원하지만 ID 전략을 IDENTITY로 하게 되면, JPA 사상과 맞지 않으므로 Batch Insert를 지원하지 않는다. (큰 성능 저하)
  • Batch Insert를 반드시 사용해야한다.
  • JPA를사용하지 않고 batch i
  • nsert(JDBC), Exposed Batch Insert를 추천

Batch 구동 환경

  • Batch  Tool로 크론탭, 젠킨스, 에어 플로우, 루이지 등의 환경을 떠올릴 수 있다.
    • Batch 스케쥴Toole은 실행 요청, 스케줄, 배치 관리, 워크 플로우 관리, 모니터링, 히스토리 관리와 같은 일을 수행
  • 기존 Toole의 아쉬운점
    • 자원 관리의 어려움
    • 배치 상태 파악의 어려움
      • 배치에서는 동작 하나하나가 매우 깊다.
      • 대부분 스케쥴 Toole에서는 로그를 볼 수 있지만 로그 정보가 매우 빈약
      • 서비스 상태를 로그로 판단하는 것은 전혀 시각적이지 않음
    • 스프링 클라우드 데이터 플로우를 도입함
      • 데이터 수집, 분석, 데이터 입/출력과 같은 데이터 파이프라인을 만들고 오케스트레이션
      • 데이터 파이프라인 종료(스트림, task(batch))
    • 오케스트레이션 (k8s와 완벽한 연동으로 batch 실행 오케스트레이션)
    • 모니터링 스프링 배치와 완벽한 호환을 통해 유용한 정보 시각적으로 모니터링

 

Spring Batch 애플리케이션 성능 향상을 위한 주요 팁

첫 번째 방법

  • Processor에서 외부 API 조회를 진행함 (응답 속도 150ms)
  • Processor에서는 요소들을 단건으로 처리하기 때문에 Chunk Size만큼 Network I/O가 발생하고 대기하니 느려질 수 밖에 없다.
  • 개선을 위해 프로세서 구간을 제거하고 등급 조회 API를 Bulk로 처리하는 것으로 수정
  • Bulk 처리는 Network I/O를 멀티 스데르 기반으로 처리했다는 의미 (RX 기반 멀티스레드로 병렬 처리)
  • 단순히 멀티 스레드를 늘린다고 성능이 증가하는 것은 아님

두 번째 방법

  • 단건 update를 in절을 활용해 I/O를 최소화함. (in update)
  • in절을 활용한 업데이트가 불가능한 상황이 발생
    • Jdbc Execute Batch를 활용
    • 쿼리 여러개를 한번에 묶어서 전송

  • Exposed 기반 Execute Batch를 활용해서 해결이 가능함

 

이상으로 포스팅을 마칩니다.

반응형
'개발/Spring Batch' 카테고리의 다른 글
  • Chunk Process
  • FlowJob
  • 스프링 배치 핵심 도메인 기초
Debin
Debin
공부 기록을 남기며 게시글 리팩토링을 진행하는 블로그입니다.
  • Debin
    리팩토링하는 블로그
    Debin
  • 전체
    오늘
    어제
    • 분류 전체보기
      • DB
        • DB 기초
        • MySQL
        • SQL 튜닝
      • OS
      • Network
      • Git
      • 디지털콘텐츠기획
      • 소프트웨어공학
      • 코딩테스트
        • 프로그래머스
        • 백준
        • 인프런
      • 공부 일지
      • 독서
        • 클린코드
        • 일상 속 사물이 알려주는 웹 API 디자인
        • 토비의 스프링
        • 객체지향의 사실과 오해
        • 자바 잘 읽는 법
      • 기록 및 회고
      • Cloud
        • AWS
      • 개발
        • Java
        • Spring Core
        • Spring MVC
        • Spring DB
        • Spring Boot
        • Spring Security
        • Spring Batch
        • JPA
        • Test
        • Android
      • 대외활동
        • UMC SERVER
        • 카엔프 SW 아카데미
      • 프로젝트
      • Docker
      • Gradle
      • ELK
      • 실무 이야기
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
  • 공지사항

    • 본인 깃허브입니다!
  • 인기 글

  • 태그

    ORM
    SQL
    운영체제
    도커
    redis
    프록시
    spring mvc
    AWS
    JPA
    컨테이너
    spring boot
    객체
    container
    객체지향
    Java
    innodb
    test
    스프링
    트랜잭션
    spring
    mysql
    토비의 스프링
    인덱스
    자바
    docker
    데이터베이스
    스프링 부트
    AOP
    리눅스
    코딩 #개발자 #노마드북클럽 #노개북
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
Debin
스프링 배치 개선하기 정리
상단으로

티스토리툴바