Overcoming the Out of Memory Problem in Spring Data JPA Streaming
많은 양의 데이터를 가져오는 전통적인 방법
1. 모든 데이터를 메모리에 한번에 올리기
대부분의 중소 규모의 데이터베이스에서는 이것이 정석적인 방법이다. 그냥 모든 데이터를 메모리 상에 올리고, relation에 대해서는 lazy loading 하고.
그러나 백만 단위의 데이터를 갖고 있는 대규모의 데이터베이스에 대해서는 모든 데이터를 메모리 상에 올리게 되면 OOM 예외가 발생하게 된다. 그러한 경우 분산 캐시 시스템을 사용하는 것이 합리적이다. 그러나 그냥 A 소스에서 데이터를 다 읽어서 다른 소스에 넣는 경우라면, 데이터를 한번만 읽을 것이기에 캐시가 적합하지 않을 수 있다.
2. 페이징 사용하기
OOM 문제에 대한 해소법은 페이지네이션이다.
limit
과 offset
을 활용하여 페이지에서 많은 데이터를 읽을 수 있다.그러나 이방식에서 명심해야 할 것은 총 페이지의 개수를 알기 위해서는 추가적인 비용이 든다는 것이다. 각 페이지에 대해 데이터를 가져올 때, 추가적인 count query를 통해 전체 페이지를 계산해야 한다. 이것이 프로세스를 상당히 크게 느리게 만들 수 있다. 속도를 높이기 위해서는 return type을
Slice
로 바꾸면 된다.(이 방식을 사용하면 extra query가 발생하지 않음)또 다른 문제는 페이지네이션이 대규모의 데이터베이스에 대해서 큰 단점을 갖고 있다는 것. 시간이 지날 수록 데이터를 조회해오는 속도가 느려진다. 그 이유는 데이터베이스에서 쿼리의 데이터를 반환할때 더 큰 offset의 값을 처리하는 것이 긴 시간이 걸리기 때문이다.
그래서, 시간이 큰 제약조건이라면 이 접근방법은 좋지 않을 수 있다.
3. Apache Spark
신뢰할 수 있는 빅데이터 솔루션인 Apache Spark는 백만 단위의 데이터를 쉽게 stream 하기에 매우 적합한 후보군이다. Spark cluster를 구축하고 무엇을 해야 하는지를 알아야 하는것 만이 유일한 단점이다.
Streaming data using Spring Data JPA
그러나 Spark에 시간을 투자하고 싶지 않거나 다른 제약 조건이 있다면, 마지막 남은 옵션은
Spring Data JPA Stream
이다. Spring Data JPA Stream이 작동하기 위해서는 Repository 클래스에서 함수의 반환 타입을
Stream<Book>
과 같이 바꾸어 주면 된다.public interface BookRepository extends Repository<Book, Long> { @QueryHints(value = { @QueryHint(name = HINT_FETCH_SIZE, value = "" + Integer.MIN_VALUE), @QueryHint(name = HINT_CACHEABLE, value = "false"), @QueryHint(name = READ_ONLY, value = "true") }) @Query("select b from Book") Stream<Book> getAll(); }
- 위의 QueryHint 부분을 보면 2차 캐시가 비활성화 되었고, READ_ONLY 속성이 활성화 되어 있음.
- 이 상황에서의 가정은 각각의 row 에 대해 그냥 읽고 어떤 작업을 수행한 뒤, 다른곳에 저장하는 상황이다. 만약 요구사항이 다르다면 해당 부분을 바꾸어야 함
- 그리고 Streaming이 동작하기 위해서는
@Transactional
어노테이션이 필요
- 거기다가, 추가적으로 OOM이 발생하지 않게 하기 위해서는 entity를 detach 시켜주는 게 필요함. 그렇게 하여, garbage collector가 메모리를 다시 회수할 수 있도록 해야 함
Spring Data JPA does not automatically clear objects from the persistence context when streaming. This is because the underlying JPA implementation relies on the persistence context to manage entities.