날짜별 글 목록: 2008년 7월 31일

자바 가비지 컬렉션 뷰어(Garbage Collection Viewer)

자바의 가장 큰 장점은 애플리케이션이 사용하는 자원을 관리하지 않아도 자동으로 자원을 해제시키는 가비지 컬렉터의 존재이다. 자바로 개발하는 경우에는 가비지 컬렉션의 기본 지식을 알고 있는 것이 애플리케이션 개발 및 디버깅에 도움을 준다.

그래서 자바 애플리케이션의 메모리의 상태(가비지 컬렉션의 유무와 점유율 등)를 비주얼로 볼 수 있다면, 애플리케이션의 모니터링에 매우 도움이 될 수 있다. 그래서 가비지 컬렉션을 비주얼하게 보여주는 몇 가지 툴을 정리해 봤다.

* http://java.sun.com/performance/jvmstat/
* http://docs.hp.com/en/5991-6757/ch03s04.html
* http://java.sun.com/developer/technicalArticles/Programming/GCPortal/
* http://www.javaperformancetuning.com/tools/gcviewer/index.shtml

Application Server(Tomcat)의 효과적인 운영 방안

1. 어플리케이션 서버에서 필요한 메모리 계산 방법
 – 계산식 : (MaxProcessMemory – JVMMemory – ReservedOsMemory) / (ThreadStackSize) = Number of threads
 – 메모리 계산 예
가정 : Java 1.5를 사용중이며 OS가 120MB를, 디폴트 스택사이즈는 0.5M


  • JVM에 1.5GB할당되었을 경우 : (2GB-1.5Gb-120MB)/(1MB) = ~380 threads
  • JVM에 1.0GB할당되었을 경우 : (2GB-1.0Gb-120MB)/(1MB) = ~880 threads
통계적으로 대략 200명의 동시 사용자 수용할 경우 300MB정도 필요하합니다. 이것을 고려해서 메모리를 계산하면 됩니다.

2. Application Server 에러 대처 방안(java.lang.OutOfMemoryError: PermGen space 현상)


  • Tomcat의 경우 v6.0.14이상의 안정적 릴리즈 된것을 선택
  • JDK1.4보다는 1.5, 1.6의 사용을 권고함
  • -XXMaxPermSize 설정을 통해 perm 사이즈를 증가시킴
  • JHat으로 메모리릭 원인을 찾고 JConsole, Lambda probe 등을 통해 메모리 모니터링을 함
  • Application Server운영자는 Garbage Collection에 대한 이해가 있어야 함

3. Tomcat에서 설정 예시



  • 힙메모리 정보를 출력 : -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC

위 설정을 통해 출력되는 로그를 보고 New Generation의 eden 영역, Old Generation 영역, Permanent 영역을 확인하여 각 영역이 작으면 아래와 같은 설정으로 적당 사이즈를 확보해 줍니다.



  • 도출된 설정 : -Xms256m -Xmx512m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m -XX:SurvivorRatio=5
    -Xms : 최소 힙 싸이즈
    -Xmx : 최대 힙 싸이즈
    -XX:NewSize : New Generation의 최소 싸이즈
    -XX:MaxNewSize : New Generation의 최대 싸이즈
    -XX:MaxPermSize : Permanent Generation의 최대 싸이즈 가 되겠다.
    -XX:SurvivorRatio : 영역비율(New Generation)

결론적으로 적용할 설정은 아래와 같습니다.



  • CATALINA_OPTS=”-server -Xss256k -Xms256m -Xmx512m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m -XX:SurvivorRatio=5 -XX:ReservedCodeCacheSize=128m -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -Djava.net.preferIPv4Stack=true -Djava.awt.headless=true ”

Open Soure는 100% 안정적이지 않기 때문에 가장 최신의 안정적인 버젼이 릴리즈되는지 항상 예의 주시하여 버전업에 게을러서는 안됩니다

위 내용은 http://www.mimul.com/pebble/default/2008/01/26/1201346400000.html 에서 발췌를 하였습니다.

Apache iBatis에서 다중 데이터 베이스 사용 방법

Apache iBatis에서 다중 데이터 베이스에 접속하는 방법이다.

1. database.properties

driver=oracle.jdbc.driver.OracleDriver
jdbc.url1=jdbc:oracle:thin:@mimuluserdb:1521:mimuluser
username1=mimuluser
password1=mimuluser
jdbc.url2=jdbc:oracle:thin:@pepsiuserdb:1521:pepsiuser
username2=pepsiuser
password2=pepsiuser

2. sqlmap1.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<properties resource="com/mimul/dwr/app/
resource/database.properties"/>
<settings
cacheModelsEnabled="true"
enhancementEnabled="true"
lazyLoadingEnabled="true"
maxRequests="40"
maxSessions="20"
maxTransactions="5"
useStatementNamespaces="false"
/>
<transactionManager type="JDBC">
<dataSource type="DBCP">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${jdbc.url1}"/>
<property name="username" value="${username1}"/>
<property name="password" value="${password1}"/>
<!-- OPTIONAL PROPERTIES BELOW -->
<property name="initialSize" value="5"/>
<property name="maxActive" value="30"/>
<property name="maxIdle" value="20"/>
<property name="maxWait" value="60000"/>
<property name="poolPreparedStatements" value="true"/>
<property name="validationQuery" value="select 0 from dual"/>
<property name="testOnBorrow" value="true"/>
<property name="maximumActiveConnections" value="10"/>
<property name="maximumIdleConnections" value="5"/>
<property name="maximumWait" value="60000"/>
<property name="logAbandoned" value="false"/>
<property name="removeAbandoned" value="false"/>
<property name="removeAbandonedTimeout" value="50000"/>
</dataSource>
</transactionManager>
<sqlMap resource="com/mimul/dwr/app/sql/Mimul.xml"/>
</sqlMapConfig>

3. sqlmap2.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<properties resource="com/mimul/dwr/app/resource/database.properties"/>
<settings
cacheModelsEnabled="true"
enhancementEnabled="true"
lazyLoadingEnabled="true"
maxRequests="40"
maxSessions="20"
maxTransactions="5"
useStatementNamespaces="false"
/>
<transactionManager type="JDBC">
<dataSource type="DBCP">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${jdbc.url2}"/>
<property name="username" value="${username2}"/>
<property name="password" value="${password2}"/>
<!-- OPTIONAL PROPERTIES BELOW -->
<property name="initialSize" value="5"/>
<property name="maxActive" value="30"/>
<property name="maxIdle" value="20"/>
<property name="maxWait" value="60000"/>
<property name="poolPreparedStatements" value="true"/>
<property name="validationQuery" value="select 0 from dual"/>
<property name="testOnBorrow" value="true"/>
<property name="maximumActiveConnections" value="10"/>
<property name="maximumIdleConnections" value="5"/>
<property name="maximumWait" value="60000"/>
<property name="logAbandoned" value="false"/>
<property name="removeAbandoned" value="false"/>
<property name="removeAbandonedTimeout" value="50000"/>
</dataSource>
</transactionManager>
<sqlMap resource="com/mimul/dwr/app/sql/Pepsi.xml"/>
</sqlMapConfig>

4. SqlCondig.java

import java.io.File;
import java.io.Reader;
import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import com.jaeminara.common.log.LogPool;
public class SqlConfig {
  private static SqlMapClient sqlMap1 = null;
  private static SqlMapClient sqlMap2 = null;
  private static SqlConfig instance_ = null;

  private SqlConfig() throws Exception {
    Reader reader = null;
    String resource = null;
    try {
      if (sqlMap == null) {
        resource = "sqlmap1.xml";
        reader = Resources.getResourceAsReader(resource);
        sqlMap1 = SqlMapClientBuilder.buildSqlMapClient(reader);
        resource = "sqlmap2.xml";
        reader = Resources.getResourceAsReader(resource);
        sqlMap2 = SqlMapClientBuilder.buildSqlMapClient(reader);
        reader.close();
      }
    } catch (Exception e) {
      System.out.println(e);
      throw e;
    } finally {
      if (reader != null)
      reader.close();
      reader = null;
      rsc = null;
    }
  }

  public static SqlConfig instance() {
    try {
      if (instance_ == null) {
        synchronized (SqlConfig.class) {
          if (instance_ == null)
            instance_ = new SqlConfig();
        }
      }
    } catch (Exception e) {
      System.out.println(e);
    }
    return instance_;
  }

  /**
  * Return SqlMapClient for SDP schema
  *
  * @return
  */
  public static SqlMapClient getSqlMap1Instance() {
    return sqlMap1;
  }

  /**
  * Return SqlMapClient for SDP schema
  *
  * @return
  */
  public static SqlMapClient getSqlMap2Instance() {
    return sqlMap2;
  }
}

* Reference
http://mimul.com/pebble/default/2008/02/24/1203779580000.html