16

yeoro·2021년 12월 15일
0

API 개발 고급 - 실무 필수 최적화

OSIV

  • Hibernate : Open Session In View
  • JPA : Open EntityManager In View

로그

WARN 17164 --- [ 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

spring.jpa.open-in-view: true

DB 트랙잭션 시작할 때 JPA 영속성 컨텍스트가 connection을 획득한다.

OSIV가 true이면 @Transactional 메소드가 끝나고 controller에 가도 connnection을 반환하지 않는다.

LAZY 로딩이 일어나려면 프록시 객체를 DB에 가져오든 해서 초기화 해야함. 이때 영속성 컨텍스트가 DB connection을 가지고 살아있어야 한다.

즉, OSIV는 트랜잭션이 끝나도 영속성 컨텍스트를 살려두는 것이다. 요청이 들어와서 처리한 후 view가 rendering 되고 reponse를 반환하면 그때서야 DB connection 반납과 영속성 컨텍스트 종료가 이루어진다. 이는 지연로딩이 가능했던 이유이기도 하다.

이 전략은 너무 오랜시간 DB connection 리소스를 사용하기 때문에 실시간 트래픽이 중요한 애플리케이션에서는 connection이 모자라 장애가 이루어질 수 있다. (connection이 말라버린다)

ex) 외부 API를 호출하면 API 대기 시간 만큼 connection 리소스를 반환하지 못하고 유지해야 한다.

장점

  • entity를 적극 활용해서 lazy 로딩 같은 기술을 controller, view 에서 활용할 수 있다.
  • 중복을 줄이고 투명하게 lazy 로딩 가능
  • 코드의 유지보수성을 높인다.

spring.jpa.open-in-view: false

트랜잭션을 종료할 때 영속성 컨텍스트를 닫고, DB 커넥션도 반환한다. 따라서 커넥션 리소스를 낭비하지 않는다.

장점

  • 커넥션 리소스를 낭비하지 않는다.
  • 실시간 트래픽에 사용하기 좋다.

단점

  • 지연로딩을 트랜잭션 안에서 처리해야 하므로 모든 지연로딩 코드를 트랜잭션 안으로 넣어야 한다.

    controller에서 객체 조회 시 에러 발생

    org.hibernate.LazyInitializationException: could not initialize proxy [jpashop.domain.Member#1] - no Session

  • view에서 지연로딩이 동작하지 않는다.

  • 결론적으로 트랜잭션이 끝나기 전에 지연로딩을 강제로 호출해 두어야 한다.

  • controller에서 처리하던 로직을 따로 service로 빼고, controller에서는 service 호출만 하도록 변경하여 해결

커맨드와 쿼리 분리

보통 비즈니스 로직은 특정 엔티티 몇개를 등록하거나 수정하기 때문에 성능이 크게 문제가 되진 않는다.

반면, 복잡한 화면을 출력하기 위한 쿼리는 화면에 맞추어 성능을 최적화 하는 것이 중요하다. 이는 복잡성에 비해 핵심 비즈니스에 큰 영향을 주는 것은 아니다.

핵심 비즈니스 로직 5개, 쿼리(화면용) 로직 20~30개.. 이 둘은 라이프 사이클이 많이 다르다.

따라서 크고 복잡한 애플리케이션은 이 둘을 분리하는게 유지보수에 좋다.

  • OrderService : 핵심 비즈니스 로직
  • OrderQueryService : 화면이나 API에 맞춘 서비스 (주로 읽기 전용 트랜잭션 : readOnly=true)

실사용

  • 고객 서비스의 실시간 API는 OSIV OFF
  • Admin 처럼 커넥션을 많이 사용하지 않는 곳은 OSIV ON

0개의 댓글