VPS를 위한 Linux OOM 킬러 튜닝: 실용적인 가이드

12분 소요 - 2026년 6월 8일

hero section cover
목차
  • VPS용 Linux OOM 킬러 조정
  • OOM 킬러가 희생 대상을 선택하는 방식
  • 시스템 중단 전에 메모리 부하 감지하기
  • oom_score_adj를 사용하여 중요 프로세스 보호
  • cgroups 및 systemd를 이용한 메모리 제한
  • OOM 이벤트 발생 후 로그 확인
  • 마치며
공유

데이터베이스와 SSH를 보호하고, cgroups로 폭주 프로세스를 제한하고, 잘못된 서비스가 중단되는 것을 막기 위해 VPS에서 Linux OOM 킬러를 조정하세요.

VPS용 Linux OOM 킬러 조정

Linux OOM 킬러는 메모리가 부족할 때 커널이 취하는 최후의 수단입니다. 시스템이 계속 작동할 수 있도록 프로세스를 선택하여 종료합니다. RAM 용량이 부족하고 대체할 수단이 없는 VPS 환경에서는 기본 설정이 종종 잘못된 선택이 됩니다. 데이터베이스 프로세스는 종료되고, 오랫동안 실행 중인 작업자(worker) 프로세스는 살아남으며, 사용자는 그 이유를 파악해야 하는 상황에 처하게 됩니다. 이 가이드에서는 OOM 킬러가 프로세스에 점수를 매기는 방식, 중요한 서비스에 점수가 더 많이 부여되도록 설정하는 방법, 그리고 하나의 폭주하는 프로세스가 나머지 시스템을 함께 다운시키지 못하도록 cgroups를 사용하는 방법을 다룹니다.


 

OOM 킬러가 희생 대상을 선택하는 방식

커널이 페이지 캐시 제거나 스왑을 통해 충분한 메모리를 회수할 수 없을 때, OOM 킬러를 호출합니다. 모든 프로세스에는 oom_score 0에서 1000 사이의 점수를 가지며, 이는 주로 상주 세트 크기(RSS)와 스왑 사용량에서 파생됩니다. 점수가 가장 높은 프로세스는 SIGKILL 신호를 받게 됩니다.

RSS가 계산에 가장 큰 비중을 차지하기 때문에, 종료 대상은 거의 항상 메모리를 가장 많이 소비하는 프로세스가 됩니다. 이는 대개 데이터베이스, 애플리케이션 서버, 또는 가장 유용한 작업을 수행하는 장기 실행 프로세스입니다. 실제로 할당을 유발한 프로세스, 즉 "호출자"가 종료되는 경우는 드뭅니다.

구분하여 이해해야 할 두 가지 유형의 OOM 이벤트가 있습니다:

  • 전역 OOM(Global OOM): 호스트(또는 VPS 전체)의 RAM과 스왑 공간이 부족합니다. 커널은 모든 프로세스를 스캔하여 점수가 가장 높은 프로세스를 종료합니다.
  • Cgroup OOM: 특정 cgroup이 메모리 한도에 도달한 경우입니다. 시스템의 나머지 부분에 여유 메모리가 있더라도 커널은 해당 cgroup 내에서만 프로세스를 종료합니다.

systemd 유닛 제한을 설정했거나 컨테이너를 실행 중인 경우, 대부분의 OOM 이벤트는 cgroup OOM일 것입니다. 이는 긍정적인 현상입니다. 영향 범위가 제한되기 때문입니다.

시스템 중단 전에 메모리 부하 감지하기

OOM(메모리 부족) 이벤트는 거의 갑작스럽게 발생하지 않습니다. 대개 메모리 부하가 점차 증가하는 기간이 먼저 나타나며, 모니터링의 목표는 바로 그 기간 내에 이를 포착하는 것입니다.

free -h 는 시스템 전체를 보여줍니다. 중요한 열은 available, free: 이 열은 회수 가능한 페이지 캐시를 반영하며, 스왑 없이 실제로 할당할 수 있는 용량을 나타냅니다. MemAvailable 피크 부하 시 MemTotal 을 유지하십시오.

프로세스별 할당량을 확인하려면 RSS 기준으로 정렬하십시오:

ps aux --sort=-%mem | head -10

또는 htop 를 사용하여 RES. 여기서 보이는 값들은 커널의 점수 산정에 직접 반영되므로, 상위에 있는 항목들이 OOM 발생 가능성이 가장 높은 대상입니다.

커널 4.20 이상에서는 Pressure Stall Information이 모니터링 시스템에 통합할 가치가 있는 조기 경보 시스템입니다:

cat /proc/pressure/memory

some avg10 이 수치는 지난 10초 동안 적어도 하나의 태스크가 메모리를 기다리며 스톨된 시간의 비율을 나타냅니다. 5% 미만이면 정상입니다. 10%를 지속적으로 초과하는 값은 시스템이 메모리 회수 작업으로 인해 실제 시간을 차단된 상태로 소비하고 있음을 의미하며, OOM으로 인한 프로세스 종료가 발생할 가능성이 높습니다.

스왑 스래싱은 vmstat 1 에서 0이 아닌 siso 열에 시간이 지남에 따라 지속되는 값으로 나타납니다. 소량의 상주 스왑은 무해합니다. 지속적인 스왑 인(swap-in)과 스왑 아웃(swap-out)은 그렇지 않습니다.

oom_score_adj를 사용하여 중요 프로세스 보호

커널이 계산하는 점수는 -1000(면역)에서 +1000(우선 종료)까지의 척도를 사용하여 oom_score_adj-1000(면제)에서 +1000(우선 종료)까지의 척도로 프로세스별로 편향을 줄 수 있습니다. 이 조정은 최종 점수에 직접 더해집니다.

실행 중인 프로세스에 대해 일회성 변경을 하려면:

echo -500 | sudo tee /proc/$(pidof sshd)/oom_score_adj

재시작 후에도 지속되도록 하려면 systemd 유닛에서 설정하십시오. sshd, 데이터베이스 및 손실을 감당할 수 없는 기타 모든 항목에 대해 이 방법이 적합합니다:

[Service]
OOMScoreAdjust=-900

시작 시 적용할 합리적인 기본값:

  • sshd: -1000. 메모리 위기 상황에서 원격 접속이 끊기면 복구가 훨씬 더 어려워집니다.
  • MySQL, PostgreSQL, Redis: -800 ~ -900. 심각한 재난 상황에서도 완전히 손대지 못하게 만들지 않으면서 강력한 보호를 제공합니다.
  • 애플리케이션 워커, 배치 작업, cron 작업: +100 ~ +500. 데이터베이스보다는 이 프로세스들이 종료되는 편이 낫습니다.

모든 프로세스를 -1000으로 설정하지 마십시오. 종료할 수 있는 프로세스가 하나도 없으면, 커널이 결국 패닉 상태에 빠지거나 멈추게 되며, 이는 더 심각한 결과를 초래합니다.

cgroups 및 systemd를 이용한 메모리 제한

점수를 조정하면 어떤 프로세스가 종료될지 결정됩니다. cgroups는 글로벌 종료(global kill)가 실제로 발생할지 여부에 영향을 미칩니다. 각 서비스에 엄격한 상한선을 부여함으로써, 하나의 프로세스가 전체 VPS의 메모리를 고갈시키는 것을 방지하고 메모리 오류를 단일 cgroup으로 제한할 수 있습니다.

systemd 유닛 파일에서:

[Service]
MemoryHigh=400M
MemoryMax=512M
OOMPolicy=stop
Restart=on-failure
RestartSec=5s

MemoryHigh 는 소프트 스로틀입니다: 커널은 이 지점 이상의 cgroup에서 페이지를 적극적으로 회수하지만, 프로세스를 종료하지는 않습니다. MemoryMax 는 엄격한 상한선입니다. cgroup이 이 한도를 초과하여 할당을 시도하면 커널은 해당 cgroup 내의 프로세스를 종료합니다. Restart=on-failure 서비스는 즉시 다시 시작됩니다.

cgroup v2(Ubuntu 22.04 이상, 최신 Debian, RHEL 9)에서는 memory.oom.group 고아 프로세스를 남기지 않고 cgroup 내의 모든 프로세스를 함께 종료합니다. 절반만 종료된 그룹이 비정상적으로 동작할 수 있는 PHP-FPM 풀과 같은 다중 프로세스 서비스에 유용합니다.

적용해 볼 만한 몇 가지 애플리케이션별 참고 사항:

  • PHP-FPM: pm = ondemand 설정하고, pm.max_children 값을 설정하세요. 2GB VPS에서 4GB의 여유 공간을 확보하도록 풀 크기를 설정하면, 용량이 처음 가득 찰 때 OOM 오류가 발생합니다.
  • Node.js: V8 힙 크기를 --max-old-space-size=512 (MB 단위)로 제한하십시오. 이를 설정하지 않으면 커널이 개입할 때까지 Node가 무제한으로 확장됩니다.
  • MySQL 및 PostgreSQL: innodb_buffer_pool_size 그리고 shared_buffers 설정 시 OS 페이지 캐시, 연결 메모리 및 서버 내 다른 애플리케이션에 충분한 여유 공간을 확보해야 합니다. 기본값은 전용 서버를 전제로 합니다.

OOM 이벤트 발생 후 로그 확인

OOM 킬러가 작동하면 커널은 링 버퍼에 상세한 보고서를 기록합니다. 다음 명령어로 해당 내용을 추출하십시오:

dmesg -T | grep -iE 'killed process|out of memory'
journalctl -k --grep='Out of memory'

주의 깊게 읽어야 할 블록은 호출자(invoker)로 시작하여 희생자(victim)로 끝납니다. 커널은 각 프로세스의 RSS, 스왑 사용량 및 최종 oom_score_adj. 다음 세 가지를 확인해 볼 가치가 있습니다:

  • 제약 조건. CONSTRAINT_NONE 는 전역 OOM을, CONSTRAINT_MEMCG 는 cgroup이 한도에 도달했음을 의미합니다. 해결 방법은 각각 다릅니다.
  • Free swap. 만약 이 경우라면 0kB인 경우, RAM과 스왑 모두 소진된 것입니다. 스왑 공간을 추가하거나 MemoryMax , 또는 동시 실행 수를 줄여야 합니다.
  • 피해 프로세스의 점수와 다른 모든 프로세스의 점수를 비교하십시오. 피해 프로세스의 점수가 다음 몇 개의 프로세스보다 훨씬 높지 않다면, oom_score_adj 값이 충분한 효과를 내지 못하고 있는 것입니다. 격차를 더 벌리십시오.

특히 cgroup OOM의 경우, kill 카운터는 memory.events cgroup 내부에 위치합니다:

cat /sys/fs/cgroup/system.slice/mysql.service/memory.events

카운터가 증가한다는 oom_kill 카운터는 해당 서비스가 반복적으로 제한에 도달하고 있음을 의미합니다. 이는 MemoryMax, 워크로드를 분석하거나, 서비스를 더 큰 리소스 플랜으로 이동해야 한다는 신호이지, 서비스를 무한 루프처럼 계속 재시작하라는 신호가 아닙니다.

마치며

OOM 킬러를 조정하는 것은 이를 없애는 것이 아닙니다. 메모리가 부족해졌을 때 어떤 프로세스가 그 대가를 치를지 제어하고, 문제가 발생했을 때 그 영향 범위를 줄이는 것입니다. 실제 운영 환경에서 통하는 패턴은 다음과 같습니다:

  • 절대 중단되어서는 안 되는 서비스, 특히 sshd와 데이터베이스에 스코어 프로텍트(score-protect)를 적용하십시오.
  • 나머지 모든 항목은 MemoryMax in a systemd unit로 제한하여, 단일 프로세스의 이상 동작이 서비스 중단이 아닌 단순한 재시작으로 끝나게 하십시오.
  • PSI를 주시하고 MemAvailable 사후에 dmesg 가 사후에 상황을 알려주기를 기다리지 마십시오.
  • RAM의 15~20%를 여유 공간으로 남겨두십시오. 튜닝만으로는 워크로드에 비해 단순히 용량이 너무 작은 VPS의 문제를 해결할 수 없습니다.

메모리 부하가 구성 문제로 인한 것이 아니라 구조적인 문제라면, 더 많은 RAM이나 더 빠른 스왑 기반 스토리지가 필요합니다. FDC Servers의 VPS 플랜은 NVMe 스토리지가 탑재된 AMD EPYC에서 실행되므로, 스왑 기반 읽기 속도가 충분히 빨라 짧은 메모리 급증으로 인해 서비스가 중단되는 일이 없습니다.

블로그

이번 주 추천

더 많은 기사
VPS를 위한 Linux OOM 킬러 튜닝: 실용적인 가이드

VPS를 위한 Linux OOM 킬러 튜닝: 실용적인 가이드

데이터베이스와 SSH를 보호하고, cgroups로 폭주 프로세스를 제한하고, 잘못된 서비스가 중단되는 것을 막기 위해 VPS에서 Linux OOM 킬러를 조정하세요.

12분 소요 - 2026년 6월 8일

Linux 트래픽 제어(tc): 실무 가이드

12분 소요 - 2026년 6월 5일

더 많은 기사
background image

질문이 있거나 맞춤형 솔루션이 필요하신가요?

icon

유연한 옵션

icon

글로벌 도달 범위

icon

즉시 배포

icon

유연한 옵션

icon

글로벌 도달 범위

icon

즉시 배포