Spring🌱/트러블슈팅

[spring boot] 아마존 aws micro.t2 CPU 사용량 100% 문제 해결

전감자(◔◡◔) 2024. 10. 18. 17:56

 



서버가 계속 다운되는 문제상황 발생 

 

 

 


최근
EC2를 통해 Spring boot 프로젝트 서비스 배포를 하는 과정에서 CPU 사용률 100% 에러를 겪었다.

분명 배포가 제대로 잘 된것을 확인했는데 !!! 다음 날 PM님께서 관리자 페이지 링크에 접속이 되지않는다고 하셨다...!!

 

코드 문제는 아닌 것 같아 ubuntu 서버에 접속하려하니 ssh 연결이 되지 않았다... AWS 콘솔을 내가 곧바로 볼 수 있었으면 좋겠지만  계정을 PM 님이 관리 해주고 계셨기에 상황을 공유드리니 우선 PM 님께서 인스턴스를 재가동해주셨다.

(재가동 하니까 또 다시 접속이 잘되었음)

 

처음엔 일시적인 문제인 줄 알고 다시 개발 작업을 진행했는데, 몇 시간 뒤에 또 다시 같은 문제 상황이 반복됐다...

ssh 접속이 안되니 로그를 확인할 수도 없어서 인스턴스 재가동만 3~4번을 반복해야했는데 너무 답답했다.

 
이쯤 되니 이건 그냥 넘어갈 문제가 아니라 뭔가 근본적인 원인이 있다는 확신이 듦
개인 프로젝트도 아니고, 클라이언트의 비용과 신뢰가 걸린 외주 프로젝트였기에 이 문제를 반드시 해결하기로 마음 먹었다.

 

 

 

 

 

 

[해결 과정]

 

 

 

 

 

원인을 찾기위해 인스턴스가 갑자기 정지되는 현상에 대해 조사하기 위해서 Stack overflow 를 뒤지던 중 ... 이런 글을 발견했다.

 

 

t2.micro 프리티어를 사용할 시

cpu 사용량이 100% 에 이르게 되면 메모리가 부족해져 갑자기 서버가 다운되버리는 현상이 흔하게 발생한다는 것이다!

 

 

AWS에 들어가서 확인해보니 omg t2.micro 의 램 공간이 2GiB 이였다. (정말 정말 작고 소중한....) 

 

top

 

 

top 명령어를 통해 어떤 프로그램이 얼마나 메모리를 차지하고 있는지 볼 수 있는데 내 경우에는 my sql 서버를 따로두지 않고

직접 인스턴스 내에 설치해서 그런가 엄청나게 메모리를 많이 잡아먹고 있었다...

Spring boot 서버랑 mysql 을 둘다 동시에 돌리니 커널이 메모리 확보를 위해 프로세스를 임의로 죽여버리는 OOM Killer 현상이 발생했고, 멀쩡하던 서버가 다음 날이면 죽어버리는 것이었다...

 

 

 

 

그럼 이런 문제를 해결할 방법은 없는가?

문제를 해결하기 위해서 여러 방법을 고민해 봤다.

 

 MySQL 을 인스턴스에서 분리하고 RDS를 도입 해볼까 생각도 했지만 이 부분은 비용 관련된 부분이라,,,

클라이언트에게 부탁할 순 없을 것 같았고  SQLite 로 바꿔보려고도 했지만 마찬가지로 갑자기 스택이 바뀌게 될 때도 클라이언트의 동의가 필요했기에 최대한 비용을 들이지 않고 기존 인프라를 유지한채로 해결하고 싶었다.

 

redis 캐싱을 이용하여 DB 조회 횟수 줄여서 메모리를 줄여볼까도 했지만 redis 까지 올리면 더 서버가 무거워질 수도 있을 것 같았다.

 

 

 

 

 

 

 

다행히도 스택오버 플로우 댓글이 하나 달려있었는데 SWAP 공간을 만들어서 문제를 해결하라는 것이었다

 

SWAP 메모리가 무엇인지 알아보니, RAM이 부족할 경우에 리눅스에서 하드디스크의 일정공간을 마치 RAM처럼 사용해서 마치  RAM 공간이 늘어난 것과 같은 효과를 만들수있다는 것이다!! (가상 메모리 개념)

 

물리 RAM 크기의 2배 정도를 SWAP 공간으로 잡는 게 좋다고 해서 2GB 정도를 할당해주려한다. 

 

 


 

 

 

SWAP 메모리 할당 방법

 

  • 일단 dd 명령어를 통해 swap 메모리를 할당한다.
sudo dd if=/dev/zero of=/swapfile bs=128M count=16

128씩 16개의 공간을 만드는 것이여서 우리의 경우 count를 16으로 할당하는 것이 좋다. 즉, 2GB정도 차지하는 것이다.

  • 스왑 파일에 대한 읽기 및 쓰기 권한을 업데이트합니다.
$ sudo chmod 600 /swapfile

 

  • Linux 스왑 영역을 설정합니다.
$ sudo mkswap /swapfile



  • 스왑 공간에 스왑 파일을 추가하여 스왑 파일을 즉시 사용할 수 있도록 만듭니다.
$ sudo swapon /swapfile

 

  • 절차가 성공했는지 확인합니다.
$ sudo swapon -s

 

  • /etc/fstab 파일을 편집하여 부팅 시 스왑 파일을 활성화합니다.

편집기에서 파일을 엽니다.

$ sudo vi /etc/fstab

파일 끝에 다음 줄을 새로 추가하고 파일을 저장한 다음 종료합니다.

/swapfile swap swap defaults 0 0

 

 

 

 

 

트러블 슈팅 후 회고  

다행히 SWAP 공간을 할당해주고 나니 Spring boot 서버가 다운되는 일은 없었다. 

 

그렇지만 이 방법은 여전히 임시방편에 불가하다 왜냐면 하드디스크나 SSD는 RAM 보다 속도가 안그래도 훨씬 느린데

데이터가 빈번하게 SWAP 공간을 왔다갔다하면 페이징 교체하는데 시간이 많이 걸려서 시스템 속도가 엄청나게 느려져서 

운영체제 시간에 배운 Thrashing 현상이 일어날 수 있다고 한다. 

 

외주 데드라인이 좀 더 길고 비용이 충분했다면 위에서 언급한 다음의 방법들을 더 시도해보았을 것 같다.

 

1. spring boot 프로파일링 도입 -> 불필요한 메모리 사용 코드 최적화 

2. redis 캐싱을 이용하여 DB 조회 횟수 줄이기 

3. MySQL 을 인스턴스에서 분리하고 RDS 도입 

4, MySQL 대신 SQLite 도입