서버 프로세스가 죽었어요 (OOM, Swap)

elive7·2025년 8월 5일

개발노트

목록 보기
2/11
post-thumbnail

물론 이렇게 죽지는 않았습니다 🥲

배경

열심히 db를 이사하고 yml 파일을 수정하여 배포를 시도했으나, 헬스체크가 되지 않아 github workflow가 실패하는 일이 발생했다.
docker ps를 해보니 green 컨테이너가 죽어있는 모습을 확인할 수 있었다.

찾아보니 OOM 관련 에러가 발생했을 가능성이 있다고 해서, dmesg | grep -i oom 명령어로 확인해보니... 실제로 관련 문제를 찾아볼 수 있었다.

[ 5480.701265] boot invoked oom-killer: gfpmask=0x140dca(GFP_HIGHUSER_MOVABLE| _GFP_COMP|GFP_ZERO), order=0, oom_score_adj=0
[ 5480.701332] oom_kill_process+0x118/0x280
[ 5480.701335] ? oom_evaluate_task+0x143/0x1e0
[ 5480.701341]
alloc_pages_may_oom+0x10c/0x1d0
[ 5480.701524][ pid ] uid tgid total_vm rss rss_anon rss_file rss_shm em pgtables_bytes swapents oom_score_adj name
[ 5480.701666] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=user.s lice,mems_allowed=0,global_oom,task_memcg=/system.slice/docker-bdcb2ffda1e432a26 911cdfa717ced706dedf5db6897858607889c23f4aada53.scope,task=java,pid=2719,uid=0
[ 5480.701733] Out of memory: Killed process 2719 (java) total-vm:2474564kB, ano n-rss:342684kB, file-rss:72kB, shmem-rss:0kB, UID:0 pgtables:1108kB oom_score_ad j:0

OOM

OOM(Out Of Memory)컴퓨터 시스템에서 사용 가능한 주 메모리(RAM)가 모두 소진됐을 때 발생하는 상황을 말한다.
리눅스와 같은 운영체제에서는 시스템, 애플리케이션, 프로세스들이 메모리를 일정량 할당받아 사용하게 된다. 이때 만약 전체 메모리(그리고 활성화된 swap 메모리 포함)가 부족해지면, 운영체제의 OOM Killer가 개입해 메모리를 가장 많이 사용하는 프로그램(종종 Java 등)을 강제로 종료시켜 시스템 전체의 다운을 막는다.

SWAP

스왑(swap)은 운영체제에서 물리 메모리(RAM)가 부족할 때 디스크 일부를 임시 가상 메모리로 사용하는 공간으로, 시스템이 원활히 동작하도록 도와준다.

스왑이 하는 역할

1) 메모리 부족 보완
시스템의 실제 RAM이 가득 찼을 때, 자주 사용하지 않는 데이터나 프로그램 메모리 일부를 디스크의 스왑 공간으로 옮겨서 RAM 공간을 확보한다. 이렇게 하면 더 많은 프로그램이 실행 가능해지게 된다.

2) 시스템 안정성 유지
RAM만으로 메모리를 감당하지 못할 때, 스왑이 없으면 프로그램이나 시스템 자체가 강제 종료되거나 다운될 수 있는데, 스왑 공간이 있으면 이런 갑작스러운 충돌을 피할 수 있다.

3) 효율적인 메모리 운영
시스템은 자주 쓰지 않는 데이터를 스왑으로 옮기고, 빈번히 쓰는 데이터에 RAM을 집중시켜 전체적인 성능 효율을 향상시킵니다.

현상태 진단

현재 내 서버 상태였다. RAM도 대부분 사용 중인데다가 swap도 아예 없어 OOM이 발생하기 딱 좋은 상태이다.

항목의미현재 상태
total전체 메모리 (961MB ≈ 1GB)작음
used현재 사용 중인 메모리723MB
free즉시 사용 가능한 메모리68MB
shared여러 프로세스가 같이 쓰는 공유 메모리 공간1MB
buff/cache캐시나 버퍼로 잡힌 메모리313MB
available전체 중 앱이 쓸 수 있는 여유238MB
Swap디스크에 마련된 가상 메모리0
  • free가 현재 완전히 사용하지 않고 텅 빈, 즉 진짜 놀고 있는 메모리 양을 의미한다면, availble은 현재 사용 중일 수도 있지만, 필요하면 즉시 해제헤사 사용할 수 있는 메모리 양의 추정치이다.

해결

Swap 활성화

sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

일단 긴급 처방용으로 Swap 공간을 만들었다.

명령어설명
sudo fallocate -l 1G /swapfile용량이 1GB인 빈 파일 /swapfile을 생성한다. 이 파일이 앞으로 스왑 공간으로 사용될 공간이다.
sudo chmod 600 /swapfile/swapfile의 권한을 소유자만 읽고 쓸 수 있도록 제한한다. (보안상)
sudo mkswap /swapfile/swapfile을 실제로 리눅스가 인식하는 "스왑 영역"으로 초기화한다.
sudo swapon /swapfile방금 만든 /swapfile을 실제로 스왑 공간으로 활성화하여 메모리 부족 시 사용할 수 있게 한다.
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

재부팅 후에도 swap 설정이 유지되도록 하기 위해, 아래 명령어를 사용해 /etc/fstab 파일에 swap 항목을 추가했다.

JVM 메모리 제한 걸기

현재 시스템에서 JVM 힙에 대해서도 제한을 두는 것이 좋겠다는 생각이 들었다.

옵션의미
-Xmx힙 메모리 최대 크기 (JVM이 절대 넘지 않음)
-Xms힙 메모리 초기 크기 (시작할 때 확보)

제한을 얼마로 두어야 할지에 대해 고민이 있었다. 현재 서버 총 메모리 약 1GB + swap 1GB인 상태에서 컨테이너 2개 (blue, green) + redis + (호스트에서 돌아가는) mysql를 운영하는 상황이었다. 찾아보니, Redis는 가벼워서 메모리 제한을 크기 안 주어도 되기에 blue, green 컨테이너에 각각 약 300MB 메모리 제한을 두었다. (총 700MB + OS 200~300MB + swap 활용)

나의 경우 docker를 활용하여 배포하고 있었기에 dockerfile은 다음과 같이 수정했다.

CMD ["java", "-Duser.timezone=Asia/Seoul", "-Dspring.profiles.active=dev", "-Xmx250m", "-Xms250m", "-jar", "server.jar"]

이렇게 하려고 했으나... 알고보니 스프링 부트(Spring Boot) 같은 프레임워크 기반 애플리케이션이라면 350MB는 꽤 타이트한 편이라고 한다. 따라서 일단 JVM 메모리 제한은 두지 않고, swap 파일만 설정해서 구동시켜보았다. 다행히 swap 설정만으로도 제대로 컨테이너가 구동되는 모습을 확인할 수 있었다. 메모리가 충분한 상태라면 JVM 제한까지 두어도 괜찮겠지만, 상황이 여의치 않다면 swap만 설정한 후 경과를 보아도 괜찮을 것 같다.

또한 mysql도 메모리를 많이 잡아먹는 프로세스라서 이를 고려해야 했다.

ps -o pid,user,%mem,command ax | grep mysqld

위 명령어로 mysql의 시스템에서 실행 중인 모든 프로세스 중 MySQL 서버(mysqld)의 PID, 사용자, 메모리 사용률, 실행 명령어를 한눈에 확인할 수 있다.

전체 메모리(RAM)의 7.4%를 mysqld가 사용 중이라는 것을 알 수 있다. 아직까지는 가볍게 잘 돌아가는 모습을 확인해 볼 수 있다.

mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"

또한 위 명령어로 InnoDB 스토리지 엔진이 사용하는 버퍼 풀 크기(innodb_buffer_pool_size) 설정 값을 조회해보았다.

약 128MB 였는데 아직까지는 괜찮은 것 같아 계속 모니터링을 해보고 조절하기로 했다. 만약 이를 변경하고 싶다면 참고란에 있는 블로그를 참고해보면 좋을 것 같다.

참고

profile
펠리컨적 사고 "일단 시도함"

0개의 댓글