HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
✍🏻
Learnary (learn - diary)
/
🌪️
Soloving_Issue_Log
/
Replication AbstractRoutingDataSource 문제

Replication AbstractRoutingDataSource 문제

kindOf
Replication
Created time
Jun 14, 2023 04:48 AM
Status
Done
keyword
문제상황원인분석문제해결

문제상황


SpringBoot RDB Replication 적용하기
Replication 설정 SpringBoot에 적용할 때각 데이터 소스 설정, AbstractRoutingDataSource의 determineCurrentLookupKey 재설정을 진행했다.
하지만 위와 같이만 적용하게 되면 readOnly속성이 true임에도 불구하고 slave 노드로 절대 호출되지 않는 문제를 발견했다.
즉, AbstractRoutingDataSource을 이용할 경우 모든 Query가 Master DBMS로만 가는 현상을 발견할 수 있을거다.
 

원인분석


Spring에 있는 AbstractRoutingDataSource는 여러개의 데이터 소스를 하나로 묶고 자동으로 분기 처리 해주는 Spring Default 객체이다.
Spring의 현재 트랜잭션 속성을 읽어오는 TransactionSynchronizationManager와 조합하여 분기 처리를 하려 설정을 해 주었지만, 이렇게 하게 되면 TransactionSynchronizationManager가 비록 @Transactional로 선언된 현재 쓰레드의 트랜잭션 상태를 읽어오는게 가능하더라도 동기 (Syncronation) 시점과 Connection 객체를 가져오는 시점에 문제가 발생하기 때문이다.
 
트랜잭션 처리방식을 간략하게 살펴보면
1. TransactionManager 선별
2. DataSource에서 Connection 획득
3. Transaction 동기화
트랜잭션 동기화를 마친 뒤 ReplicationRoutingDataSource에서 Connection을 획득해야만 정상 동작을 할텐데, 이 순서가 뒤 바뀌어 있다는 것이 문제이다. 즉, 이미 커넥션 가져왔는데 바꾸는 것도 비용이 비싸다(커넥션 풀은 엄청 비싼 자원이다)
 

문제해결


문제를 해결하기 위해서는 ReplicationRoutingDataSource를 LazyConnectionDataSourceProxy로 감싸주어서 처리를 하면 된다.
LazyConnectionDataSourceProxy는 실질적인 Query 실행 여부와 상관없이 트랜잭션이 걸리면 무조건 Connection 객체를 확보하는 Spring 단점을 보완하여 트랜잭션 시작시 Connection Proxy 객체를 반환하고, 실제 Query 발생 시에 DataSource에서 getConnection()을 호출하는 역할을 해주고 있다.
 
프록시 패턴은 실제 호출하기 전에 Lazy하게 뒤로 미는 특징을 가짐을 알면 좋을 것 같다.
 
LazyConnectionDataSourceProxy을 사용했을 때, 처리 방식
1. TransactionManager 선별
2. LazyConnectionDataSourceProxy에서 Connection Proxy 객체 획득(아직 커넥션 안가져옴!)
3. Transaction 동기화
4. 실제 Query Call 할때, ReplicationRoutingDataSource.getConection() / determineCurrentLookupKey() Call
 
위 순서와 같이 Spring의 트랜잭션과 알맞는 ReplicationRoutingDataSource가 만들어지게된다.
이러한 이유로 Transaction 동기화 시점에 Connection 획득을 위해 LazyConnectionDataSourceProxy로 한번 감싸주어야 하는 작업이 필요하다.