ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스레드 덤프로 확인할 수 있는 문제
    Backend/Java and Trouble Shooting 2020. 2. 23. 14:27

    스레드 덤프*로 어떤 문제를 확인할 수 있을까? (*스레드 단면)


     1 . 시스템 다운

    • 시스템 다운의 경우 스레드 덤프가 기본적으로 생성되지 않아 좋은 단서가 될 수 없다.
    • JVM 옵션에 OnError 이벤트에 대해 스레드 덤프가 남도록 하여 실마리를 잡을 수도 있다.
    -XX:OnError="kill -3 %p"
    -XX:ErrorFile=파일경로

     2 . 시스템 느려짐

    • 가장 많이 발생하는 현상으로 시스템이 느려진다면 다음과 같은 순서로 확인하는 것이 좋다.
    1. CPU, 메모리와 같은 리소스 사용량 점검
    2. 외부와 연동하는 리소스 사용량 점검
    3. WAS 메모리 및 스레드 설정 및 사용량 점검
    4. Web 서버 설정 점검
    5. OS 설정 점검
    6. 스레드 상태 점검
    7. 메모리 상태 점검
    • 위 절차를 도식화한 것은 다른 글에서 정리하도록 하겠다. 여기서는 6번의 스레드 상태를 점검하는 것만 알아보자.
    • Application의 성능이 느려졌을 때는 APM(Application Performance Monitoring)을 사용하여 프로파일링을 해보는 것이 좋다.
    • Web Application에서 대부분의 응답 시간이 느려지는 원인 중 대부분(약 80% 정도)은 DB와 같은 WAS와 연동되는 외부 서버들 때문이다.  DB SQL 성능이나 DB서버의 CPU 사용량은 어떤지, DB에 Lock이 발생하지 않았는지, 다른 외부 연동 서버들의 상태는 괜찮은지를 먼저 확인해 봐야 한다.

    3 . 시스템 응답 없음

    • 스레드 덤프가 가장 큰 효과를 발휘하는 경우로, 어떤 스레드에서 응답을 주지 않아 시스템이 멈추어 버렸는지 매우 쉽게 찾을 수 있다. 
    • 시스템이 응답하지 않을 때 보통 WAS가 정해 놓은 스레드 풀이나 DB 커넥션 풀이 꽉 찼을 확률이 높다.
    • 이 때, 스레드 덤프를 30초에서 1분 단위로 발생시킨 후 APM을 통해 확인을 해본다.
    • 응답이 없는 경우 다음 순서로 확인 해보자
    1. 전체 스레드의 개수를 확인한다.
    2. Java 6 이상일 경우, 스레드 덤프의 루트 노드를 클릭하여 메모리 사용량을 확인하고, 여러 개의 덤프 파일을 비교해 가며 값의 변화를 확인 한다.
    3. 모니터 목록에서 빨간색으로 표시되어 여러 스레드를 잡는 녀석이 없는지 확인한다.
    4. 해당하는 문제가 보이지 않을 때, Runnable 상태의 스레드를 확인하자.
    5. 지속해서 수행중인 스레드가 존재하지 않는지 "Long running threads detect" 기능을 사용하여 확인한다.

    그래도 원인이 없어 보인다면... 다른 원인을 찾을 수 밖에... 


    if 웹서버 설정?, 웹서버 문제?
    then 웹서버 설정이나 로그도 확인 해보자.
    if JVM 힙 메모리 부족?  
    then 스레드 단면 + 메모리 단면을 같이 사용하면 문제 원인 빠르게 확인 가능하다. 왜냐하면 메모리 부족할 경우 GC관련 스레드가 상태(Runnable)이면서 CPU 코어를 하나 이상 100% 점유하고, 나머지 모든 스레드는 아무런 작업을 하지 않을 수  있기 때문이다.
    스레드 실행 중인 상태 → CPU 코어 하나가 100% 이상 사용 → 메모리 상태 모니터링

     

    이러한 상황에서는 다음과 같이 분석하자.

    1. 스레드 덤프를 주기적으로 떠놓는다.
    2. 스레드 덤프를 뜰 때, ps -Lf -p pid 명령어도 같이 수행하여 주기적으로 떠 놓는다.
    3. CPU 사용 시간이 지속해서 증가하는 스레드가 있다면, pid확인 후 APM을 통해 어떤 스레드인지 확인해 본다.
    4-1. 해당 스레드가 GC관련 스레드라면, 메모리가 부족하거나 GC알고리즘에 문제가 발생했을 확률이 높다. 따라서 jstat 명령어로 메모리 사용량을 확ㅇ인한 후 메모리가 부족하면 메도리 단면을 떠서 어떤 객체가 메모리를 가장 많이 잡고 있는지를 확인해 본다.
    > jstat -gcutil 5s
    (*메모리 단면을 발생시키는 동안에는 해당 JVM이 완전 중단되어 WAS가 각종 사용자의 요청을 처리하지 못하므로 유의해서 작업해야 한다.)
    4-2. GC 관련 스레드가 아닌 다른 스레드라면 해당 스레드가 지속해서 수행되고 있는지(무한 루프) 확인해 본다.

    ※ TimeoutExcept이 지속 반복되는 경우...

    • DB sql 성능 저하로 WAS에 설정해 놓은 Timeout 시간내에 리턴이 오지 않은 경우.

    • GC 설정시간 이상 응답이 없어 처리되는 경우.

    • 각종 외부 시스템에서 응답이 없는 경우. 

     

     


    사례 보기

    사례 1. CPU 사용량이 갑자기 올라가서 안내려 오는 경우

    더보기

    상황

    시스템의 서버들의 CPU 사용량이 불규칙적으로 증가한 후 떨어지지 않는 현상이 발생했다. 이전에도 가끔 유사 현상이 있었지만, 이번에는 전체 서버에서 문제가 발생하고 있다. APM을 통해 CPU 사용량 확인 시, 계단형으로 증가하는 경향을 확인 하였다.

     

    접근방법

    CPU 사용량이 올라가는 원인은 여러 가지다. 각 CPU가 어떻게 점유하는지 확인한다.

    4개의 CPU 중 하나의 CPU만 100%고 나머지는 0~3%를 유지했다. 이 경우 다음과 같은 원인을 유추할 수 있다.

     a.  Application 로직상의 문제 (무한루프)

     b.  XML 라이브러리 문제로 특수만자가 들어왔을 때 parsing을 제대로 못 하고 무한루프 빠졌을 때

     c.  정규 표현식을 잘못 사용 하여 무한 루프에 빠졌을 때

     d.  메모리가 부족하여 GC관련 스레드만 반복적으로 수행하고 있을 때

     

    result1. 전체 CPU를 사용하게 되는 상황 (a,b,c)

    이 경우 전체 CPU를 사용하게 되는 상황으로 확장할 확률이 높다. 처음에는 25% 쓰다 50%, 75%, 100%로 증가하는 것이다. 왜냐하면 문제의 로직을 수행한 사용자가 응답이 없으면, 재시도하여 서버에 동일한 요청을 하기 때문이다. 다음과 같이 확인 하였다.

      1)  스레드 덤프를 30s ~ 1m 간격으로 5~10회 정도 생성

           >  kill -3 pid

      2) 스레드 덤프 생성 시, 동시에 각 스레드 별 사용 시간에 대한 덤프도 생성

           > ps -Lf -p pid

      3) APM을 통해 분석

      4) 가장 수행시간이 오래된 pid 확인 (오랫동안 수행되어 왔으면서, 덤프를 생성할 때마다 시간이 증가한 경우)

      5) 해당 스레드가 어떤 작업을 하고 있는지 스택 정보를 확인

      6) 결과 공유

     

    result2. 메모리 관련 문제의 경우 (d)

    이 경우 코어 하나만을 점유해서 지속해서 증가할 확률이 높다. 메모리 분석 글에서 확인하자.

     

    사례 2. 스레드 풀의 스레드 개수가 계속 증가하는 경우

    더보기

    상황

    WAS의 스레드 풀을 최대 1,024개로 설정하여 사용하고 있다. 그런데 이 스레드 풀이 꽉 차는 현상이 발생했다. 그런데 이상현상은 10대의 장비 중 1대의 장비에서만 이런 현상이 발생하는 것이다.

     

    접근방법

    스래드 개수가 증가하는 상황이기 때문에 스레드 덤프를 가장 먼저 떠봐야 한다. (주기적으로 여러번)

    스레드 덤프를 APM을 통해 분석해 본 결과 록이 잠겨 대기하고 있는 스레드의 종류가 다양 했으며, 각 록별로 용도가 달랐다.

    해당 스레드의 스텍 정보에서 공통으로 발견되는 부분이 바로 I/O 관련 부분이 있었다.

    네개의 스레드 스택 정보를 통해 최초 록을 발생한 원인을 분석할 수 있었다.

     

    사례 3. 시스템의 응답이 없는 경우

    더보기

    상황

    시스템 응답이 없다는 보고를 받고, WAS가 응답하지 않음을 확인했다. CPU는 하나만 줄기차게 사용하고 있으며, 스레드 덤프와 ps -Lf 명령어를 사용하여 어떤 스레드가 CPU를 계속 사용하고 있는지에 대한 자료는 모아 두었다.

     

    접근방법

    ps -Lf 명령어로 수집한 데이터를 토대로 장기간 수행중인 스레드가 발견되었고, 몇몇 스레드 역시 오랜 시간 수행 중이었다.

    이 Native ID 기반으로 스레드 덤프 분석도구를 통해 확인 결과 GC관련 스레드임을 확인 하였다.

     

    이러한 상황에서 장애를 발생한 가장 유력한 용의자는 메모리 릭(leak)이다. JVM을 지속해서 사용하면서 어떤 어플리케이션 메모리를 풀어주지 않고 야금야금 먹는다면, 이 애플리케이션은 언젠가 할당해 놓은 메모리가 부족해 질 것이다. 

     

    스레드 덤프는 반드시 장애 상황에서 떠야 합니다.. 혹여나 리스타트 후에 덤프를 뜨는 경우가 있다면, 소용 없는 행동 입니다.


    참고 자료: 자바 트러블 슈팅. 이상민 지음

     

    본 내용은 위 책을 통해 공부하며 정리한 내용 입니다.

     

    하기 글에 내용 정리가 잘 되어 있습니다.

    https://d2.naver.com/helloworld/10963

    불러오는 중입니다...

     

Designed by Tistory.