티스토리 뷰

728x90
반응형

 포스팅에서는 Linux에서의 CPU 과점유현상을 분석해보겠습니다. 


먼저 CPU 사용률은 서버의 중요한 성능포인트가 됩니다. CPU사용률이 지나치게 높을경우, Web/WAS 뿐만아니라 H/W, Network등의 bottleneck(병목)현상을 유발하게됩니다. 이번 포스팅에서는 Linux에서의 CPU과점유현상에 대해 알아봅니다.



먼저, 특정 계정의 CPU 사용률을 보기위한 명령어는 다음과 같습니다. 자세한 옵션은 아래에서 살펴보겠습니다. 

top -H -U [계정명]


[wildfly@kmkang~/jboss64/bin$]top -H -U wildfly




  PID   USER    PR  NI    VIRT      RES     SHR   S   %CPU   %MEM    TIME+ COMMAND

 4560 wildfly   20   0   7155556 587304  21260 R    99.9       7.4      26:49.26     java


* 필드

PID : 프로세스 ID (PID)

USER : 프로세스를 실행시킨 사용자 ID

PRI : 프로세스의 우선순위 (priority)

NI : NICE 값. 일의 nice value값이다. 마이너스를 가지는 nice value는 우선순위가 높음.

VIRT : 가상 메모리의 사용량(SWAP+RES)

RES : 현재 페이지가 상주하고 있는 크기(Resident Size)

SHR : 분할된 페이지, 프로세스에 의해 사용된 메모리를 나눈 메모리의 총합.

S : 프로세스의 상태 [ S(sleeping), R(running), W(swapped out process), Z(zombies) ]

%CPU : 프로세스가 사용하는 CPU의 사용율

%MEM : 프로세스가 사용하는 메모리의 사용율

COMMAND : 실행된 명령어


* 옵션

-a : 메모리 사용에 따라 정렬

-b : 배치 모드에서 시작

-c : 명령어 대신 명령어 라인을 보여줌

-d : 업데이트 간격을 조정

-h : 도움말

-H : 모든 개별 쓰레드가 보여짐

-i : 좀비(zombie) 또는 Idle 상태의 것들은 무시됨

-m : VIRT 대신 USED를 보고

-M : 메모리 유닛(K/M/G)을 보여줌

-n : 반복의 최대 수를 지정

-P : 지정된 프로세스 ID들만 보여줌

-s : 보안 모드로 시작

-S : 누적 시간 모드로 시작. 활성화되면 각 프로세스는 CPU를 사용한 시간과 함께 출력

-u : 지정된 유효 사용자에 의한 프로세스만 보여줌

-U : 지정된 사용자에 의한 프로세스만 보여줌. 사용자는 실제, 유효한, 저장된 및 파일시스템 UID를 의미

-v : 프로그램 라이브러리 버전을 출력


* top 실행 중 명령어
 * 스페이스바  : 화면 갱신
 * k : kill 명령
 * r : nice 값 변경

    (nice는 우선순위를 뜻하며, -20 ~ 20 까지 사용가능. 낮을수록 우선권이 높음. 기본값은 0)
 * Z : 화면 출력 색상 변경

     (a 또는 w를 누르면 색상이 순차적으로 변경되며 보여줌)
 * z : Z로 변경된 출력 색상과 기본 출력 색상간 전환
 * B : 글자 두껍게
 * l : top 출력 상단의 load avg 항목 on/off
 * t : top 출력 상단의 프로세스와 cpu 항목 on/off
 * m : top 출력 상단의 메모리 항목 on/off
 * O : 화면 정렬(sort) 기준 지정
 * r : nice 조정 (-20 ~ 20. 우선순위 높음 ~ 낮음)
 * q : top 종료

그럼 이제 CPU과점유 현상을 재현해보고, 분석해보도록 하겠습니다. 


1.Thread Dump 생성

리눅스환경에서는 일반적으로 아래와 같이 thread dump수집을 할 수 있습니다. 


kill -3 JAVA_PID

jstack -l JAVA_PID > jstack.out (Open JDK, Sun JDK)


PID를 확인하겠습니다. 

java process를 확인합니다. 4442로 확인되네요.


[wildfly@kmkang~/PocApp/JBTEST$]ps -ef | grep java

wildfly   4442  4322 92 16:40 pts/1    00:02:16 /usr/local/jdk1.8.0_152/bin/java -D[Standalone] -server -XX:+UseCompressedOops -verbose:gc -Xloggc:/home/wildfly/jboss64/standalone/log/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=3M -XX:-TraceClassUnloading -Xms1303m -Xmx1303m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true -Djboss.modules.policy-permissions=true -Dorg.jboss.boot.log.file=/home/wildfly/jboss64/standalone/log/server.log -Dlogging.configuration=file:/home/wildfly/jboss64/standalone/configuration/logging.properties -jar /home/wildfly/jboss64/jboss-modules.jar -mp /home/wildfly/jboss64/modules -jaxpmodule javax.xml.jaxp-provider org.jboss.as.standalone -Djboss.home.dir=/home/wildfly/jboss64 -Djboss.server.base.dir=/home/wildfly/jboss64/standalone -Djboss.server.base.dir=/home/wildfly/jboss64/standalone -Djboss.node.name=standalone -c standalone.xml -b 0.0.0.0 -bmanagement=IP -Djboss.socket.binding.port-offset=50

wildfly   4650  4262  0 16:43 pts/1    00:00:00 grep --color=auto java 



[wildfly@kmkang~/jboss64/$]jstack 4442 > dump.txt


2.top 결과에서의 PID를 HEX 값으로 변환합니다. 아래와 같이 프로그래머 계산기를 사용하시면 됩니다. 


  PID   USER    PR  NI    VIRT      RES     SHR   S   %CPU   %MEM    TIME+ COMMAND

 4560 wildfly   20   0   7155556 587304  21260 R    99.9       7.4      26:49.26     java





3.Thread dump 내에서 HEX값인 11d0을 찾아보겠습니다. 



자세히 확인해보면, sleep1.jsp파일이 stack trace중 하나로 확인되네요.


 "http-/0.0.0.0:8130-1" #112 daemon prio=5 os_prio=0 tid=0x00007fad5410c800 nid=0x11d0 runnable [0x00007fadae695000]

   java.lang.Thread.State: RUNNABLE

at org.apache.jsp.sleep1_jsp._jspService(sleep1_jsp.java:58)

at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:69)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)

at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:365)

at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:309)

at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:242)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:295)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:231)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:149)

at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:150)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97)

at org.jboss.web.rewrite.RewriteValve.invoke(RewriteValve.java:466)

at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:559)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)

at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:854)

at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653)

at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:926)

at java.lang.Thread.run(Thread.java:748)



실제로 sleep1.jsp 내에는 아래와 같은 소스가 존재합니다. 


 <%@ page contentType="text/html; charset=euc-kr" %>

<%

        int i=0;

        int sum=0;

        while (i<=0) {

                        sum=sum+i;

                        i=i++;

        }

%>


또한 명시적으로 stack trace에서 확인가능한 sleep1_jsp.java 의 58라인에 어떤 소스가 있는지 확인해보겠습니다. 

     42     try {

     43       response.setContentType("text/html; charset=euc-kr");

     44       response.addHeader("X-Powered-By", "JSP/2.2");

     45       pageContext = _jspxFactory.getPageContext(this, request, response,

     46                         null, true, 8192, true);

     47       _jspx_page_context = pageContext;

     48       application = pageContext.getServletContext();

     49       config = pageContext.getServletConfig();

     50       session = pageContext.getSession();

     51       out = pageContext.getOut();

     52       _jspx_out = out;

     53

     54       out.write('\n');

     55

     56         int i=0;

     57         int sum=0;

     58         while (i<=0) {

     59                         sum=sum+i;

     60                         i=i++;

     61         } 


개발자는 CPU과점유를 일으키는 해당 소스코드에 대한 검토를 해야합니다. 


이상으로 리눅스상의 CPU과점유 현상 분석에 대해 알아보았습니다. 다음 포스팅에서는 다른 OS상에서의 CPU과점유 현상을 분석해 보겠습니다. 

고맙습니다.






728x90
반응형