Linux 자바 cpu 과점유 트러블 슈팅

Ada·2022년 12월 14일
0

항해TOL

목록 보기
55/63

문제 해결 방법 없어요ㅠㅠ 단순 기록용 글입니다!

제이미터로 성능 테스트를 하던 중 이상하게 평소보다 훨씬 TPS가 낮은 것을 발견했다.

index 유무 차이 테스트이고, 테스트 부분인 mainPage의 코드는 바뀐게 없는데 이상하게 너무 느려서

gitbash 창에서 리눅스 상태 확인 명령어인 top 을 사용해서 cpu와 메모리 상태를 확인해봤다.

세상에.....

평소보다 적은 Thread 로 테스트 했는데도 cpu가 죽어있었다.

계속 죽어있는 상태가 아니고 테스트 시에만 일시적으로 cpu 점유율이 엄청나게 치솟았는데

이건 정상적인 상태가 아니라고 확신하고 해결 방법을 찾아보기 시작했다.

sudo jmap -dump:format=b,file=[파일명]_dump.hprof [PID]

우선 heap dump 를 생성하여 프로세스를 살펴보기로 했다.

  • Heap : 인스턴스가 저장되는 메모리 영역

  • Dump : 정보를 다른 곳으로 복사해 가서 저장하는 것

=> heap dump는 특정 시점에서의 heap 메모리 사용을 파일로 저장한 것이다.



vi 등의 툴을 이용해서 Heap Dump 파일을 열면

여는 순간 파일의 힙 메모리 사이즈만큼 서버의 메모리를 사용하게 된다.

그러므로 로컬 컴퓨터로 복사한 후 파일을 열어야 한다.

로컬 컴퓨터로 옮긴 파일을 Heap Dump 파일 생성 및 분석 툴인 이클립스 MAT을 통해 열어준다.

MAT 다운로드 링크

위의 링크를 통해 MAT 을 다운받으면 된다.

나는 윈도우 환경이라 ZIP 파일을 다운 받았다.

사용 방법은 아래의 사이트에서 참고하였다.

Eclipse Memory Analyzer 소개
https://spoqa.github.io/2012/02/06/eclipse-mat.html


Leak suspect 를 살펴보니 apache.tomcat 의 NioEndpoint 인스턴스가 문제라고 하는 것 같다.

Dominator tree 로 자세히 살펴보니 socket 이란 단어가 반복해서 보인다.


!! 여기부터는 다 소용 없는 행위였기 때문에 굳이 안보셔도 됩니다...




이를 통해 밸런스 게임을 웹소켓으로 리팩토링 하기 위해 설치했었던 socket 의존성이 문제인 것 같다고 판단하였다. (-> 웹소켓 문제 아님...)

일단 외부 라이브러리에 웹소켓이 존재하는 것을 확인하였다.

웹소켓을 사용하지 않을 것이기 때문에 쓸데없이 메모리만 잡아먹는 의존성을 제거하기로 했다.

나는 이미 웹소켓의 의존성들을 모두 지워둬서 오른쪽의 창에 아무것도 안 보이는데,
원래는 목록 2개가 뜬다.

그 목록들을 선택하고 - 버튼을 눌러준 뒤 마지막에 Apply 랑 ok 버튼을 누르고 나와줬다.

그럼 이제 외부 라이브러리 창에서 웹소켓이 안 보인다.

사실 이게 근본적인 문제 해결 방법인지 아닌지는 모르겠다.

그래서 다시 한 번 jar 파일을 만들어 배포한 뒤 cpu 상태를 확인해보았다.

ㅠㅠ.... cpu가 그대로 90% 이상을 유지하고 있다.

심지어 외부 라이브러리 창에 웹소켓이 다시 생성되어있다.

다시 덤프 파일을 만들어 리포트를 확인해봤다.


ㅎㅎ 그대로였다....


Project Structure 에 다시 들어가서 웹소켓을 찾아서 선택하고 좌측 상단의 - 버튼을 눌러서 지워주었다.

그리고 다시 자동으로 생성 되는 폴더들인 out, build, .idea 를 삭제해주었다.

(out - 인텔리제이 빌드시 컴파일 한 class 폴더
build - gradle 빌드시 컴파일 한 class 폴더)

이 상태로 인텔리제이를 종료하고 다시 실행시켰다.

그러면 오른쪽 아랫 부분에 Load Gradle Project 버튼이 활성화 되는데

아까 지운 폴더들을 다시 생성하기 위해 이걸 눌러줬다.

ㅎㅎ.. Heap Memory 상태는 여전히 그대로....

그래서 이번엔 visualVM 이라는 프로그램으로 인텔리제이를 연결해서 확인해보니

서버에 jar 파일을 띄우고 부하를 다시 줄 때 used heap 그래프가 요동치는 것을 확인할 수 있었다.

심지어 부하를 줄 때만 사용되는 힙 메모리가 증가하는 것이 아니고

부하 신호가 끝난 뒤에 뚝 떨어졌던 힙 메모리가 다시 증가하는 것을 확인할 수 있었다.

휴.... 그래서

결론은....

메모리 부족 -> CPU 사용 -> 서버 과부하 =>> 메모리 추가 할당 필요

SWAP 필요하다!!!

이다....


그래서 이제 aws ec2 로 만든 서버에 메모리를 할당하는 swap 을 시도하는 과정을 기록해보려고 한다.

일단 기존의 jvm 의 메모리 점유율(jmap -histo)와 메모리 상태를 확인하였다.

그리고 150개의 쓰레드를 5초 간격으로 10번 발생시킨 뒤 메모리 상태를 다시 확인하였다.

기본 자바 프로그램이 잡아먹는 메모리가 엄청 많았다.

사실... 생각보다 드라마틱한 변화는 없었지만....그래도 일단 swap을 시도해보기로 했다.

# swapfile 메모리를 할당
sudo dd if=/dev/zero of=/swapfile bs=128M count=16

dd 명령어는 파일 복사 및 변환 관련 유닉스 명령 유틸리티이고

/dev/zero는 데이터 스토리지 초기화 관련 파일이다.

bs=128M * count=16 으로 총 2GB로 swapfile 크기를 설정해주었다.

# swapfile 권한 세팅 (READ, WRITE)
sudo chmod 600 /swapfile

읽기, 쓰기가 가능하도록 chmod 600으로 설정해준다.

# swap 공간 생성 (Make swap)
sudo mkswap /swapfile

mkswap 명령어로 swapfile을 추가할 swap 공간을 생성한다.

# swap 공간에 swapfile 추가하여 즉시 사용할 수 있도록
sudo swapon /swapfile

swapon 명령어를 통해 swapfile을 swap memory에 추가한다.

# /etc/fstab vi 에디터 열기
sudo vi /etc/fstab

# 파일의 맨 끝 다음줄에 아래 명령어 작성
/swapfile swap swap defaults 0 0

etc/fstab는 파일시스템 정보를 저장하는 곳이다. 파티션 변경 및 디스크 추가 시에는 이 파일에 등록해야 자동으로 마운트가 가능하다.

따라서 /etc/fstab 파일에 swapfile을 세팅해주었다.

스왑 직후에는 무슨 이유인지 모르겠지만 가만히 있어도 CPU 사용률이 혼자 99퍼센트를 넘기면서 서버가 죽을락 말락 했다....

그런데 좀 기다렸다가 아까와 마찬가지로 스레드 150을 여러번 주면서 테스트 해보니 CPU 점유율이 스왑 할당 전보다 훨씬 낮아졌다.

그런데.... 내가 최종적으로 CPU 점유율을 확인하게 된 계기인 TPS 성능 저하는 해결이 안됐다....

다른 방법을 찾아봐야겠다.

참고 : https://kth990303.tistory.com/361

profile
백엔드 프로그래머

0개의 댓글