Spring 의 AbstractRoutingDataSource와 Mybatis의 Mapper를 이용하여 코딩을 했다는 내용의 글을 올렸다.

 

http://knight76.tistory.com/entry/mysql-%EC%97%90%EC%84%9C-%EB%8F%99%EC%9D%BC%ED%95%9C-table-schema%EB%A5%BC-%EA%B0%80%EC%A7%84-Multi-DB-%EB%A5%BC-java%EB%A1%9C-%EC%A0%91%EA%B7%BC%ED%95%98%EA%B8%B0

 

 

Mybatis의 Mapper 클래스와 XML를 이용한 것은 기존의 Mybatis의 XML을 쓰기 편한 장점이 있었다.

 

 

대충 관련코드를 공유..

 

 

public class DynamicRoutingDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicContextHolder.getDataSourceName();
    }

}

 

 

 

mybatis의 SqlSessionFactoryBean를 상속받아 SqlSessionFactory를 생성하게 하는 Bean.

 

 

public class DynamicSqlSessionFactoryBean extends SqlSessionFactoryBean {

    private DataSource dataSource;

    private Resource configLocation;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void setConfigLocation(Resource configLocation) {
        this.configLocation = configLocation;
    }

    public SqlSessionFactory buildSqlSessionFactory() {
        super.setConfigLocation(configLocation);
        super.setDataSource(dataSource);
        SqlSessionFactory factory = null;
        try {
            factory = super.buildSqlSessionFactory();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return factory;
    }

    public void afterPropertiesSet() throws Exception {
    }

}

 

 

@Aspect
@Component
public class ExecutionAspect implements InitializingBean {

 

public Object distribute(ProceedingJoinPoint joinPoint) throws Throwable {
      

    … 중략..

 

 

        SqlSessionFactory s = createSqlSessionFactory(dataSourceNumber);


        SqlSession sqlSession = s.openSession();
        DynamicContextHolder.setSqlSession(sqlSession);

        Object returnValue = joinPoint.proceed();

        DynamicContextHolder.clear();
        return returnValue;

 

}

 

createSqlSessionFactory () 메소드가 DynamicSqlSessionFactoryBean 의 buildSqlSessionFactory를 매번 생성하도록 하였다.

 

처음에는 괜찮아보였지만. 성능상 큰 이슈가 발생했다.

 

 

mybatis의 mapper xml를 사용하기 위해서 매번 mybatis의 SqlSessionFactory생성하는 코드를 넣을 때 유의해야 한다. 성능이 떨어질 수 밖에 없다.

(또한, AbstractRoutingDataSource 사용 자체가 매번 DB connection을 DBPool로부터 fetch 해서 사용하고 close 하는 것도 성능 이슈이긴 했다. )

 

 

성능이 잘 안 나와서 덤프를 떠보니.. Blocked 된 쓰레드를 많이 발견했다.

XML을 매번 읽어서 SqlSessionFactory를 만드는 작업은 xerces lock 에 의해서 성능을 떨어뜨리도록 되어 있다.

 

 


"TP-Processor1275" daemon prio=10 tid=0x00002aaabc31c800 nid=0x11d4 waiting for monitor entry [0x0000000044f6f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.sun.org.apache.xerces.internal.impl.dv.DTDDVFactory.getInstance(DTDDVFactory.java:44)
    - waiting to lock <0x00000006f0854ae8> (a java.lang.Class for com.sun.org.apache.xerces.internal.impl.dv.DTDDVFactory)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.<init>(XML11Configuration.java:538)
    at com.sun.org.apache.xerces.internal.parsers.XIncludeAwareParserConfiguration.<init>(XIncludeAwareParserConfiguration.java:125)
    at com.sun.org.apache.xerces.internal.parsers.XIncludeAwareParserConfiguration.<init>(XIncludeAwareParserConfiguration.java:86)
    at sun.reflect.GeneratedConstructorAccessor10.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at java.lang.Class.newInstance0(Class.java:355)
    at java.lang.Class.newInstance(Class.java:308)
    at com.sun.org.apache.xerces.internal.parsers.ObjectFactory.newInstance(ObjectFactory.java:349)
    at com.sun.org.apache.xerces.internal.parsers.ObjectFactory.createObject(ObjectFactory.java:154)
    at com.sun.org.apache.xerces.internal.parsers.ObjectFactory.createObject(ObjectFactory.java:97)
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.<init>(DOMParser.java:133)
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.<init>(DOMParser.java:117)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.<init>(DocumentBuilderImpl.java:115)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl.newDocumentBuilder(DocumentBuilderFactoryImpl.java:72)
    at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:237)
    at org.apache.ibatis.parsing.XPathParser.<init>(XPathParser.java:122)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.<init>(XMLMapperBuilder.java:74)
    at org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XMLConfigBuilder.java:310)
    at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:104)
    at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:89)
    at org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:374)
    at jp.google.center.multidatasource.DynamicSqlSessionFactoryBean.buildSqlSessionFactory(DynamicSqlSessionFactory
Bean.java:42)
    at jp.google.center.multidatasource.ExecutionAspect.distribute(ExecutionAspect.java:110)

 

 

 

구글에 검색해보니.. 이미 성능 이슈가 난 것으로 알려져 있다. (fixed가 되어 있다.jaxb도 연관되어 있었음을 확인할 수 있다. )

https://issues.apache.org/jira/browse/CXF-3180

 

 

결국. AbstactDataSourceRouter를 제외하는 구조로 변경했다. 미리 Connection Pool과 Mybatis SqlSessionFactory를 초기화과정에서 만들어지도록 했다. 만들어진 SqlSessionFactory를 사용하도록 하니.

성능이 3배 정도로 나왔다.

Posted by 김용환 '김용환'

댓글을 달아 주세요