어제 찾은 오류들을 바탕으로 발표 자료를 마저 정리하고, 공부의 결론을 낸 뒤 다음 진도로 넘어가려고 했습니다.
다음 진도는 context-transaction.xml 파일의 구성을 살펴보는 것이었습니다.
그런데 선언된 bean 두 개를 찬찬히 뜯어보다 보니, 두 매니저가 서로 다른 데이터소스를 바라보면서도 정작 동일한 포인트컷(*ServiceImpl.*Tx(..))을 가리키고 있는 것을 발견했습니다.
이상한 마음에 에이전트에게 관련 설정을 넘겨주고 이 구조에 대한 추가 설명을 요구했습니다.
에이전트로부터 돌아온 답변은 꽤나 의외였습니다.
“매우 예리하고 정확한 지적이십니다. context-datasource.xml과 실제 properties 파일(app.properties)을 교차 대조해 본 결과, 레거시 시스템에서 매우 은밀하게 작동하고 있던 심각한 아키텍처적 결함과 비효율을 발견했습니다.”
실제 비즈니스 로직에서 실행되는 쿼리는 단 하나뿐인데, 백그라운드에서는 주 DB와 영업 DB의 커넥션 풀을 동시에 두 개씩 점유하고 있었던 겁니다.
구체적으로 어떤 비효율이 발생하고 있었는지 확인해 보았습니다.
원인 분석: JNDI 동일 리소스 매핑과 중첩 AOP의 합작
원인은 과거 시스템 아키텍처의 흔적과 낡은 XML AOP 설정이 겹치면서 발생한 비효율이었습니다.
첫째로, 설정 구조상 JNDI 동일 리소스 매핑 상태였습니다.
context-datasource.xml빈 정의를 보면 주 DB용dataSource와 영업 DB용dataSourceSale빈이 각각 따로 선언되어 있었습니다.- 하지만
app.properties설정과 Tomcatcontext.xml리소스를 대조해 보니, 두 빈이 가리키는 실제 JNDI 물리 DB 리소스는 동일한jdbc/netshop이었습니다. - 즉, 이름만 다른 두 데이터소스 빈이 결국 똑같은 하나의 물리 DB를 가리키고 있었던 셈입니다.
둘째로, XML AOP의 이중 바인딩이 작동하고 있었습니다.
context-transaction.xml설정을 보니, 메서드 이름이Tx로 끝나는 포인트컷에 대해 주 DB 트랜잭션 매니저(txAdvice)와 영업 DB 트랜잭션 매니저(txAdviceSale)가 동시에 작동하도록 중첩 선언되어 있었습니다.- 결과적으로
~Tx메서드가 호출될 때마다 스프링은 두 개의 트랜잭션을 중첩해서 시작시켰고, 동일한 물리 DB에 대해 불필요하게 커넥션을 두 번씩 획득하고 반환하고 있었습니다.
결과적으로 커넥션 풀 리소스가 불필요하게 낭비되는 비효율이 발생하고 있었던 겁니다.
해결책: 단기 및 장기 리팩토링 로드맵
이중 점유 문제와 전편에서 짚은 트랜잭션 누락 문제를 동시에 안전하게 풀기 위해, 리팩토링 계획을 단기와 장기 로드맵으로 한층 더 구체화하여 수립했습니다.
1. 단기 개선안 (당장 시급한 병목 차단)
외부 통신 분리와 Facade 패턴 도입
다건 사은품/쿠폰 발급이나 외부 PG사 결제 연동처럼 외부 네트워크 I/O 대기가 발생하는 로직은 Facade 패턴을 적용해 트랜잭션 밖으로 완전히 격리합니다. 외부 통신 완료 후, 순수 내부 DB 관련 CUD 작업들만 묶어서 하나의 트랜잭션(~Tx 메서드) 내에서 수행되도록 분리합니다.
AOP 포인트컷 명칭 분리
주 DB(예: *Tx)와 영업 DB(예: *SaleTx)의 명명 규칙 포인트컷을 XML 설정 상에서 명확하게 쪼개어, 동일한 메서드 호출 시 이중으로 트랜잭션이 중복 획득되는 현상을 원천 차단합니다.
2. 장기 개선안 (구형 체계의 완벽한 청산)
어노테이션 인프라 활성화 및 데드 코드 정비
<tx:annotation-driven> 설정을 활성화하여 작동하지 않던 가짜 @Transactional 데드 코드를 안전하게 복원하고, 꼭 트랜잭션이 보장되어야 하는 범위에만 전략적으로 배치합니다.
구형 XML 매핑 체계 완전 제거
단순 단일 쿼리임에도 ~Tx 이름 규칙 때문에 커넥션 연결/종료 비용을 무의미하게 소모하던 구형 XML AOP 설정을 완전히 걷어냅니다. 100% 명시적인 어노테이션 기반 트랜잭션 체계로 전환하여 통신 오버헤드를 줄입니다.
이중 커넥션 점유 내용까지 완벽하게 업데이트하여 6월 팀 회고용 발표 자료 정리를 마쳤습니다.
이로써 어제부터 이어진 스프링 트랜잭션 설정 오류와 잠재적 병목 분석이 마무리되었네요.
아래 슬라이드는 이번에 보완된 상세 분석 내용(JNDI 동일 리소스 매핑 및 이중 AOP 바인딩 구조 분석)과 시각적인 다이어그램을 담은 최신 HTML 프레젠테이션 자료입니다. 슬라이드를 넘기며 확인해 보실 수 있습니다.