일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- spring jpa
- ibatis
- CEP
- jenkins
- drools
- COC
- Hudson
- jstl
- rember me
- zabbix
- @SqlResultSetMapping
- GEventEvaluator
- jquery serialize
- custom filter
- querydsl
- Drools Fusion
- guvnor
- bootstrap jquery datepicker
- SVN
- Spring
- gwt
- JBoss Seam
- jquery
- java tip
- JPA
- gwt-ext
- spring transaction
- maven
- spring security
- MySQL
- Today
- Total
봉 블로그
Spring read-only transaction & MySQL Replication 본문
Spring MVC + MyBatis + MySQL Replication 환경에서
Spring transaction설정이 read-only=true & propagation="SUPPORTS"인 서비스 메소드 실행시 query 수행이 MySQL Replica 서버로 가지않고 master 서버로 가게된다.
반대로 propagation="SUPPORTS"설정을 제거한 read-only=true 서비스는 replica 서버로 수행되어 부하분산된다.
테스트결과 성능차이도 매우 심하게 차이가 났다. propagation="SUPPORTS" 가 설정되어 있는경우가 훨신좋다.
먼저 read-only=true & propagation="SUPPORTS" 설정이 mysql master 서버로 질의되는 현상은(read-only=true 설정이 있음에도 불구하고) db connection 의 readOnly 설정이 true로 셋팅되지 않기때문이다. 이현상을 좀더 자세히 알려면 Spring Transaction 과 MyBatis 와의 작동방식을 이해해야 한다.
먼저 <tx:method name="get*" read-only="true"/> 의 propagation 은 기본값인 REQUIRED 이다. propagation="REQUIRED" 는 서비스 메소드 실행 직전에 기존에 생성된 Transaction 이 있으면 생성된 Transaction 에 참여하게 되고 생성된 Transaction 이 없으면 신규로 생성해서 사용한다. 신규로 생성하는 시점에 Spring의 DataSourcePlatformTransactionManager 에 의해 read-only=true 설정에 따라 db connection 의 readOnly 설정을 true 로 셋팅하게 되고, replica 서버로 부하가 분산된다.
하지만 propagation 이 SUPPORTS 로 설정되면 기존에 생성된 Transaction 이 생성됬을때만 참여하고 생성된 Transaction 이 없으면 신규생성하지 않는다.
결국 <tx:method name="get*" read-only="true" propagation="SUPPORTS"/> 의 상황에서는 Spring Transaction 이 생성되지 않고, MyBatis에게 Transaction 관리가 위임되며, 아시다시피 MyBatis는 Spring 처럼 선언적 트랜젝션 처리를 지원하지 않아 자동으로 db connection 의 readOnly 설정을 처리하지 않는다. 따라서, mysql이 master 서버로 query 가 수행되는것이다.
<tx:method name="get*" read-only="true" propagation="SUPPORTS"/> 로 설정해도 mysql의 replica 서버로 보낼수 있는 방법을 고민한 결과 mybatis-spring 연동모듈에서 db connection 을 처리하는 TransactionFactory 를 확장해서 readOnly 를 true로 설정하게끔 하였다.
Spring 환경에서 MyBatis 가 db connection 을 가져오는 소스(SpringManagedTransaction)는 아래와 같다.
private void openConnection() throws SQLException { this.connection = DataSourceUtils.getConnection(this.dataSource); this.autoCommit = this.connection.getAutoCommit(); this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource); if (logger.isDebugEnabled()) { logger.debug( "JDBC Connection [" + this.connection + "] will" + (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring"); } }
위 소스 마지막 부분에 아래와 같은 코드를 삽입하여 새로운 클래스를 만들고
if (this.connection != null && this.isConnectionTransactional && this.autoCommit) { if (this.logger.isDebugEnabled()) { this.logger.debug("set connection read only"); } this.connection.setReadOnly(true); }