OOM Killer 프로세스 종료 정책 (OOM Killer Process Termination Policy)

Ⅰ. OOM Killer의 개념

1. 정의

OOM Killer (Out-Of-Memory Killer)는 Linux 커널이 시스템의 물리 메모리 및 스왑 영역이 완전히 고갈되었을 때, 메모리를 확보하기 위해 특정 프로세스를 강제 종료(Kill)하는 커널 메커니즘이다. OOM 상태에서는 새로운 메모리 할당이 불가능하므로, 커널이 직접 개입하여 시스템 전체의 다운(Crash)을 방지한다.

비유: OOM Killer는 "비상시 배를 가볍게 하기 위해 화물을 바다에 던지는 선장"이다. 배(시스템)가 침몰하는 것보다 일부 화물(프로세스)을 희생하는 것이 낫다.

2. OOM 발생 조건

OOM 발생 과정

[정상 상태]
  물리 메모리: 8GB / 16GB
  Swap: 0GB / 4GB
      |
      v  (메모리 사용 증가)
[메모리 압박 상태]
  물리 메모리: 15.5GB / 16GB
  Swap: 3.5GB / 4GB
  --> kswapd 활성, 페이지 회수 시작
      |
      v  (회수 불충분)
[OOM 경고 상태]
  물리 메모리: 16GB / 16GB (FULL)
  Swap: 4GB / 4GB (FULL)
  --> Direct Reclaim, Memory Compaction 시도
      |
      v  (모든 회수 실패)
[OOM 발생!]
  커널이 oom_badness()로 희생 프로세스 선정
  --> OOM Killer가 프로세스에 SIGKILL 전송
  --> 메모리 확보 후 시스템 계속 운영

3. OOM Killer의 목적

목적설명
시스템 생존 보장전체 시스템 패닉(Panic) 방지
서비스 연속성필수 서비스 유지, 덜 중요한 프로세스 희생
메모리 확보종료된 프로세스의 메모리를 즉시 회수
자동 복구관리자 개입 없이 자동으로 메모리 복원

Ⅱ. OOM 점수 산정 (oom_score)

1. oom_badness() 알고리즘

커널은 oom_badness() 함수를 통해 각 프로세스의 OOM 점수(oom_score)를 계산한다. 점수가 높을수록 OOM Killer에 의해 먼저 종료될 확률이 높다.

oom_score 산정 모델

oom_score = 프로세스 메모리 사용량 + 가중치 보정

+-----------------------------------------------+
|  oom_score 구성 요소                           |
|                                               |
|  1. Resident Set Size (RSS)                   |
|     --> 물리 메모리 상주 크기                   |
|                                               |
|  2. 페이지 테이블 크기 (Page Table Size)        |
|     --> 페이지 테이블 엔트리 수                  |
|                                               |
|  3. Swap 사용량                                |
|     --> 스왑 영역 사용 크기                     |
|                                               |
|  4. oom_score_adj 보정값                       |
|     --> 관리자가 수동 조정 (-1000 ~ +1000)     |
|                                               |
|  최종 점수 = (RSS + Swap + PageTable) / 총메모리 |
|             + oom_score_adj 보정                |
+-----------------------------------------------+

2. oom_score 범위

점수 범위의미
0메모리를 거의 사용하지 않음 (거의 종료되지 않음)
1~999보통 수준의 메모리 사용
1000매우 높은 점수 (OOM 발생 시 높은 우선순위로 종료)

3. 점수 확인 방법

# 특정 프로세스의 OOM 점수 확인
cat /proc/[pid]/oom_score
# 예: 543

# OOM 점수 조정값 확인
cat /proc/[pid]/oom_score_adj
# 예: 0

# 전체 프로세스의 OOM 점수 확인 (높은 순서)
ps -eo pid,comm,rss,oom_score | sort -k4 -rn | head -10

비유: oom_score는 "위험도 순위표"다. 선장(OOM Killer)은 가장 높은 점수를 받은 화물을 먼저 바다에 던진다. 점수를 낮추면 안전하다.


Ⅲ. oom_score_adj를 통한 제어

1. oom_score_adj

oom_score_adj는 관리자가 프로세스의 OOM 우선순위를 수동으로 조정할 수 있는 인터페이스이다. /proc/[pid]/oom_score_adj 파일에 값을 기록하여 변경한다.

oom_score_adj 설정에 따른 동작

[-1000]  ================================================
         OOM 면제: 이 프로세스는 OOM Killer 대상에서 제외
         단, 시스템 자체가 불가피한 상황이면 예외 존재

[-999 ~ -1]  ==========================================
              oom_score에서 해당 값만큼 차감
              종료 확률 낮아짐

[0]  ====================================================
     기본값: oom_badness()로 계산된 점수 그대로 사용

[+1 ~ +999]  ==========================================
              oom_score에서 해당 값만큼 가산
              종료 확률 높아짐

[+1000]  ================================================
          무조건 최우선 종료 대상
          OOM 발생 시 가장 먼저 SIGKILL

2. 설정 예시

# 프로세스를 OOM Killer로부터 보호
echo -1000 > /proc/1234/oom_score_adj

# 프로세스를 OOM 시 우선 종료 대상으로 지정
echo 500 > /proc/1234/oom_score_adj

# 기본값으로 복원
echo 0 > /proc/1234/oom_score_adj

# 설정 확인
cat /proc/1234/oom_score_adj

3. systemd에서의 OOMScoreAdjust

# /etc/systemd/system/myapp.service
[Service]
OOMScoreAdjust=-500    # OOM 종료 우선순위 낮춤 (보호)
ExecStart=/usr/bin/myapp
OOMScoreAdjustsystemd 기본값
systemd 자체-1000 (항상 보호)
사용자 서비스0
커스텀 설정-1000 ~ 1000

Ⅳ. cgroup 기반 OOM 제어

1. cgroup v1: memory.oom_control

cgroup (Control Group)을 사용하면 프로세스 그룹 단위로 메모리 사용량을 제한하고 OOM 동작을 제어할 수 있다.

cgroup 메모리 제어 구조

[System Level]
  oom_kill_disable=0 (default)
  -->
  [cgroup: /sys/fs/cgroup/memory/database]
    memory.limit_in_bytes = 4G
    memory.oom_control:
      oom_kill_disable = 0  --> OOM Killer 활성
      under_oom = 0         --> 현재 OOM 아님
    |
    +-- [PostgreSQL] (PID 1001)
    +-- [Redis]      (PID 1002)
    
  [cgroup: /sys/fs/cgroup/memory/app]
    memory.limit_in_bytes = 2G
    memory.oom_control:
      oom_kill_disable = 1  --> OOM Killer 비활성
    --> 메모리 초과 시 해당 cgroup 내 프로세스 멈춤 (Sleep)
    --> 관리자가 수동 해제해야 함

2. cgroup v2: memory.events

# cgroup v2에서 OOM 이벤트 확인
cat /sys/fs/cgroup/memory/mygroup/memory.events
# low 0
# high 0
# max 3
# oom 1
# oom_kill 1

# 메모리 한계 설정
echo "2G" > /sys/fs/cgroup/memory/mygroup/memory.max

# OOM Kill 비활성화 (v2에서는 memory.oom.group 등 활용)
echo 1 > /sys/fs/cgroup/memory/mygroup/memory.swap.max

3. OOM Kill Disable의 주의사항

oom_kill_disable=1 설정 시 동작

+--------------------------------------------------+
| memory.limit_in_bytes = 2G                       |
| oom_kill_disable = 1                             |
|                                                  |
| [메모리 초과 시]                                  |
|   --> OOM Killer가 프로세스를 죽이지 않음          |
|   --> 해당 cgroup 내 프로세스이 Sleep 상태로 대기   |
|   --> 새 메모리 할당은 즉시 실패 (ENOMEM)          |
|   --> 시스템 전체 OOM으로 확산 가능               |
|                                                  |
| [주의!]                                          |
|   부적절한 사용은 시스템 전체 불안정 유발          |
|   반드시 모니터링과 알림 필요                     |
+--------------------------------------------------+

비유: cgroup은 "건물별 전기 사용량 제한기"다. 한 건물이 한계를 넘으면 그 건물만 차단(OOM Kill)하는데, oom_kill_disable=1은 "한계를 넘어도 차단하지 않겠다"는 의미로, 결국 전체 건물(시스템)이 정전될 수 있다.


Ⅴ. OOM Killer 로그 분석 및 대응

1. OOM Killer 로그

# dmesg 또는 /var/log/syslog에서 OOM 이벤트 확인
dmesg | grep -i "oom\|out of memory\|killed process"

# 로그 예시:
# Out of memory: Killed process 12345 (java) total-vm:8G, anon-rss:6G
# oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),
#   cpuset=systemd,mems_allowed=0,oom_memcg=/database,
#   task=java,pid=12345,uid=1000,oom_score_adj=0

2. OOM 방지 전략

OOM 방지 다중 방어 레이어

[Layer 1: 예방]
  ├── 메모리 사용량 모니터링 (Prometheus, Grafana)
  ├── Swap 영역 적절한 크기 설정
  └── 과도한 메모리 할당 제한 (ulimit -v)

[Layer 2: 제어]
  ├── cgroup 메모리 제한 설정
  ├── oom_score_adj로 중요 프로세스 보호
  └── 메모리 과다 할당 해제 (vm.overcommit_memory)

[Layer 3: 대응]
  ├── OOM 이벤트 알림 설정
  ├── 자동 재시작 메커니즘 (systemd restart)
  └── 장애 후 포스트모템 분석

요약

지식 그래프

OOM Killer 프로세스 종료 정책
├── 개념
│   ├── Out-Of-Memory 상태
│   ├── 커널 개입으로 시스템 생존 보장
│   └── SIGKILL로 강제 프로세스 종료
├── 점수 산정
│   ├── oom_badness() 함수
│   ├── RSS (Resident Set Size)
│   ├── 페이지 테이블 크기
│   └── Swap 사용량
├── 점수 제어
│   ├── oom_score (0~1000, 읽기 전용 산정값)
│   ├── oom_score_adj (-1000~+1000, 수동 조정)
│   └── /proc/[pid]/oom_score_adj
├── cgroup 제어
│   ├── cgroup v1: memory.oom_control
│   ├── cgroup v2: memory.events
│   ├── memory.limit_in_bytes
│   └── oom_kill_disable
├── 관리자 도구
│   ├── dmesg (OOM 로그 확인)
│   ├── ps (프로세스 점수 확인)
│   └── systemd OOMScoreAdjust
└── 방지 전략
    ├── 모니터링
    ├── 메모리 제한 설정
    └── 자동 복구

세 줄 설명 (어린이용)

  1. OOM Killer는 컴퓨터의 메모리가 꽉 찼을 때, 가장 덜 중요한 프로그램을 골라서 끄는 "긴급 구조대"예요.
  2. 각 프로그램은 점수(oom_score)를 받는데, 점수가 높을수록 먼저 끌려가고, 점수를 낮추면 안전해져요.
  3. 점수를 -1000으로 하면 "절대 끄지 마!"라고 표시할 수 있고, cgroup으로도 그룹 단위로 지킬 수 있어요.

약어 정리

약어Full Name
OOMOut-Of-Memory
RSSResident Set Size
SIGKILLSignal Kill (무조건 종료 시그널)
ENOMEMError No Memory
cgroupControl Group