spy memcached(arcus) 를 사용하면서 발생했다.

Context switching이 갑작스럽게 많아지고, 결국 외부 인터페이스 (db, memcached) timeout과 서버가 문제되는 문제가 발생했다.

Request 의 양과 상관없이 시도 때도 없이 발생했다. (초반에는 traffic peak치 때 발생했었다.)

 


자바 서비스는 GC는 g1을 쓰고 있었고, JAVA 1.7.0 25 버전을 쓰고 있었다.

 

문제는 다음 부분이다.

 

1. jvm thread dump시 epoll 코드에서 cpu 가 높게 사용되는 현상

2. memcached client(arcus client)에서 timeout 나는 현상 (arcus 서버는 문제 없음)

3. memcached client 특정 메소드가 높게 사용되는 현상

4. context switching 이 점점 쌓이는 것처럼 점점 많아지는 현상 (memory leak처럼 context switching값이 커짐)

5. cpu가 높아질 때, l4에서 뺏다가 다시 넣으면 다시 cpu가 튀는 현상 (단시간, 장시간 모두 문제 발생)


 

인터넷에 검색하면서 메모리 증설로 해결봤다니, 옵션 추가니 다 해 봤지만 실익이 없었다.

 

하지만, 결정적인 부분을 보고 문제 방식을 jvm으로 생각하게 되었다.

 


thread dump를 뜰 때, 10초에 한번씩 이렇게 뜬 다음에 비교하지 않고, 10초동안 덤프 끝나자마자 연달아 떠보자는 의견이 있어서 해봤더니..

 

간단한 memory access(beans get)에서 오랫동안 멈추어져 있던 것을 발견했다. 직감적으로 jvm 메모리 버그로 확신할 수 있었다. (java 1.4 시절 , 특정 linux 커널 버전에서는 메모리 이슈로 장애나는 부분이 있었다. )

 

 

원인을 linux 상에서 다음과 같이 분석했다.

1. 평상시는 문제가 없으나, 문제가 발생되는 서버에서 java total thread count는 늘어나, thread 개수 늘어가 자원 고갈 현상(?)이 보였다.  (모든 서버에서 발생하지 않고, 일부 서버에서만 발생하는 데. 마치 산에 올라가는 일부 일탈 회원의 느낌....)

2. java total thread cpu ration는 크게 변화가 없다. 

3. strace로 가장 높은 cpu를 쓰는 java thread attach 해도 특이현상이 없다. (느려지는 부분은 있어도..)

 

 

 

따라서 thread 문제는 아니니, memory 문제라 판단했다. profiling 해도 메모리쪽이나 gc time쪽도 이슈가 없었다. 따라서 g1 gc 패치가 많이 발생한 버전인 java 8 update 20을 다운받아서 서버를 띄웠더니 더이상 문제는 발생되지 않았다.

 

 

 

원인은 정확치는 않지만, 개인적으로는 jvm의 G1 알고리즘 구현이라고 생각하고 있다. 소스가 공개된 것도 아니고 패치 내역만 있긴 하지만.. g1 이 새롭게 만들어진 gc 알고리즘이라 메모리 관리하는 부분에서 버그가 있었을꺼라 대충 예상하고 있다..

 

 

따라서, (개인적으로) 대용량 서비스에서 혹시 G1 GC를 쓰는 서버 애플리케이션의 경우, 반드시 java 8 update 20 또는  java 7 update 60 이상의 버전을 쓰도록 권고한다.

 

 

참조 : http://www.oracle.com/technetwork/java/javase/2col/8u20-bugfixes-2257730.html

http://www.oracle.com/technetwork/java/javase/2col/7u60-bugfixes-2202029.html

 



당시 나의 해결 방법은 Java8 update 20으로 올렸다. permgen과 (-XX:MaxTenuringThreshold=15) 이슈 빼고는 큰 문제가 없었다. 사실 당시에 java7 기반에서 java8로 올라가려고 하고 있었다. (지금도 진행중..)


http://knight76.tistory.com/entry/java-8%EC%9D%98-XXMaxTenuringThreshold-%EC%84%A4%EC%A0%95%EA%B0%92-%EB%B3%80%EA%B2%BD

Posted by '김용환'
,


새로운 프로젝트를 생성한 후,  slf4j를 사용하여 logging(Logger.info()) 이 출력했는데. 출력되지 않는 경우가 있다. Logging이 안된다면 slf4j-simple을 빌드 dependency에 포함시켰는지 확인한다. 




Logger 출력 클래스


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;


@Controller

@RequestMapping("test")

public class TestController {

  //private static final Logger logger = LoggerFactory.getLogger(TestController.class);

  private final Logger logger = LoggerFactory.getLogger(this.getClass());

  ..

}



log4j.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">


<!-- Appenders -->

<appender name="console" class="org.apache.log4j.ConsoleAppender">

<param name="Target" value="System.out" />

<layout class="org.apache.log4j.PatternLayout">

<param name="ConversionPattern" value="%-5p: %c - %m%n" />

</layout>

</appender>

<!-- Application Loggers -->

    <logger name="com.google.idp.admin">

        <level value="debug" />

    </logger>


<!-- 3rdparty Loggers -->

<logger name="org.springframework">

<level value="debug" />

</logger>


<!-- Root Logger -->

<root>

<priority value="info" />

<appender-ref ref="console" />

</root>

</log4j:configuration>



이럴 때는 pom.xml 파일을 살펴본다.


eclipse(또는 Spring Tool Suite)를 사용하고 있다면, Dependency Hierarchy를 살펴보아서 slf4j-simple이 제대로 포함되어 컴파일되어 있는지 확인해야 한다. 

만약 없다면 pom.xml 파일에 slf4j-simple dependency를 추가한다.


pom.xml


<!-- Logging -->

<dependency>

    <groupId>org.slf4j</groupId>

    <artifactId>slf4j-api</artifactId>

    <version>1.7.5</version>

</dependency>

<dependency>

    <groupId>org.slf4j</groupId>

    <artifactId>slf4j-simple</artifactId>  

    <version>1.7.5</version>

</dependency>

<dependency>

    <groupId>org.slf4j</groupId>

    <artifactId>jcl-over-slf4j</artifactId>

    <version>1.7.5</version>

</dependency>


Posted by '김용환'
,

log4jdbc

java libs 2011. 12. 16. 10:40

jdbc driver 의 PreparedStatement에 대한 코드를 잘 분석해줄 수 있는 툴이다.

select * from athlete where code=?  이라는 쿼리에 동적으로 데이터 A 를 넣는 경우에 로그로

select * from athlete where code=A 라고 출력한다.

참고 자료

http://stackoverflow.com/questions/6315057/log4jdbc-preparedstatement-tostring

http://code.google.com/p/log4jdbc/

http://www.mimul.com/pebble/default/2008/10/24/1224847200000.html

http://www.cubrid.com/zbxe/modules/board/skins/xe_board_cubrid_tutorial/tutorial.php?srl=47278&htm=log4jdbc.htm

http://dev.anyframejava.org/anyframe/doc/core/3.1.0/corefw/guide/query-sqllogging.html

Posted by '김용환'
,

Apache Commons 프로젝트에서는 Nexus를  활용하려는 계획을 가지고 있다. 

현재 정식 문서가 아닌 Draft 이긴 하지만, nexus를 사용하려는 위키를 발견했다.

http://wiki.apache.org/commons/UsingNexus

 

짧게 내용을 얘기한다면.

deploy 가 바로 배포되지 않게 한다. 중간에 nexus를 통해서 jar를 올리면, maven repository 에 deploy를 하지 않고 caching을 내부적으로 가지고 있다가, contributer들이 vote를 해서 vote 결과에 따라서 배포여부를 결정하게 된다.

의견을 서로 주고 받으면서 배포할 수 있는 모델이라 많이 도움이 될만한 툴로 쓰지 않을까 생각도 든다.

Posted by '김용환'
,

Ehcache에서 persistent 기능을 활용하다가 종료시 이 데이터를 잘 저장하려면,
tomcat listener를 상속받은 ShutdownListener가 있다. 이 것을 활용하면 좋을 듯..


http://christiansons.net/mike/blog/2010/01/shutting-down-ehcache-properly/

<listener>
    <listener-class>net.sf.ehcache.constructs.web.ShutdownListener</listener-class>
</listener>
Posted by '김용환'
,