티스토리 뷰
[TroubleShooting] 다양한 장애유형 대처방안 (CPU, Resource, Boot)
GodNR 2018. 6. 25. 10:40본 포스팅은 다양한 Exception Case를 살펴보고 1차 선 대응 방법에 대해 알아 보겠습니다.
본 포스팅은 모든 Exception Case를 살펴보는것에 의의가 있지는 않습니다. Exception은 워낙 많은 Case가 존재하고 이를 모두 살펴 보려면 100년이 걸려도 다 살펴보지는 못할 것이기 때문입니다. 그렇기 때문에 많은 분야의 전문가가 존재할 것입니다. 이번 시간에는 이런 문제가 발생했을 경우 어떻게 대응하고 해결해 나갈 것인지에 대한 개론적인 내용을 다루고자 합니다. 특히 그중 Hand Up에 의한 장애 처리에 대해 좀 더 중점적으로 확인 할 예정입니다. 이미 많은 사람에 의해 해결된 이슈들이므로 훓어보기 식으로 쭉 내려 보기를 추천합니다.
먼저 CPU 과부하를 유발하는 현상에 대해 알아보겠습니다.
다음으로 과도한 RMI Call을 사용하였을 경우입니다. RMI 호출은 Java Object를 직렬화 하고 역 직렬화하는 과정을 수반하는데, 이는 CPU를 많이 사용하는 직업이기 때문에 항시 주의가 필요합니다. 특별히 RMI Call을 하지 않더라도 EJB를 call하는 것이 Remote일 때는 RMI호출을 사용하게 되고 부하량이 많을 때는 이 부분이 주로 병목의 요인이 되곤 합니다. JEUS에선 single-vm-only 및 invocation optimize 기능을 적절히 잘 사용하여야 합니다.
세번째로 JNDI lookup을 과도한 사용입니다. JNDI lookup은 Server의 JNDI에 Binding된 Object를 읽어오는 과정입니다. 이 과정도 위에서 설명한 RMI call이 수행되는데, 특히 EJB를 호출하기 위해서 Home과 Remote Interface를 lookup 하는 과정에서 종종 CPU를 과점유 하기도 합니다. 그러므로 JSP나 Sevelet 에서 caching해서 사용하는 것을 권장합니다.
네번째로 임시 객체 생성을 빈번히 할 경우입니다. 너무 빈번하게 임시객체를 생성하면 성능은 이상 없어 보이지만 CPU 점유율은 높아집니다. Application 특성을 잘 파악하여 Singleton으로 구성 가능한지 체크해야 합니다.
마지막으로 성능이 느린 Query를 사용하는 경우입니다. Database query 로직이 매우 느려도 CPU에 영향을 줄 수가 있습니다.
두번째로 CPU에 영향을 주는 Full GC가 발생하는 경우입니다.
먼저 JVM Debug Option을 운영중에 사용할 경우입니다. WAS 실행 시 해당 옵션을 적용하고 운영하면 CPU overhead 및 기타 Performance에 영향을 주므로 실제 운영 시 삭제하도록 해야 합니다.
두번째로 JEUS에 불필요한 옵션이 들어가 있지는 않은지 확인해야 합니다.
Check-include-JSP 설정은 JSP 안에 include file에 대한 jsp를 강제적으로 compile 시키는 옵션인데 파일이 많으면 과부하를 일으킬 수 있습니다.
또한 Auto reload 설정을 운영중에 반영할 경우에는 호출 시점마다 Class reloading을 자동적으로 수행하여 CPU에 과부하를 줄 수 있습니다.
그럼 실제 CPU 과점유 현상이 발생하였을 경우 어떻게 분석해 나가야 할지 알아보겠습니다.
GC Log를 설정하고 하루에 Full GC가 일어나는 횟수와 Pause Time이 어느정도 발생하는지를 모니터링 합니다.
GC Log를 눈으로 보기보다는 무료 오픈소스가 많기때문에 IBM GC Analyzer 또는 APM tool등을 사용합니다.
다음으로 Thread dump를 분석합니다.
Thread dump를 통해 현재 해당 AP가 어떤 logic을 수행 중인지 확인합니다.
세번째로 OS command 및 tool을 이용한 분석을 수행합니다.
ps 명령을 이용하여, JEUS Process의 각 시스템 thread의 사용률을 구하는 것이 그 출발이 될 것입니다.
여기서 CPU가 가장 높은 부분을 찾아 Thread Dump의 TID간 비교를 통해 어떠한 업무가 대량의 CPU를 사용하고 있는지 확인 할 수 있습니다.
다음으로 Connection Resource 장애 발생 시 조치방법에 대해 알아보겠습니다.
Connection Resource에 대해 먼저 알아보겠습니다. Web Server, DB 및 기타 공통 시스템의 접속을 위한 객체 (Connection, Statement, Resultset 등)을 의미하여 잘못된 Connection Resource의 잘못된 Handling 에 의해 다음과 같은 문제가 발생할 수 있습니다.
Database가 굉장히 busy한 상황의 IO wating 조건에서 Connection pool이 MAX size 까지 증가형 응답을 받기 위해 대기하는 경우가 있습니다. 대용량 Query를 보냈거나 DB lock에 의해 발생하는 경우, 해당 DB서버의 높은 시스템 Resouce 사용률에 인한 경우, 트래픽으로 인해 네트워크가 느려지거나 단절되는 경우에 발생할 수 있습니다.
두번째로 Application 동기화 문제입니다.
Connection을 얻는 과정에서 synchronized block을 사용할 경우 thread safe하게 동작은 하지만 안에 synchronized block안의 Connection을 얻는 로직이 빠른 수행능력을 보여주지 못한다면 문제의 소지가 있습니다.
다음으로 Connection leak 현상입니다.
Connection의 비정상 문제로 인해 Pool로 반환이 안되고 계속 쌓이는 경우입니다.
마지막으로 heap leak 현상입니다.
Connection Resource중의 하나인 Statement 객체가 close가 안되어서 OS에서 native heap이 계속 증가하는 현상입니다.
그럼 실제 Connection Resource 장애가 발생하였을 경우 어떻게 분석해 나가야 할지 알아보겠습니다.
hread dump에서 데이터를 read 하기 위해 대기하는 경우 발생할 수 있습니다. 이런 현상이 발생하는 경우는 다음과 같습니다.
대용량 Query를 보냈거나 DB lock에 의해 발생하는 경우, 해당 DB서버의 높은 시스템 Resoure 사용률에 인한 경우, 트래픽으로 인해 네트워크가 느려지거나 단절되는 경우에 발생 가능합니다. 위 경우 일정시간 지나면 풀리는 경우가 있지만 DB lock의 경우 DBA를 통해 해당 connection을 kill해야만 하는 경우도 있습니다.
두번째로 Application 동기화 문제입니다.
application 동기화 블록에 의해서 사용자 User 수가 급격히 늘어 났을 때 발생이 가능합니다. 전부 DBConnectionPool의 getConnection 시도시 wating이 걸려 있는 상황에 발생이 가능하며, 이런 경우가 자주 발생시 application 의 수정이 불가피합니다.
세번째로 Connection leak 문제입니다.
개발자의 실수로 인해 connection close가 제대로 되지 않아서 Connection이 계속 누적되는 경우와 물리적인 connection은 끊겼으나 Connection referense는 가지고 있는 상황이 해당됩니다. 누적된 Connection이 max 수치까지 늘어나면 나머지 request는 connection을 얻기 위해 대기상태에 빠져 서비스 장애까지 다다를 수 있으며 pool을 사용하지 않는다면 Back단 DB의 물리적 Connection을 증가시켜 심각한 장애를 초래 할 수 있습니다.
보통 아래와 같이 Datasource pool을 모니터링 하여 idle 값이 connection pool 연결된 수치에서 시간이 지나도 떨어지지 않는다면 leak을 의심해 볼 수 있습니다.
네번째로 heap leak 문제에 대한 해결 방안입니다.
Statement가 close가 안되서 누적되는 사항은 JEUS 및 log thread dump 등 일반적인 방법으로는 찾기가 어렵습니다. APM을 이용하는 방법이 최선이나 OS에서 native heap이 증가 되는지 관찰하는 것도 일단 의미는 있습니다. 모니터링 후 native heap이 증가 한다면 JEUS와 같은 경우는 max-use-count와 같은 옵션을 사용하여 물리적인 Connection을 버리는 것도 한 방법이 될 수 있습니다.
PreparedStatement 역시 사용 후에는 반드시 close()를 해 주어야 합니다. 그렇지 않을 경우, 데이터베이스의 오픈된 CURSOR가 증가함과 동시에 JVM의 힙 메모리 증가를 야기하게 됩니다. ResultSet 역시 마찬가지입니다. 이처럼 누수된 Statement 미반환 건수는 각 데이터베이스의 특성에 따라 때론 Open Cursor Exceed와 같은 SQL 예외사항을 발생시킵니다.
여러 개의 Container를 운영하거나 JEUS 및 타 WAS가 한 시스템에 여러 개 설치되어 있는 경우 발생할 수 있습니다.
또한 알려진 Port(Web Port 같은)는 다른 Port로 변경해서 사용해야 하는데 미처 확인하지 못했을 때, Process를 내리는 도중 Port Clear가 깨끗하게 안 되는 경우, JEUS에서 쓰는 기타 Port 등이 Security(바이러스, 백신) Tool에 의해서 holding 되어 있는 경우등을 들 수 있습니다.
이런 경우 현재 JEUS Port를 수정하거나 다른 application의 Port가 수정되어져야 한다.
다음으로 Security Exception 현상입니다.
JEUS 설치 시 설정하였던 UserID와 password가 일치하지 않을 경우 또는 기억하지 못할 경우 발생할 수 있습니다.
또한 Server의 DNS 설정으로 인해 NodeName을 제대로 가져 오지 못했을 경우에도 발생 가능합니다.
마지막으로 Host Resolution으로 인한 기동 실패 현상입니다.
JEUS가 설치 된 서버의 DNS 설정으로 인해 설정된 local ip가 아닌 이상한 IP로 mapping 되는 경우 기동이 실패할 수 있습니다.
그럼 실제 기동 실패 장애가 발생하였을 경우 어떻게 분석해 나가야 할지 알아보겠습니다.
기본적이지만 JEUS Log를 먼저 확인합니다.
Port confict 일 경우 "소켓 이름이 이미 사용 중입니다."와 같은 로그가 발생할 수 있습니다.
os command 및 tool을 이용하여 사용중인 포트를 확인해야 합니다.
lsof나 netstat 명령어를 통해 현재 사용중인 Process가 누구인지 확인 후 해당 Process를 중지하거나, 기동 Port를 변경하도록 합니다.
정확히 분석해 나가기 위해서는 위에서 정리한 내용들은 전체의 일부에 불가하다는 것을 말씀드립니다. 경험을 바탕으로 새로운 장애에 유연하게 대응할 수 있도록 항상 고민과 학습을 병행해야 할 것입니다.
이 밖에 다양한 파트의 장애 유형에 대해서는 앞으로도 지속적으로 포스팅할 예정이니 많은 관심 부탁합니다.
고맙습니다.
'② 성능 최적화, 트러블 슈팅 > ⓣ TroubleShooting' 카테고리의 다른 글
[404] Not Found에 대한 고찰 (2) | 2018.08.18 |
---|---|
[TroubleShooting] WAS 장애복구 기능 (0) | 2018.06.27 |
[TroubleShooting] OutOfMem 발생 시 자동 복구 방법 (0) | 2018.06.17 |
[TroubleShooting] ThreadDump 분석 가이드 (0) | 2018.06.15 |
vmstat을 활용한 시스템 리소스 모니터링 (2) | 2018.06.13 |
- Total
- Today
- Yesterday
- apache
- Da
- nodejs
- Docker
- jeus
- node.js
- git
- 마이크로서비스
- API Gateway
- SWA
- JEUS7
- JEUS6
- JBoss
- kubernetes
- MSA
- aws
- webtob
- wildfly
- 오픈스택
- openstack token issue
- TA
- 쿠버네티스
- 마이크로서비스 아키텍처
- Architecture
- SA
- openstack tenant
- OpenStack
- aa
- k8s
- 아키텍처
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |