항해99 after - 조회 API에 readOnly=true를 설정하면 성능이 개선될까?
조회 API에서 고려해야할 부분이 몇 가지 있습니다. 그중 하나가 트랜잭션입니다. 저는 실전 프로젝트에서 @Transactional 을 통해 트랜잭션을 처리했는데요. 그 중에서 오늘은 @Transactional의 readOnly 옵션에 대해 알아보도록 하겠습니다.
목차
1. @Transactional readOnly 옵션
2. 실제 프로젝트에 readOnly 적용하기
3. 성능 비교
1. @Transactional readOnly 옵션
스프링 공식 문서에 따르면 Read-only 상태를 넣으면 최적화에 유용할 수 있다고 합니다.
최적화가 되는 이유를 조금 찾아보면 아래와 같습니다.
1. 읽기 전용 트랜잭션에서는 레코드에 Lock 설정을 하지 않아도 된다.
2. Jpa를 사용할 경우 dirty checking을 하지 않아도 됩니다.
3. Jpa를 사용할 경우 읽기 전용 트랜잭션에서는 flush를 호출하지 않아도 됩니다.
2. 실제 프로젝트에 readOnly 적용하기
1. readXxx 메서드 read-only 옵션 체크 Aspect 구현
2. Application layer에 readXxx 메서드 readOnly=true 적용
1번 작업의 경우 추후 API가 추가될 때 readOnly옵션을 지정하지 않은 것을 인지하는 용도로 만들어 두었습니다.
우선 현재 Repository 내부 메서드에 readOnly 옵션이 적용되었는지 확인해봅시다. 실전 프로젝트에서는 Spring data Jpa를 사용했습니다.
결론부터 말씀드리면 동적으로 생성되는 findByUserIdAndEventId()나 , @Query 사용한 정의한 메서드는 @Transactional(readOnly=false)가 설정됩니다.
현재 트랜잭션이 readOnly인지 확인하는 AOP입니다.
아래 API를 호출해보면 읽기 전용 트랜잭션이 아니라는 로그를 확인하실 수 있습니다.
로그
readOnly 옵션이 적용되지 않은걸 볼 수 있습니다. 이제 트랜잭션의 시작점인 Application layer에 readXxx 메서드에 @Transactional(readOnly = true)를 달아줍시다.
3. 성능 비교
일정 50개 조회, DB는 Mysql을 기준으로 테스트를 해보았습니다.
(1) readOnly 미 적용 시
(2) readOnly 적용 시
(3) application layer에 @Transactional 애노테이션을 뗄 경우
3번이 오히려 성능면에서 확실하게 이점이 있다. 왜 이런 결과가 나오게 될까?
첫 번째 가설은 단순히 API를 한 클라이언트가 호출하는 것 만으로는 readOnly의 이점을 볼 수 없다. Lock 측면에서 서로에게 영향을 주려면 최소 2개 이상의 커넥션이 발생해야 할 것이기 때문이다.
두 번째 가설은 트랜잭션의 범위가 늘어나기 때문이 아닐까 생각한다.
현재로선 어떤 것이 정확한 원인이라고 파악할 순 없겠지만 그래도 성능 개선을 할 때는 꼭 테스트로 마무리해야된다는 교훈을 얻을 수 있었다.