ultra_dev
스프링 배치 - 3편 (간단한 성능 개선기, JPA) 본문
<상황>
프로젝트 내 스프링 배치에서 특정 상태를 바꿔주는 코드가 있다.
특정 날짜가 지난 게시글들을 만료 처리하는 배치코드이다.
백엔드 서버가 JPA로 구성돼 있으므로 스프링 배치도 동일한 기술 스택을 유지하기 위해 JPA를 선택했다.
일관된 기술 스택을 사용하여 코드 개발, 유지보수에 도움이 되고, 컴파일 시점에 에러를 잡을 수 있는 등 다양한 장점이 있기 때문이다.
<문제점>
아이템라이터에서 아이템 업데이트를 더티체킹 방식으로 하다보니, 청크사이즈만큼 아이템이 있다고 해도
각 엔티티마다 개별적으로 업데이트 쿼리가 나가서 데이터베이스 부하가 커지는 문제가 생겼다.
<해결>
이에 따라 문제를 해결하기 위해 각 아이템을 모아서 한번에 업데이트 하는 방식으로 코드를 변경했다.
즉 만료 처리할 게시글들을 모아서 IN 절로 한번에 벌크 업데이트 처리를 하게 바꿨다.
이렇게 함으로써 엔티티마다 발생하던 여러 번의 업데이트 쿼리를 한 번의 쿼리로 처리할 수 있었고, 데이터베이스 부하를 줄이고 효율적인 배치 처리가 가능해졌다. 청크 사이즈만큼 모으기 때문에 과도한 부하가 걸릴 일도 없다.
<단순 예시코드>
@Override
public void write(Chunk<? extends Post> chunk) throws Exception {
// id들을 그룹화
List<String> postIds = chunk.getItems().stream().map(Post::getId).toList();
// 벌크 업데이트
int updatedRows = postRepository.bulkUpdatePostStatusByIds(postIds, PostStatus.EXPIRED);
System.out.println("업데이트된 행 수: " + updatedRows);
}
}
만약 위의 경우라면 Spring Data Jpa Repository에는 아래와 같이 돼있을 것이다.
@Modifying
@Query("UPDATE Post p SET p.status = :status WHERE p.id IN :postIds")
int bulkUpdatePostStatusByIds(List<Long> postIds, PostStatus status);
* 여기서 벌크성 쿼리를 날리는데 왜
@Modifying(clearAutomatically = true) 와 같이 영속성컨텍스트를 초기화 하는 작업을 안해주는지 의문점이 생길 수도 있다.
스프링 배치는 보통 대용량 작업에 사용하고,
아이템 라이터는 작업의 끝부분이다.
위의 쿼리 이후 추가 작업이 없는데 굳이 영속성 컨텍스트를 초기화하는 불필요한 작업으로 추가 부하를 줄 필요는 없다고 판단했다.
'SPRING&JAVA' 카테고리의 다른 글
Amazon SQS와 Lambda를 활용한 서버리스 활용 및 성능 개선기(feat. 람다에서 비동기 코드 사용시 주의하기) (0) | 2024.04.05 |
---|---|
스프링 배치 - 2편(DB) (0) | 2024.03.25 |
스프링 배치 - 1편 (0) | 2024.03.18 |
Jenkins & Docker를 활용한 CI/CD(Mac os 기준) (0) | 2024.02.28 |
AOP, Custom Annotation 활용기 (0) | 2023.11.07 |