개요
2025.04.04 - [팀 프로젝트/플러스 프로젝트] - Transactional-Readonly가 어플리케이션에 미치는 영향
Transactional-Readonly가 어플리케이션에 미치는 영향
개요Hot Key를 관찰하려고 부하테스트를 하던 도중, 세션 자동 생성에 이어 이상한 점을 하나 더 발견했다.우선, 짧게 실험 결과를 요약하고 가면..1. 실험 목적:Hot Key가 Redis 또는 시스템에 어떤 영
roqkfchqh.tistory.com
지난번에 이어서... Transactional Readonly에 관한 글이다.
Transactional readonly를 불필요한 상황에서 사용했을 때 쓸모없는 DB 커넥션이 생겨버려서 부하가 몰릴 경우 어플리케이션 전반의 latency가 증가하는 현상을 관측할 수 있었다.
그런데.. 어째서 "캐시만" 조회하는 로직에서 트랜잭션 관련 쿼리가 발생한 걸까?
실험
생각해보니 단순 캐시 조회인데 커넥션이 생성되는게 이상해서, 테스트용 코드를 만들었다.

오늘은 이 코드에 Transactional을 뗏다 붙였다 해보면서 분석을 해보자.
프로젝트 코드 로직의 문제일 수도 있으니, 최대한 프로젝트 코드를 간소화한 로직으로 준비했다.

간소화 한 로직에서도, 심지어 DB호출부를 주석 처리 했는데도 커넥션을 사용하고 있다.

그럼 이건 어떨까? 아예 외부 서비스를 하나도 이용하지 않고 변수 선언만 해보자.

그래도 커넥션을 사용한다.
생각
조금 생각해보니 이건 CGLIB 방식 프록시의 한계인 거 같다.
기본적으로 CGLIB나 JDK Dynamic Proxy는 트랜잭션을 메서드 진입 전에 무조건 시작할지 말지 결정하게 된다.

디버깅해보면 로직을 알 수 있는데, 리플렉션을 통해 @Transactional을 감지하고
곧바로 프록시 객체(ReadOnlyService)를 사용하는 것을 볼 수 있다.
트랜잭션을 사용하지 않으면 해당 과정 없이 Service계층으로 바로 이동한다.
이처럼 @Transactional이 선언된 메서드는 실제 서비스 구현체가 아니라 Spring AOP 프록시로 감싸지게 되며,
트랜잭션 매니저가 논리적 트랜잭션 컨텍스트를 설정하고, 물리적인 커넥션을 획득하게 된다.
트랜잭션이 시작된다고 해서 항상 커넥션이 필요한건 아니지만..
대부분의 JPA 트랜잭션 매니저는 트랜잭션이 시작될 때 곧바로 커넥션을 획득한다.
이는 추후에 있을지도 모르는 DB접근을 위해 미리 선점하는 방식인데 결국 커넥션을 쓰지않아도 풀에서 자원을 점유하게 되는 비효율로 이어진다
이 때문에 서비스 로직을 구성할 때 어디까지가 DB 트랜잭션의 책임 영역인지 명확히 구분하는 게 중요한 거 같다.
@Transactional을 꼭 필요한 메서드에만 최소한으로 적용하고,
Redis나 Cache, 외부 API 등 DB 외부 영역와 혼합된 로직은 분리하거나 상위계층에서 orchestration해주자.
'팀 프로젝트 > market.normalization.project' 카테고리의 다른 글
조회 성능 향상시키기(7) Semaphore에서 Mutex로 갈아타기 (0) | 2025.04.10 |
---|---|
Transactional-Readonly가 어플리케이션에 미치는 영향 (0) | 2025.04.04 |
Actuator가 자동으로 Session을 생성한다 (0) | 2025.04.02 |