You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
현재 DB Replication을 위해서 쓰기전용 DataSource = masterDB 그리고 읽기전용 DataSource = slaveDB를 사용중입니다.
Resolver에서 User를 조회할 때 readOnly 트랜잭션을 사용합니다.
readOnly 트랜잭션을 사용한다는건 읽기전용 DataSource => slaveDB 를 사용합니다.
여기서 OSIV에 의해 트랜잭션이 끝나도 영속성 컨텍스트는 유지됩니다.
댓글 등록, 수정 등등의 데이터 쓰기 api 호출 시 Resolver에서 User를 조회하는데 readOnly 트랜잭션이 먼저 사용되면서 slaveDB의 DataSource를 사용합니다. 이때 사용된 DataSource를 계속 유지한채로 쓰기 api의 Service까지 도달합니다.
댓글 등록을 예로 들면
MemberArgumentResolver에서 User 조회
EntityManager에 SlaveDB DataSource 등록됨
댓글 등록 CommentController -> CommentService
CommentService 에서 댓글 등록 메서드 호출 -> 이미 등록된 DataSource가 있으므로 그대로 사용(SlaveDB의 DataSource 😈 )
댓글 등록이 SlaveDB로 쓰기를 실행
SlaveDB에 댓글이 저장됨
그럼 지금까지는 masterDB에 잘 저장됐는데?? 라는 의문을 가질 수 있어요
아래 코드는 MemberArgumentResolver에서 호출하는 AuthService의 findUserByToken 메서드입니다.
사진을 보면 @transactional 애너테이션이 생략됐습니다. 즉 readOnly=false 트랜잭션으로 사용하므로 Resolver에서 사용하는 DataSource는 MasterDB의 dataSource 입니다.
그래서 댓글 등록도 MasterDB의 DataSource를 사용하는 것이죠. 즉 의도한대로 동작은 하지만 문제는 있다고 봅니당.
현재는 OSIV를 켜고 MemberArgumentResolver에서 호출하는 AuthService의 findUserByToken 메서드에 @transactional(readOnly=true)를 주면 Resolver는 SlaveDB를 찌르고 Service의 메서드에서 쓰기 메서드를 사용해도 SlaveDB를 찌릅니다.
Replication의 본래 목적인 Write&Read 부하 분산이 일어나지 않는다.
어디서 시작되든 처음 시작되는 트랜잭션의 DataSource를 계속 사용하는점
지금처럼 Resolver에 의해서 쓰기에서 잘못된 DataSource를 사용할 수 있는점
하나의 Controller에서 여러 service를 호출해야하는 상황이 생겼을때 각각의 DataSoure를 줄 수 없는점
이런 문제들이 있다고 봤어요.
OSIV를 꺼버리면 의도한대로 Resolver는 조회DB Service레이어의 쓰기 메서드는 쓰기DB를 사용하도록 할 수 있습니다.
(코드에서 좀 수정이 필요!)
저희 서비스에서는 OSIV를 User 접근 용도에서만 거의 대부분 사용되고 있으니, replication을 적절하게 하기 위해 제거해주는 방향이 더 좋을 수도 있겠다는 생각이 드네요!
저는 OSIV를 끄면 물론 커넥션이 조금 더 발생한다는 단점도 있겠지만, replication 역시 그런 부하를 줄이기 위한 역할 중 하나고 전체적으로 봤을 때 replication을 우선순위에 두는 것이 좀 더 좋겠다고 생각합니다! 👍👍👍👍
내용
OSIV에 의해서 잘못된 DataSource가 선택되는 문제
정확히는 다중 DataSource 와 OSIV에서 생기는 문제입니당
시나리오
현재 DB Replication을 위해서
쓰기전용 DataSource = masterDB
그리고읽기전용 DataSource = slaveDB
를 사용중입니다.Resolver에서 User를 조회할 때 readOnly 트랜잭션을 사용합니다.
readOnly 트랜잭션을 사용한다는건 읽기전용 DataSource => slaveDB 를 사용합니다.
여기서 OSIV에 의해 트랜잭션이 끝나도 영속성 컨텍스트는 유지됩니다.
댓글 등록, 수정 등등의 데이터 쓰기 api 호출 시 Resolver에서 User를 조회하는데 readOnly 트랜잭션이 먼저 사용되면서 slaveDB의 DataSource를 사용합니다. 이때 사용된 DataSource를 계속 유지한채로 쓰기 api의 Service까지 도달합니다.
댓글 등록을 예로 들면
그럼 지금까지는 masterDB에 잘 저장됐는데?? 라는 의문을 가질 수 있어요
아래 코드는 MemberArgumentResolver에서 호출하는 AuthService의 findUserByToken 메서드입니다.

사진을 보면 @transactional 애너테이션이 생략됐습니다. 즉 readOnly=false 트랜잭션으로 사용하므로 Resolver에서 사용하는 DataSource는 MasterDB의 dataSource 입니다.
그래서 댓글 등록도 MasterDB의 DataSource를 사용하는 것이죠. 즉 의도한대로 동작은 하지만 문제는 있다고 봅니당.
이런 문제들이 있다고 봤어요.
OSIV를 꺼버리면 의도한대로 Resolver는 조회DB Service레이어의 쓰기 메서드는 쓰기DB를 사용하도록 할 수 있습니다.
(코드에서 좀 수정이 필요!)
참고문서
The text was updated successfully, but these errors were encountered: