HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
✍🏻
Learnary (learn - diary)
/Batch/
Spring Batch with OpenAPI, Feign

Spring Batch with OpenAPI, Feign

목표: 데이터 적재 및 데이터 변경에 능동적으로 대응하기 with SpringBatch초기 문제점(설계)2번쨰 문제점(구현)멀티쓰레드 기준으로 병렬성 생각해보기다중 서버 생각하기 with 분산락
 

목표: 데이터 적재 및 데이터 변경에 능동적으로 대응하기 with SpringBatch

  • 초기: 오픈 API로 데이터를 적재
  • 초기 이후
    • 일정 별로 데이터는 중복해서 가지고 잇되 최신화 된 데이터 여부를 확인하기 위해 꾸준히 적재
    • 오늘 날짜 기준으로 있는 것들만 데이터 보여주기 위해서
    •  
       
왜 이런 목표를 잡아야 하는지?
  • 오픈 API의 데이터는 기존에 있던 데이터가 없어질 수도 수정될 수도 새로 추가될 수 있기 때문이다.
  • 변경에 능동적으로 대응하기 위해서 필요했다.
 
 
Batch의 처리방식의 핵심은 3가지의 Step으로 진행된다.
  • Reader → Procssor → Writer
 

초기 문제점(설계)

  • Reader에서 데이터를 읽어오는데 open api로 데이터를 1개씩 가져와 처리한다.(Critical)
 
네트워크 자원을 활용하여 데이터를 가져오는데 1개씩 가져온다.
Batch 차원에서는 이전 파일 시스템 처럼 한줄 한줄 하나의 레코드 단위로 취급하는 것은 그래도 괜찮았다고 생각하지만 이번에는 네트워크를 열었다 닫았다 하면서 하기에는 TCP OverHead 때문에 성능이 오히려 나빠질 수 있다고 생각했다.
 
그래서 일정량의 데이터들을 가져와 Batch로 처리하고자 했다.
 

2번쨰 문제점(구현)

내가 하고자하는 것: Bulk insert로 데이터 적재하기 - Jdbc Bulk 연산이 더욱 JPA보다 성능향상을 꾀할 수 있기 때문이다. 하지만 Entity 스펙에 유연하게 대응하지 못하는 것은 좋지 못하지만 그래도 많은 데이터 양과 작업수를 고려했을때, 성능이 좋아야 한다고 생각했다.
 
 
  • ItemWriter의 구현체인 JDBCBatchItemWriter
    • notion image
 
  • BatchConfigure
@Bean public JdbcBatchItemWriter<List<Spot>> jdbcBatchItemWriter(DataSource dataSource) { return new JdbcBatchItemWriterBuilder<List<Spot>>() .dataSource(dataSource) .sql(PublicDataSql) .beanMapped() .build(); }
 
  1. reader에서 List형식을 반환
  1. proccessor에서 Entity 형식의 List 로 가공
  1. List 바로 Bulk Insert
 
되기를 기대했지만, 3번에서 Invalid Bad SqlGrammerException이 발생했다.
 
이부분을 해결하기 위해, 공식문서를 찾아보았지만, 예제가 없었다.. 그리고 StackOverFlow에서도 해결책은 없고.. 이렇더라 이야기만 있을 뿐이다.
 
불가능한건가. 라고 생각했는데 국내 자료 중에 JpaItemWriter를 처리하는 방법이 있기는 해서 여기서 가능성을 보았다.
Spring Batch ItemWriter에 List 전달하기
안녕하세요? 이번 시간엔 springboot-batch에서 writer에 List를 전달하는 예제를 진행해보려고 합니다. 모든 코드는 Github에 있기 때문에 함께 보시면 더 이해하기 쉬우실 것 같습니다. (공부한 내용을 정리하는 Github와 세미나+책 후기를 정리하는 Github, 이 모든 내용을 담고 있는 블로그가 있습니다. ) 문제상황정산과 관련된 프로젝트를 진행 중, Sales 데이터를 파싱하여 Tax 데이터를 저장하는 spring batch를 만들어야 한다고 가정하겠습니다. 예를 들어 A Sales가 조회되면 이를 파싱하여 Tax1,Tax2,Tax3으로 저장되어야 합니다. 그럼 간단하게 batch configuration을 작성하겠습니다.특별할것이 없는 코드입니다. 저 같은 경우엔 ItemW..
Spring Batch ItemWriter에 List 전달하기
https://jojoldu.tistory.com/140
Spring Batch ItemWriter에 List 전달하기
 
그래서 이부분을 커스텀 하였지만 버전이 많이 예전 버전같다. 나는 5.1.2 버전이라 예외가 발생하는 부분이 많았다.
어쨋든 이 부분도 분명 가능할 거라 생각했다.
notion image
 
SimpleChunkProcessor 라는 구현체에서 “데코레이터 패턴”으로 구현되는 것을 확인했다.
notion image
 
예외 구간이 여기에서 발생하는 것 또한 확인했다.
notion image
 
처음에는 PrePareStateMent 쪽 에서 sql을 잘못생성할 거라고 생각해서 들어갔더니
List안에 내가 가져온 List<Spot> 이 중첩으로 처리되고 있었다.
그래서 items ….. 이렇게 돌면서 sql을 만드는 데 처음부터 items → 200개의 데이터가 담긴 List가 있어 처리하지 못해서 BadSql Grammer Exception이 발생했다.
 
JdbcBatchItemWriter 구현체의 writer 메서드를 보면 하나의 Chunk 타입의 객체로 처리하였고 이부분을 재이용하기로 했다.
notion image
우선 Proccsor에서 넘겨받은 객체가 Chunk 타입이고 그 안에 Items가 여러개 있지만 첫번째 인덱스에 내가 open api로 호출한 200개의 데이터가 있었다.
 
그래서 여기에서 가져와 한개씩 JdbcBatchItemWriter.write() 메소드를 청크단위로 감싸서 쓰도록 의도했더니 성공했다.
package com.example.batch.writer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.item.Chunk; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.database.JdbcBatchItemWriter; import java.util.List; public class PublicDataWriter<T> implements ItemWriter<List<T>> { private static final Logger log = LoggerFactory.getLogger(PublicDataWriter.class); private final JdbcBatchItemWriter<T> jdbcBatchItemWriter; public PublicDataWriter(JdbcBatchItemWriter<T> jdbcBatchItemWriter) { this.jdbcBatchItemWriter = jdbcBatchItemWriter; } @Override public void write(Chunk<? extends List<T>> chunk) throws Exception { log.info("PublicDataWriter -> write call -> {}", chunk); for (List<T> ts : chunk) { jdbcBatchItemWriter.write(new Chunk<>(ts)); } log.info("============= [END] PublicDataWriter -> write call =============== "); } }
 
 

멀티쓰레드 기준으로 병렬성 생각해보기


  • 이 배치 작업이 멀티스레드로 동시에 처리될떄 어떻게 해야할지 고민해봤다.
 
페이지 정보들은 절대로 공유되서는 안되기도 하고 Reader는 페이지 정보를 알아야했다.
동시적으로 같은 데이터 목록을 접근해서는 적재하면 안되기 때문에 그래서 Reader 인스턴스는 싱글톤이 아니도록 하는것이 핵심이다라고 생각했다.
 
@StepScope ⇒ 로 Reader 부분만 따로 가져가면 page No [1 - N] 다른 Reader들을 생성하고 나머지 processor, writer 는 공유한다.
 
이러면 같은 데이터 목록에 접근하여 중복하여 데이터를 적재하는 부분을 해결할 수 있었다.
notion image

다중 서버 생각하기 with 분산락