Java/Spring

[Spring] OSIV[Open Session In View]를 적절히 사용하여 성능 최적화

SeungbeomKim 2023. 3. 8. 12:49

OSIV란 무엇인가? 

하이버네이트에서 Open Session In View라고 불렀고, 향후 JPA가 생기고 나서는 Open EntityManager In View라고 불렀습니다.

관례상 OSIV라고 합니다. OSIV는 하이버네이트를 뷰까지 열어두는 기능입니다. 

 

spring.jpa.open-in-view : true(기본 값)

다음과 같이 애플리케이션을 시작 시점에 warn로그를 뿌립니다. 이제 그 이유에 대해서 알아보겠습니다.

 

OSIV 전략은 최초 데이터베이스 연결 시작 시점부터 API 응답이 끝나기 전 까지 영속성 컨텍스트와 데이터베이스 커넥션을 유지하게 됩니다. 그래서 View 템플릿이나 API 컨트롤러에서 지연로딩이 가능해왔습니다. (지연 로딩(LAZY)가 가능하려면 영속성 컨텍스트가 살아 있어야 가능하고, 영속성 컨텍스트는 기본적으로 데이터베이스 커넥션을 유지합니다). 개발 입장에서 중복도 줄이고 투명하게 LAZY로딩을 이어나갈 수 있기 때문에 유지, 보수 차원에서는 매우 큰 장점입니다. 

 

하지만, 이 전략은 너무 장시간 동안 데이터베이스 커넥션 리소스를 사용하기에, 실시간 트래픽이 중요한 애플리케이션에서는 커넥션이 부족할 수 있습니다. 이러한 이유 때문에, 시스템 장애의 큰 원인이 될 수 있습니다.

 

이를 해결하기 위해 spring.jpa.open-in-view 값을 false(OSIV OFF)로 설정한다면, 트랜잭션을 종료할 때  영속성 컨텍스트를 닫고, 데이터베이스 커넥션도 반환합니다. 그래서 커넥션 부족 문제를 해결할 수 있습니다.

하지만, 지연로딩을 트랜잭션 안에서 모두 처리해줘야 한다는 단점이 있습니다. view 템플릿에서도 지연로딩이 동작하지 않습니다.

((영속성 컨텍스트를 닫고, 영속성 컨텍스트의 생존 범위를 벗어났기에 지금까지 지원해온 지연로딩이 불가능)

-> 트랜잭션이 끝나기 전에 지연로딩을 강제로 호출해야 합니다.

 

실무에서는 OSIV를 끈 상태로 복잡성을 관리하는 방법은 커멘드(command)와 쿼리(query)를 분리하는 방법이 있습니다. 비즈니스 로직에서 등록이나 수정하는 영역이기에 성능상 문제가 되지 않습니다.

하지만, 성능 문제는 조회부분에서 일어납니다. 복잡한 화면을 출력하기 위한 쿼리는 화면에 맞춰 성능을 최적화해야 합니다. 그래서 이러한 로직이 담긴 Service를 따로 만들어줘서 비즈니스 로직과 화면이나 API를 위한 서비스를 분리해주면 유지, 보수적인 관점에서 좋습니다.

(대규모 애플리케이션을 만드는 경우에는 확실하기 분리하는 것이 좋습니다)

 

<결론>

실시간 트래픽을 많이 사용하는 API에서는 OSIV를 꺼주고, 커넥션을 많이 사용하지 않는 경우에는 OSIV를 켜줍니다.