open-session-in-view?
OSIV는 기본값을 true로 설정되어있다. 이후 WARN 로그가 남는다.
OSIV 전략은 트랜잭션 시작처럼 최초 데이터베이스 커넥션 시작 시점부터 API 응답이 끝날 때까지 영속성 콘텍스트와 데이터베이스 커넥션을 유지한다.
언제 JPA가 데이터베이스 커넥션을 가져올까?
트랜잭션 시작 시점에 영속성 콘텍스트가 데이터베이스 커넥션을 획득한다.
그럼 반환하는 곳은 어디일까?
osiv가 켜져 있다면 트랜잭션이 끝나고 VIEW 계층까지 커넥션을 유지한다.
그렇기 때문에 우리가 view Template이나 API 컨트롤러에서 지연 로딩을 사용할 수 있던 것이다.
지연 로딩은 영속성 콘텍스트가 살아있어야 가능하고, 이는 기본적으로 데이터베이스와 커넥션을 유지한다.
다만 이 전략은 너무 오랜 시간 데이터베이스 커넥션 리소스를 사용하기에 커넥션이 모자랄 수 있다.
API 호출 시 외부 API 대기 시간만큼 커넥션을 물고 있다는 것은 의도치 않게 장시간 커넥션을 물고 있을 수 있다.
그럼 옵션을 false로 하면 어떻게 될까?
OSIV를 종료를 하면 모든 지연 로딩을 트랜잭션 안에서 처리해야 한다. 따라서 TURE일 때 얻었던 장점을 포기하게 된다.
또는 fetch join을 통해 처리할 수 있다. 대신 트랜잭션 안에 많은 코드가 들어갈 것이다.
만약 실무에서 OSIV를 끈 상태로 복잡성을 관리하는 좋은 방법은 커맨드와 쿼리를 분리하는 것이다.
복잡한 화면을 출력하기 위한 쿼리나 조회가 성능 문제를 일으킨다. 이는 전부 화면에 맞춰서 개발을 한다.
그 복잡성에 비해 핵심 비즈니스에 큰 영향을 주지 않는다.
개발을 할 때 한 리파지토리나, 서비스에 쿼리나 커맨드가 전부 녹여놓으면 유지보수성이 매우 떨어진다.
생각해보면 라이프사이클이 다르다. 화면에 맞춘 기능은 라이프사이클이 빠른 반면 비즈니스 정책이 있는 커맨드 같은 경우는 라이프 사이클이 화면보다 느리다.
이 관심사를 명확하게 분리하는 선택은 유지보수 관점에서 충분히 의미가 있다.
이 옵션의 활성화 여부를 고민하는 것은 애플리케이션의 규모다.
실시간 유저 트래픽을 받아내는 경우 항상 커넥션에 대한 고민을 할 수밖에 없을 것이다. 이 경우 OSIV는 장애로 이어질 가능성이 존재한다.
가능성이 있다면 이를 예방해야 하기 때문에 OSIV를 끄는 것이 맞는 것 같다.
다만 내부적으로 사용하는 내부툴이나 관리자 페이지 같은 경우 기본 커넥션 수만으로도 충분하기 때문에 이 경우 OSIV를 켜서 영속성 콘텍스트의 이점을 사용하는 것이 맞는 것 같다.
서비스 내부코드가 커맨드와 쿼리를 분리하는 전략을 고민한다면 프레젠테이션 계층과 서비스 계층에 프락시 초기화를 위한 facade 계층을 하나 더 두는 것도 방법이다.
이는 facade 계층을 추가하여 단순히 서비스 계층을 호출하는 위임하는 코드도 있지만 다른 작업을 추가적으로 할 수 있다는 것도 장점을 가져갈 수 있지 않을까 싶다.
아니면 DTO로 즉시 반환하는 것도 하나의 방법이 될 수도 있을 것이다. 극도의 성능과 커맨드, 쿼리를 분리할 수 있는 방법이 아닐까 싶다.
다만 실제 dto로 반환하는 코드를 위해 내부적으로만 복잡성이 증가하겠지만 깔끔하게 별도의 계층을 두지 않고 OSIV를 꺼서 사용할 수 있는 방법이다.
결국 모든 적절한 선택에는 결국 트레이드오프가 존재한다. 개발자는 신중히 선택하여 그 책임을 져야 한다.
댓글