스프링 배치 개선하기 정리

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
      • 실무 이야기
  • 블로그 메뉴

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

    • 깃허브
  • 공지사항

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

  • 태그

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

  • 최근 글

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

티스토리툴바