[Linux] OOM(Out of Memory)란?
[Linux] OOM(Out of Memory)란?
l Linux
몇일전부터 개발 환경에서 겪던 문제로 멀쩡하던 MySQL 서비스가 갑자기 연결이 되지 않는다. 처음엔 단순히 행 현상인줄 알고, MySQL 서비스를 재시작 하였다. 그런데 동일한 상황이 하루에도 여러 번 발생하고 있어서 원인을 살펴보기로 했다. 원인을 살펴보니, 아래와 같은 로그가 있었다.
Aug 30 01:35:08 xxxxx kernel: [7189052.423131] [18540] 111 18540 1930392 1535479 12935168 0 0 mysqld Aug 30 01:35:08 xxxxx kernel: [7189052.423132] Out of memory: Kill process 18540 (mysqld) score 512 or sacrifice child Aug 30 01:35:08 xxxxx kernel: [7189052.424065] Killed process 18540 (mysqld) total-vm:7721568kB, anon-rss:6141916kB, file-rss:0kB, shmem-rss:0kB Aug 30 01:35:08 xxxxx kernel: [7189052.749286] oom_reaper: reaped process 18540 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB |
OOM으로 인한 OOM Killer(강제 서비스 종료)였다. OOM은 무엇이고 왜 발생하는 것일까? 그리고 로그는 어떻게 확인할 수 있을까?
OOM (Out of Memory)
Linux의 swap 메모리와 물리 메모리를 모두 사용 중 일 때, 프로세스에서는 필요에 의해 추가적인 물리 메모리 할당을 요청하였는데, 더 이상 할당할 물리 메모리 공간이 없어 할당이 불가능한 상태를 의미한다. 즉 메모리 Over Commit 상태일 때 발생하는 현상으로 물리적으로 메모리가 부족하다는 뜻이다. 이러한 문제는 물리 메모리만 증설하면 사실 간단히 해결된다. 하지만 왜 이러한 현상이 발생하는지 원인을 찾지 못한 상태에서 무한정 메모리를 증설할 수도 없다.
OOM Killer
서버 메모리 부족으로 OOM이 발생하였을 때, 리눅스에서는 메모리를 확보하기 위해 OOM Score를 기준으로 점수가 높은 프로세스를 강제로 Kill 하여 메모리를 확보하는 Kernel 기능이다. 이렇게 OOM Killer로 프로세스가 종료되면 내부 시스템 로그에 기록되어 추후 확인할 할 수 있다.
OOM Killer Log 확인
OOM Killer로 프로세스가 종료되었을 때에는 각종 시스템 로그에서 확인할 수 있다. 시스템 로그에는 OOM Killer외에도 다양한 로그가 있기 때문에 로그 양이 많을 경우 필터를 해서 검색을 해야 할 수도 있다. 일반적으로 특별히 로그 경로를 수정하지 않았다면 아래 경로에서 다양한 시스템 로그를 확인할 수 있다.
/var/log/ |
Kern.log에서는 아래와 같은 OOM 로그를 확인할 수 있었다.
cat kern.log |
Aug 30 01:35:08 XXXXX kernel: [7189052.423131] [18540] 111 18540 1930392 1535479 12935168 0 0 mysqld Aug 30 01:35:08 XXXXX kernel: [7189052.423132] Out of memory: Kill process 18540 (mysqld) score 512 or sacrifice child Aug 30 01:35:08 XXXXX kernel: [7189052.424065] Killed process 18540 (mysqld) total-vm:7721568kB, anon-rss:6141916kB, file-rss:0kB, shmem-rss:0kB Aug 30 01:35:08 xxxxx kernel: [7189052.749286] oom_reaper: reaped process 18540 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB |
syslog에서는 다양한 로그가 많이 기록되어 OOM이라는 필터를 사용하여 확인하였다.
cat syslog | grep oom |
Aug 29 23:45:33 xxxxx kernel: [7182478.018455] oom_kill_process+0x21f/0x420 Aug 29 23:45:33 xxxxx kernel: [7182478.018529] [ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name Aug 29 23:45:34 xxxxx kernel: [7182478.495925] oom_reaper: reaped process 22648 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB Aug 30 01:35:08 xxxxx kernel: [7189052.422998] icinga2 invoked oom-killer: gfp_mask=0x14200ca(GFP_HIGHUSER_MOVABLE), nodemask=(null), order=0, oom_score_adj=0 Aug 30 01:35:08 xxxxx kernel: [7189052.423021] oom_kill_process+0x21f/0x420 Aug 30 01:35:08 xxxxx kernel: [7189052.423096] [ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name Aug 30 01:35:08 xxxxx kernel: [7189052.749286] oom_reaper: reaped process 18540 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB |
message 로그 파일에서도 동일한 오류 내역을 확인할 수 있다. Message 로그 파일은 다양한 로그 파일의 미러 역할을 하기 때문에 정말 다양한 로그가 기록되어 있다.
OOM killer 우선순위
로그를 살펴보면 OOM에 의해 mysqld가 kill 되었음을 확인할 수 있다. 그렇다면 프로세스를 종료시키는 우선순위는 어떻게 정해질까? 두 가지 방법이 있다.
1. oom_badness() 메소드에서 각 프로세스별 점수를 계산하여 종료시킬 프로세스를 선택한다.
2. 사용자가 특별히 지정하여 순위를 변동시킬 수 있다.
oom_badness()가 사용하는 우선순위 선정 방법은 아래와 같다.
1. 특정 프로세스를 킬 함으로써 최소한의 프로세스만 잃을 수 있어야 한다.
2. 많은 메모리를 회수할 수 있는 프로세스 (메모리 사용량이 작으면 킬 되지 않는다.)
3. 프로세스중 Leak이 발생하지 않는 프로세스 (릭이 발생하면 프로세스 Kill이 의미가 없다)
4. 사용자가 특별히 지정한 프로세스
이 외에도 nice와 score 기반으로 우선순위를 선정할 수 있다.
OOM Killer score 확인
OOM score 확인 방법은 /proc/${pid}/oom_score 파일을 통해 조회할 수 있다. PID를 확인하는 방법은 ps 명령을 사용한다.
l ps : shell에서 실행중인 프로세스만 출력
l ps -e : 실행 중인 모든 프로세스 출력
l ps -f : 실행중인 모든 프로세스의 상태 정보 출력
l ps -ef | grep mysql : grep을 사용하여 특정 프로세스(mysql) PID를 확인 한다.
ps -e | grep mywql |
cat /proc/15368/oom_score |
OOM Killer 순위 설정 방법
1. 특정 프로세스의 PID를 조회
2. /proc/PID/oom_adj 파일에 -17을 입력. oom_adj는 -17 ~ 15의 값을 가지며, 낮은 값 일수록 후순위.
3. /proc_PID/oom_scroe_adj 파일에 -1000을 입력. oom_score_adj는 -1000 ~ 1000의 값을 가지며 낮은 값일수록 후순위.
아래 예시는 oom_adj 파일에 -17로 변경하는 것으로 PID를 변경하여 사용할 수 있다.
sudo echo -17 > /proc/${pid}/oom_ajd |
아래 예시는 oom_score_adj파일에 -1000로 변경하는 것으로 PID를 변경하여 사용할 수 있다.
sudo echo -1000 > /proc/${pid}/oom_score_adj |
메모리 누수로 인한 System hang 현상을 방지하기 위해 리눅서 커널에서는 OOM killer 자체는 비활성화 할 수 없기 때문에 위 순위 설정을 참고하여 중요한 프로세스는 Kill 되지 않도록 한다.
2023-08-30 / Sungwook Kang / https://sungwookkang.com
리눅스, Linux, OOM, OutOfMemory, 메모리부족현상, 강제킬, 프로세스확인, 메모리압박, 아웃오브메모리, OOMKiller, oom_score