• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

transaction 구간이 길어질 경우의 처리방법 문의드립니다.

22.05.31 17:52 작성 조회수 655

0

spring batch의 tasklet에서 100만건을 조회하는 상황에서 OOM 발생합니다.

jvm 옵션으로 메모리를 늘리면 되지만, OOM 발생할때마다 늘리는건 아닌거 같아서 다른 해결책을 찾고 있습니다.

paging을 도입해봐도 OOM은 발생했고, 오히려 page가 뒤로 갈수록 느려지는 현상도 발생했었습니다.

native query를 쓰면 OOM도 없어지고, 속도저하도 안생기는것을 확인했습니다.

 

질문1. tasklet의 transaction이 하나라서 JPA가 100만건을 영속성 컨텍스트에 캐시하면서 생긴 이슈가 맞나요?

 

spring batch에서 chunk를 사용하지 않고 tasklet을 쓰면 transaction이 하나로 유지되는걸로 알고 있습니다.

그리고 하나의 transaction 내에서는 JPA의 영속성 컨텍스트가 유지되는걸로 알고 있습니다.

native query의 경우에 영속성 컨텍스트를 사용하지 않기 때문에 문제가 없는게 아닐까 추정을 하고 있습니다.

10만건씩 10회 조회하도록 paging을 도입해봐도 문제가 계속 되는것 봐서는 페이징과 상관없이 영속성 컨텍스트 이슈로 보이는데요, 이 추정이 맞을까요?

 

질문2. paging 도입시 loop가 돌수록 점차 느려지던데 영속성 컨텍스트 때문이 맞을까요?

 

100만건을 한번에 올리는게 무리인거 같아서, 하나의 tasklet 내에서 10만건씩 paging을 도입했습니다.

당연히 이래도 OOM은 났습니다. 근데 페이지가 뒤로 갈수록 점차 느려졌습니다.

건건히 detach를 해주니까 속도저하가 사라졌는데요, 추정하는 원인으로는

"첫루프 = 영속성컨텍스트 0건과 새로운 10만건의 중복 체크

2번째 루프 = 영속성 컨텍스트 10만건과 새로운 10만건의 중복 체크

3번째 루프 = 영속석 컨텍스트 20만건과 새로운 10만건의 중복 체크

..."

이런거 같던데 혹시 이러한 원인이 맞을까요?

 

질문3. paging을 도입하고, entity manager에서 detach를 하면 해결이 되던데 좀더 좋은 방법은 없을까요?

 

한번에 select 해오는 건수를 줄이고 (대략 10만씩 10번 조회), 매 loop에서 em.detach(obj)를 해주고 있습니다.

혹시나 @Transaction(readOnly = true)를 설정해봤는데도 OOM이나, 속도저하는 동일하게 발생하는것 같았습니다.

아무래도 snapshot을 추가로 보관하느냐의 차이일 뿐, 기본적으로 영속성 컨텍스트에 캐시를 해서 그런게 아닐까 추정하고 있습니다.

 

detach는 list나 paging에서는 먹히지 않아서 건건히 detach 해주는게 효율이 좋아보이지도 않았고, 애초에 영속성 컨텍스트에 안올리고 처리를 하면 되지 않을까 했는데요, native query 쓰는법 외에 영속성 컨텍스트에 저장하지 않고 데이터를 가져오는 방법이 있을까요?

 

스프링 배치에서의 이슈라... 질문을 어디에 올릴까 하다가, 스프링을 활용한 프로젝트에서 트랜잭션 내에 대용량 처리라고 생각하여 여기에 글 남깁니다.

답변 1

답변을 작성해보세요.

1

2번에서 "tasklet 내부에 페이징"이라는 말씀이 어떤 것인지 조금 햇갈리지만 아마도 한 트랜잭션 내부에서 페이징을 했다면 1과 2는 동일하게 짐작하신대로 영속성 컨텍스트에 너무 많은 객체가 캐싱되기 때문에 발생한 문제로 보입니다. 제가 스프링 배치를 잘 모르지만, 배치 작업을 페이징 단위에 맞춰서 여러 청크로 쪼개서 구성할 수 있지 않을까요?

유성민님의 프로필

유성민

질문자

2022.06.08

안녕하세요.

 

"tasklet 내부에 페이징"은 백기선님께서 말씀하신게 맞습니다.

 

회사에서 메인프레임을 java로 전환하고 있는데요, 매일 적재되는 수백, 수천만건 row를 스캔해서 테이블 여러군데와 파일 여러군데를 작성해야 하는 상황입니다.

 

청크작업은 write를 한군데에밖에 하지 못해서, 테이블/파일 갯수만큼 테이블을 스캔하다보니 부담이 되어서 이런 구조로 작성하였다가 문제가 발생했습니다.

 

detach나 native query를 쓸때 해결이 되길래 영속성 컨텍스트 이슈려나 했는데, 확신이 없어서 질문을 드리게 되었습니다.

 

답변 주셔서 감사합니다.