간단하게 서버 부하를 점검할 수 있는 무료 툴


http://openwebload.sourceforge.net


윈도용은 설치는 따로 필요없고 사용법도 간단함

# 에피소드 1

public void someMethod() {

    1) .... some logic ....

    2) .... System.out ....

}

위 someMethod()의 1)번 로직 수행에 문제가 있어 로직을 수정한 후 실행시켰는데 반영이 안된다.

그래서 2)번 위치에 System.out을 찍었는데 1)번 로직만 실행되고 2)번에 추가한 System.out은 실행되지 않는다.

내 PC에 문제가 있는 건가? 뭐가 문제일까?


# 에피소드 2

@Scheduled(cron="0 * * * * ?")
public void doSchedule() {

    1) .... DB에서 데이타 가져온 후 대상 자료 있으면 수행하는 로직 .... 에러 발생 시 DB에 에러로그 등록됨

}

Spring에서 지원하는 스케줄러 어노테이션을 이용해 1분마다 실행되는 로직을 1)번에 삽입했다.

1)번 로직에 문제가 생겨 DB에 에러로그가 계속 쌓이고 있어서 1)번 로직을 주석처리 후 반영했다. 

그럼에도 불구하고 1)번 로직이 수행되어 DB에 에러로그가 1분마다 계속 쌓인다. 

내 PC에 유령이 있는 것인가? 뭐가 문제일까?


# 에피소드 1 : 이클립스의 Project > Build Automatically 옵션이 꺼져 있었다. ㅠㅠ 

# 에피소드 2 : 해당 스케줄러가 다른 개발자 PC에서도 수행되고 있었다. 결국 그 개발자 PC의 시스템 시간이 내 PC보다 몇밀리초 빨라서 그 쪽 PC에서 위 로직이 먼저 실행된 것이다. ㅠㅠ


결론 : 컴퓨터는 거짓말을 하지 않는다. 이것은 진리 !!!!



로컬 윈도우 환경에서는 잘 돌아가는 녀석이, 서버(리눅스) 에만 올리면 "There is no result map named" 에러가 발생한다. 

구글신에게 물어봐도 답을 찾지 못했다. 결국 금요일 퇴근도 못하고 삽질 3시간 후 해결 .... ㅠㅠ

AAAA-sqlmap.xml

<sqlMap namespace="_AAAA">


    ....


    <resultMap id="myMapId" class="XXXX">

    ....

    </resultMap>


    ....


</sqlMap>

 
BBBB-sqlmap.xml

<sqlMap namespace="_BBBB">


    ....


    <select id="list" resultMap="_AAAA.myMapId" parameterClass="XXXX">

    ....

    </select>


    ....


</sqlMap>


이렇게 사용해야 될 경우에는 sqlmap 파일의 로딩순서에 유의해야 한다.

sqlmap-config.xml 파일에 수동으로 기능별 sqlmap 파일을 선언해 줄 경우에는 아래와 같이 AAAA-sqlmap.xml을 먼저 선언해줘야 한다.

<sqlMapConfig> 

    ....

    <settings enhancementEnabled="true" useStatementNamespaces="true"/> 

    <sqlMap resource="com/foo/AAAA-sqlmap.xml" /> 

    <sqlMap resource="com/foo/BBBB-sqlmap.xml" /> 

    ....

</sqlMapConfig> 



만약 스프링과 연동하여 sqlmap 파일을 자동으로 로딩해서 사용하고 있을 경우에는 아래와 같이 해주도록 한다.

<bean id="sqlMapClient"

    class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">

    ....

    <property name="mappingLocations">

        <list>

            <value>classpath*:/com/foo/AAAA-sqlmap.xml</value>

            <value>classpath*:/com/foo/BBBB-sqlmap.xml</value>

            <value>classpath*:/com/others/**/*-sqlmap.xml</value>

        </list>

    </property>

    ....

</bean>





아래의 코드에 따라 ....

@RequestMapping(value="/club/{seq}")

public String clubFrame(@PathVariable("seq") Integer seq) {

    return "/club/ER_index";

}

 
주소창에 /club/3 을 입력하면 NoSuchRequestHandlingMethodException 예외가 발생하는 경우가 있다.

참고로 web.xml에는  

<servlet-mapping>

    <servlet-name>dispatcher</servlet-name>

    <url-pattern>*.do</url-pattern>

</servlet-mapping>

<servlet-mapping>

    <servlet-name>dispatcher</servlet-name>

    <url-pattern>/club/*</url-pattern>

</servlet-mapping>

 와 같이 설정되어 있다.

해결책은 아래와 같다.

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">

    <property name="alwaysUseFullPath" value="true" />

    ....

</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">

    <property name="alwaysUseFullPath" value="true" />

    ....

</bean>

 
톰캣 설정
context-1.xml
<Context crossContext="true" .... 생략

context-2.xml 
<Context crossContext="true" .... 생략

테스트
context-1.jsp 

<%

    ServletContext ctx = application.getContext("/context-1");

    Integer counter = (Integer)ctx.getAttribute("counter");

    if (counter == null) {

        counter = 0;

    }

    counter++;

    

    request.setAttribute("counter", counter);

    ctx.setAttribute("counter", counter);

%>


<h1>Context-1</h1>

<h1>현재 카운터는 ${counter}입니다.</h1>


context-2.jsp

<%

    ServletContext ctx = application.getContext("/context-1");

    Integer counter = (Integer)ctx.getAttribute("counter");

    if (counter == null) {

        counter = 0;

    }

    counter++;

    

    request.setAttribute("counter", counter);

    ctx.setAttribute("counter", counter);

%>


<h1>Context-1</h1>

<h1>현재 카운터는 ${counter}입니다.</h1>


출처 : http://jee-bpel-soa.blogspot.com/2009/06/session-sharing-in-apache-tomcat.html
 

 
Sitemesh 2.4.1 버전은 기존의 PageFilter가 SitemeshFilter로 바뀌었다.

이번 버전에서는 아래와 같은 에러가 데코레이션 되는 URL에서는 발생하지 않지만 데코레이션 되지 않는 URL에서는 여전히 발생한다.

ProtocolException : Didn't meet stated Content-Length

Sitemesh 이전 버전에서의 해결방법은 http://finkle.tistory.com/56 게시글 참조

Sitemesh 2.4.1 버전에서 해결방법은 아래와 같다.
com.opensymphony.sitemesh.webapp.decorator.NoDecorator 클래스를 아래와 같이 수정한다.

if (Container.get() != Container.WEBLOGIC) {
    response.setContentLength(content.originalLength());
}

또 하나, 보통 SpringMVC 3.0에서 Annotation을 통해 JSTL View를 지정하여 화면을 렌더링 하는데 Sitemesh 데코레이션 파일에 설정된 URL을 Weblogic에서는 제대로 인식하지 못한다.

아래 설정정보는 Tomcat에서 잘 작동하는 데코레이션 설정인데 Weblogic에서는 데코레이션 되지 않는다.

decoration.xml

<decorator name="xxxx_manage" page="xxxx/common/decorator/xxxx_manage.jsp">
    <pattern>/manage/**/xxxx_*.do</pattern>
</decorator>

해결방법은 아래와 같다.

<decorator name="xxxx_manage" page="manage/common/decorator/xxxx_manage.jsp">
    <pattern>/manage/**/xxxx_*.do</pattern>
    <pattern>/WEB-INF/view/manage/**/xxxx_*</pattern> <!-- For weblogic -->
</decorator>


ANT 빌드 스크립트에서 아래와 같이 Tomcat 재기동 작업을 설정 후 Hudson에 연결했을 경우 생성되는 Hudosn 하위 프로세스가 종료되지 않고 대기하는 문제가 발생한다.

<target name="tomcat.stop" >
    <echo>Stopping Tomcat server instance</echo>
    <exec executable="/etc/init.d/tomcat6">
       <arg value="stop" />
    </exec>
</target>

<target name="tomcat.restart" depends="tomcat.stop">
    <sleep seconds="2" />
    <echo>Starting Tomcat server instance</echo>
    <exec executable="/etc/init.d/tomcat6" spawn="true">
        <arg value="start" />
    </exec>
</target>

spawn :  하위 프로세스를 생성해서 실행하는 옵션

이런 경우에는 hudson 실행 스크립트에서 아래와 같은 옵션을 주어 해결하자.

-Dhudson.util.ProcessTreeKiller.disable=true

10g XE에서 잘 돌아가던 넘이 운영서버 환경에 올리자 CLOB 등록이 안된다.

iBatis 단독 사용 시 CLOB 넣기

sqlmap-config.xml

<typeHandler javaType="string" jdbcType="CLOB" callback="test.OracleClobStringTypeHandler"/>
 
<transactionManager type="JDBC">
    <dataSource type="SIMPLE">
        <property name="JDBC.Driver" value="oracle.jdbc.driver.OracleDriver" />
        <property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@xxxxx:1521:SID" />
        <property name="JDBC.Username" value="${ID}" />
        <property name="JDBC.Password" value="${PASS}" />
    </dataSource>
</transactionManager>

logic-sqlmap.xml

INSERT INTO TABLE_NAME (
    SEQ, TITLE, CONTENTS
)
VALUES(
    #seq#, #title#, #contents:CLOB#
)

iBatis + Spring단독 사용 시 CLOB 넣기

application-context.xml

<bean id="dataSource"
    class="org.springframework.jndi.JndiObjectFactoryBean">
   <property name="jndiName" value="java:comp/env/jdbc/jndiNameDS"/>
</bean>

<bean id="sqlMapClient"
    class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
    <property name="configLocation" value="WEB-INF/conf/sqlmap-config.xml" />
    <property name="dataSource" ref="dataSource" />
    <property name="lobHandler"><ref bean="oracleLobhandler"/></property>
</bean>

<bean id="nativeJdbcExtractor"
    class="org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor"
    lazy-init="true" />

<bean id="oracleLobhandler"
    class="org.springframework.jdbc.support.lob.OracleLobHandler"
    lazy-init="true">
    <property name="nativeJdbcExtractor">
        <ref local="nativeJdbcExtractor" />
    </property>
</bean>

sqlmap-config.xml

<typeHandler
    callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"
    jdbcType="CLOB" javaType="java.lang.String" />

logic-sqlmap.xml

INSERT INTO TABLE_NAME (
    SEQ, TITLE, CONTENTS
)
VALUES(
    #seq#, #title#, #contents:CLOB#
)

java.lang.NullPointerException at org.springframework.jdbc.support.lob.OracleLobHandler.initOracleDriverClasses(OracleLobHandler.java:150
) 에러 발생 시


application-context.xml

JNDI -> DBCP로 변경
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
     <property name="driverClassName" value="oracle.jdbc.OracleDriver" />
     <property name="url" value="jdbc:oracle:thin:@xxxx:1521:SID" />
     <property name="username" value="${ID}" />
     <property name="password" value="${PASS}" />
     <parameter name="maxActive" value="20" />
     <parameter name="maxIdle" value="5" />
     <parameter name="maxWait" value="5000" />
     <property name="validationQuery" value="SELECT 1 FROM DUAL" />
</bean>

Oracle JDBC 드라이버는 ojdbc14.jar (최신버전)으로 적용.

http://opensource.atlassian.com/confluence/oss/display/IBATIS/Environment+Specific+Information

Timeout
As of release 2.2.0, iBATIS includes a query timeout funcionality.
You can specify both a global timeout
  
<settings defaultStatementTimeout="2" />
or a per query timeout
  
<statement ... timeout="2">
When the timeout expires, it throws a SQL Exception "ORA-01013 : user requested cancel of currentoperation".
  
Tested with: Oracle 9i release 2 drivers.

결론 : 수행에 3초이상 걸리는 쿼리가 있다면 해당 쿼리 정의문에 timeout attribute를 주던가 기본 sqlmap-config.xml 파일의 defaultStatementTimeout 값을 늘려주어라.

+ Recent posts