본문 바로가기
🔗 JPA

OSIV(Open Session in view)이란? 장단점, 써야할지 말아야할지

by 비타민찌 2022. 10. 21.
728x90

Open-In-View / Open-Session-In-View / Open-EntityManager-In-View

스프링부트 2.x 이상을 사용 중이라면 아래 경고를 한번 쯤 본 적 있을 것이다.

2022-10-21 15:19:29.799  WARN 45628 --- [  restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning

여기서 말하는 open in view 가 바로 OSIV 다.

 

1. OSIV 란? (Open Session in view)

Open EntityManager In View 라는 필터는 JPA EntityManager(영속성 컨텍스트: DB에서 읽어온 객체들을 관리하는 컨텍스트. persistent 상태인 객체들을 관리) 또는 hibernate session(영속성 컨텍스트), 즉 영속성 컨텍스트를 뷰 랜더링이 끝날 때 까지 유지하는 것이다. 스프링부트는 기본적으로 Open EntityManager In View를 설정해준다. persistent 상태인 객체들은 트랜잭션 안에서는 객체 상태의 변경만 감지하다가 트랜잭션이 종료될 때 DB에 반영한다.

 

true가 default로 설정 되어있다.

spring.jpa.open-in-view: true

 

jpa(영속성 컨텍스트)는 기본적으로 데이터 베이스 트랜잭션을 시작할 때 데이터 베이스 커넥션을 가져오는데, 이걸 언제 디비에 돌려줄까?

OSIV가 true로 되어있을 경우,(따로 설정해 주지 않았다면 기본이 true로 되어 있다) 마지막까지. api의 경우 api가 유저에게 반환 될 때까지, html의 경우 화면이 사용자에게 반환할 때까지, 어딘가 response를 주기 전까지 가지고 있다가 반환이 되면, 데이터베이스 커넥션을 돌려주고 영속성 컨텍스트도 함께 사라진다. 그래서 지금껏 지연로딩을 사용할 수 있었던 것이다.

 

그런데 이 전략의 단점은 이렇게 너무 오랜시간 데이터베이스 커넥션을 사용한다는 점이다.

실시간 트래픽이 중요한 어플리케이션에서는 이를 두고 커넥션이 말라버렸다고 표현하는데, 이게 곧 시스템 장애다.

 

일반적인 애플리케이션에서는 데이터베이스 트랜잭션이 끝나고 바로 반환하면 되는데,

이 경우 커넥션을 끝까지 들고 있는다.

예를들어 컨트롤러에서 외부 api를 호출 할 때 이게 3초 걸린다면, 그 3초 동안 커넥션 리소스를 반환하지 못하고 유지해야한다.

블로킹이라도 걸리면 커넥션을 다 먹어버리게 된다..

 

OSIV 설정을 꺼두면 어떻게 될까?

spring.jpa.open-in-view: false

트랜잭션이 시작하고 끝날때까지만 영속성 컨텍스트 / 데이터 베이스 커넥션을 유지하고,

그래서 커넥션 리소스를 낭비하지 않는다.

 

그런데... OSIV를 끄면 모든 지연로딩을 트랜잭션 안에서 처리해야 한다는 문제가 생긴다.

모든 지연로딩 코드를 트랜잭션 안에서 처리해야하는 것이다. 즉, 트랜잭션이 끝나기 전에 지연로딩을 강제 호출 해주어야 한다.

나의 경우 코드에 Lazy 로딩이 굉장히 많은데 이 옵션을 off 하고 실행해 보면:

 

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.minji.vanillashop.domain.order.entity.Order.orderItems, could not initialize proxy - no Session at...

위와 같은 에러가 발생한다.

이럴 경우 모든 지연로딩 코드를 트랜잭션 안에서 처리하고 반환하거나 fetch join을 사용해 해결할 수 있다. 

 

그럼 OSIV를 켜는게 좋을까, 끄는게 좋을까?

OSIV가 켜져 있으면 아무래도 데이터베이스 커넥션 이슈가 있긴 하겠지만, 지연로딩 사용이 편리하다. 즉 유지보수성이 높아진다. 성능 빼고는 거의 장점 뿐이다.

 

그래서 실시간 조회 트래픽이 많은 서비스라면 OSIV를 끄는게 좋겠고

admin 시스템 정도(요청 많지 않은 것)라면 키는게 좋지 않을까 싶다.

 

OSIV 설정을 yml 파일로 글로벌하게 적용시키고 싶지 않을 경우(프로젝트가 단일 모듈로 되어 있어서 함께 배포가 되어야 한다면) OpenEntityManagerInViewFilter 나 OpenEntityManagerInViewInterceptor를 직접 스프링에 등록하면 되고, 등록하면서 적용되는 URL Path를 적용하고 싶은 곳으로만 잡아주면 된다.

 

[참고]

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

 

728x90

댓글