Out Of Memory Killer 회피하기

Eunju Son
4 min readApr 28, 2019

이전에 쓴 번역글에서 메모리가 부족할 때 머신의 내부에서 어떤 일들이 벌어지는지 간단하게 살펴보았습니다. 다시 한 번 요약해보면, 프로세스가 메모리를 필요로 할 때 RAM에 가용한 메모리가 없으면 buff/cache 나 swap file system을 빌려서 사용하게 됩니다. 하지만 이또한 부족해지는 시점이 있는데 그 시점에서 리눅스 커널이 OOM Killer라 불리는 작업을 실행해서 현재 실행중인 프로세스를 끈다는 내용이었습니다.

이 포스트에서는 바로 그 OOM Killer가 무엇이며 어떤 원리로 동작하는지, OOM Killer로부터 꺼져서는 안되는 중요한 프로세스를 어떻게하면 지킬 수 있는지에 대해서 알아보려고 합니다.

What is OOM(Out Of Memory) Killer?

lol

개발한 프로그램을 운영하다보면 누구든 다음과 같은 에러를 만난 경우가 있을 것입니다. 프로세스들이 필요로 하는 메모리를 할당받지 못하면 시스템은 점점 느려지다가 끝에서는 거의 멈춰버린 것 같은 체감을 줍니다. 심하면 교착 상태(deadlock)에 빠지게 될 수도 있겠습니다. 이런 상황이 일어나지 않기 위해서 커널이 부르는 것이 바로 OOM Killer입니다.

OOM Killer는 시스템을 위해서 하나 이상의 프로세스들을 희생시키는 역할을 합니다. 이 때 희생되는 프로세스와 같은 mm_struct (프로세스가 사용하고 있는 메모리를 저장하는 메모리 디스크립터)를 공유하는 프로세스 또한 같이 희생됩니다. 희생시킬 프로세스를 고르는 로직은 커널 코드에서 확인해볼 수 있습니다.

OOM Killer는 메모리를 기준으로 가장 나쁜(?) 녀석을 선택해 희생시켜서 결과적으로 좋은 상태를 만드는 것을 목표로 합니다. 위의 주석을 통해 OOM Killer가 목표로 하는 것을 알 수 있습니다.

  1. 완료된 작업의 수를 최대로 유지할 수 있게 한다.
  2. 많은 양의 메모리를 복구한다
  3. 무고한(메모리를 많이 소비하지 않는) 프로세스는 죽이지 않는다
  4. 최소한의 프로세스만 희생시킨다
  5. 사용자(여기서는 개발자)가 희생되리라고 기대하고 있는 프로세스를 죽인다

OOM Scoring

OOM Killer는 희생시킬 프로세스를 고르기 위해서 각 프로세스에 점수를 매기는 과정을 거칩니다. 앞으로 이 점수를 나쁨 점수라고 부르겠습니다. OOM Killer는 결과적으로 메모리가 부족해졌을 때 프로세스 중 가장 높은 나쁨 점수를 받은 순서대로 프로세스를 척살(?)하기 시작합니다.

나쁨 점수는 기본적으로 프로세스에게 할당된 메모리의 양으로 매겨집니다.

거기에 해당 프로세스로부터 fork()된 자식 프로세스들의 메모리를 더해줍니다.

거기에 오래 돌고 있는 프로세스의 경우 그만큼 점수를 낮춰주고, 나이스된 프로세스는 나쁨 점수를 두배로 올립니다.

여기서 나이스란 프로세스의 우선 순위를 낮춰주는 점수를 의미합니다. 이에 대해서 더 알고싶으시다면 제 블로그의 Process and Kernel 편을 참고해주세요 (깨알홍보)

마지막으로 다른 프로세스들보다 비교적 중요하게 취급되어지는 프로세스들 (superuser에 의해서 실행되거나, 하드웨어와 직접적인 관련이 있는)은 값을 크게 낮춰줍니다.

종합해보면 나쁨 점수는 가장 최근에 시작되서, 스스로와 자식들이 메모리를 많이 사용하고, 우선순위가 낮은 프로세스가 높게 부여받게 됩니다. 프로세스의 나쁨 점수를 직접적으로 보고 싶다면 /proc/<pid>/oom_score파일을 확인해보면 됩니다.

$ cat /proc/19862/oom_score
12

OOM Killer의 척살 대상으로부터 벗어나기

시스템이 멈춰버리는 것을 피하기 위해서 OOM Killer를 끄는 것은 불가능하게 되어 있습니다. 하지만 가끔은 서비스의 안정성을 위해서 꺼지면 안 될 프로세스도 존재하는 법입니다. (예를 들어서 특정한 작업을 하고 있던 worker 프로세스가 이런 경우에 들 수 있겠죠)

OOM Killer를 직접적으로 끌 수는 없지만, OOM Killer의 scoring 대상에서 벗어나는 것은 가능합니다. 그리고 생각보다 쉽게 할 수 있습니다. 바로 /proc/<pid>/oom_adj값을 -17로 설정해주는 것입니다. -17 값은 OOM_DISABLE의 상수 값입니다.

$ echo -17 > /proc/<pid>/oom_adj

이 외에도 proc/<pid>/oom_scoring_adj값을 -1000으로 설정하는 방법도 있습니다. 하지만 이 방법은 OOM Scoring을 비활성화한다기보다는 충분히 낮은 값을 주어서 척살 대상에서 벗어나게 하는 식으로 작동합니다.

--

--

Eunju Son

Passionate Developer who is interested in SRE Devops / Platform / Deep Learning. Github: @EJSohn, Blog: https://ejsohn.github.io/