OOM 정책 마스터하기: 메모리 부족 상황에 대한 Systemd의 대응 방식 조정
Linux 시스템은 강력하게 설계되었지만, 과부하 상태이거나 메모리 누수로 인해 가용 메모리가 부족해질 수 있습니다. 이러한 상황이 발생하면 커널의 OOM(Out-of-Memory) 킬러가 호출되어 프로세스를 종료하고 메모리를 확보하여 시스템 전체 충돌을 방지합니다. 그러나 기본 OOM 킬러 동작이 항상 최적인 것은 아니며, 중요 서비스의 종료로 이어질 수 있습니다. 많은 Linux 배포판에서 최신 init 시스템이자 서비스 관리자인 Systemd는 시스템이 메모리 고갈에 직면했을 때 프로세스를 처리하는 방식을 세밀하게 조정할 수 있는 강력한 도구를 제공합니다.
이 기사에서는 systemd 유닛 파일 내의 OOMScoreAdjust 및 OOMPolicy 지시어를 중심으로 systemd의 OOM(Out-Of-Memory) 정책을 구성하는 방법을 자세히 다룹니다. 이러한 설정을 이해하고 조작함으로써 커널이 희생시키기로 선택하는 프로세스에 크게 영향을 미칠 수 있으며, 이를 통해 메모리 부족 상황에서도 핵심 애플리케이션을 보호하고 시스템 안정성을 보장할 수 있습니다.
Linux OOM 킬러 이해
Systemd의 구성으로 들어가기 전에 OOM 킬러가 어떻게 작동하는지 파악하는 것이 중요합니다. 커널은 할당 요청을 충족시키기 위해 더 이상 확보할 수 있는 메모리가 없음을 감지하면 OOM 킬러를 호출합니다. 이 메커니즘은 실행 중인 프로세스를 스캔하고 각 프로세스에 oom_score를 할당하며, 이는 해당 프로세스의 '나쁨 정도' 또는 종료될 가능성을 나타냅니다. 많은 양의 메모리를 소비하거나, 오랫동안 실행되었거나, oom_score가 더 높은 프로세스가 종료 대상이 될 가능성이 높습니다.
oom_score는 메모리 사용량, 프로세스 우선순위, 프로세스가 실행된 기간을 포함한 여러 요소를 기반으로 계산됩니다. 그런 다음 커널은 시스템 운영을 유지하기에 충분한 메모리를 회수하기를 바라면서 가장 높은 oom_score를 가진 프로세스를 선택하여 종료합니다. 효과적이기는 하지만, 이 프로세스는 사후 대응적이며 때로는 덜 중요한 프로세스 또는 oom_score가 의도치 않게 높아진 중요한 프로세스까지 종료하게 만들 수 있습니다.
Systemd와 OOM 제어
Systemd는 개별 서비스에 대한 OOM 동작을 관리하기 위한 보다 세분화된 접근 방식을 제공합니다. 커널의 전역 OOM 점수에만 의존하는 대신, systemd 유닛이 관리하는 프로세스의 oom_score에 영향을 미치고 OOM 조건에서 해당 유닛이 어떻게 작동해야 하는지에 대한 특정 정책까지 정의할 수 있습니다.
OOMScoreAdjust 지시어
systemd 유닛 파일에서 사용할 수 있는 OOMScoreAdjust 지시어를 사용하면 해당 유닛이 시작한 프로세스의 oom_score에 직접적으로 영향을 미칠 수 있습니다. 이는 유닛의 메인 프로세스에 대한 /proc/[pid]/oom_score_adj 파일의 oom_score_adj 값을 조정함으로써 달성됩니다.
- 값 범위:
OOMScoreAdjust의 범위는 -1000부터 1000까지입니다. - 값이 -1000이면 프로세스가 OOM 킬러에 면역이 됩니다.
- 값이 1000이면 프로세스가 종료를 위한 주요 후보가 됩니다.
- 값이 0이면
oom_score_adj가 수정되지 않으며, 프로세스의oom_score는 커널의 기본 로직에 의해 결정됩니다.
작동 방식: Systemd가 서비스를 시작할 때 해당 프로세스에 대한 oom_score_adj를 설정할 수 있습니다. oom_score_adj 값이 낮을수록 프로세스의 oom_score가 감소하여 종료될 가능성이 줄어듭니다. 반대로, 값이 높을수록 oom_score가 증가합니다.
예시: OOM 이벤트 중에 중요한 데이터베이스 서비스가 종료될 가능성을 줄이려면 해당 systemd 유닛 파일(예: /etc/systemd/system/mydatabase.service)에 다음을 추가할 수 있습니다.
[Service]
ExecStart=/usr/bin/my-database-server
OOMScoreAdjust=-500
이 예시에서 OOMScoreAdjust=-500은 my-database-server 프로세스의 oom_score를 크게 감소시켜 OOM 킬러의 대상이 될 가능성을 훨씬 낮춥니다. OOMScoreAdjust=-1000으로 설정하면 효과적으로 해당 프로세스를 보호할 수 있습니다.
팁: OOMScoreAdjust=-1000 사용 시에는 극도로 주의해야 합니다. 프로세스에 메모리 누수가 있을 경우 완전히 면역 상태로 만들면 해당 프로세스가 제거되지 않아 다른 필수 프로세스의 메모리를 고갈시켜 시스템 불안정으로 이어질 수 있습니다.
OOMPolicy 지시어
OOMPolicy 지시어는 주어진 유닛에 대해 OOM 상황을 처리하는 방법에 대한 보다 구체적인 지침을 systemd에 제공합니다. 이는 시스템이 메모리 압박을 받고 유닛의 프로세스가 종료 대상으로 고려될 때의 동작을 결정합니다.
- 가능한 값:
inherit(기본값): 유닛이 상위 cgroup으로부터 OOM 정책을 상속받습니다. 이것이 가장 일반적인 설정입니다.continue: 프로세스가 종료되지 않고 시스템이 계속 작동합니다. 이는 근본적인 문제가 해결되지 않으면 추가적인 메모리 고갈로 이어질 수 있습니다.kill: 프로세스가 OOM 킬러에 의해 종료됩니다.critical: 유닛을 중요(critical)로 표시합니다. 시스템은 이 중요 유닛 내의 프로세스를 종료하기 전에 중요하지 않은(non-critical) 프로세스를 종료하여 메모리를 확보하려고 시도합니다.special:special:container: 컨테이너 유닛이 이 정책으로 표시되면 OOM 조건이 발생할 경우 전체 컨테이너가 종료됩니다.special:stop: OOM 조건이 발생할 때 서비스가 종료됩니다(강제 종료가 아님).
예시: 웹 서버를 중요(critical)로 지정하여 다른 중요하지 않은 프로세스가 먼저 종료되도록 보장합니다.
[Service]
ExecStart=/usr/bin/nginx
OOMPolicy=critical
예시: OOM 킬러에 의해 강제 종료되도록 두는 대신 서비스를 정상적으로 중지하려면:
[Service]
ExecStart=/usr/local/bin/my-batch-job
OOMPolicy=special:stop
이 구성은 메모리 압박이 높을 때 my-batch-job 프로세스에 깔끔하게 종료하라는 신호를 보내며, 갑작스러운 종료 대신 가능하다면 현재 작업을 완료할 수 있도록 합니다.
경고: continue 정책은 매우 신중하게 사용해야 합니다. 만약 어떤 프로세스가 메모리 압박의 원인이 되고 있는데 계속 실행되도록 허용된다면, 이는 문제를 악화시켜 잠재적으로 전체 시스템 정지 또는 통제 불가능한 충돌로 이어질 수 있습니다.
실제 적용 및 모범 사례
- 중요 서비스 식별: 시스템 운영에 필수적인 서비스(예: 데이터베이스, 중요 애플리케이션 백엔드, 핵심 네트워크 서비스)가 무엇인지 결정합니다. 이들이 OOM 정책 조정을 위한 주요 후보입니다.
OOMScoreAdjust를 통한 미세 조정: 중요 서비스의 경우OOMScoreAdjust를 사용하여oom_score를 낮춥니다. 적당한 값(예: -200에서 -500)으로 시작하고 시스템 동작을 모니터링하세요. 필요한 경우에만 조정을 늘리고, 프로세스를 면역 상태로 만드는 위험을 항상 염두에 두십시오.OOMPolicy=critical활용: 절대적으로 중요한 서비스의 경우OOMPolicy=critical은 강력한 옵션입니다. 이는 시스템이 중요한 서비스를 고려하기 전에 다른 프로세스를 종료하는 것을 우선하도록 지시합니다.- 정상적인 종료를 위한
OOMPolicy=special:stop고려: 서비스가 안전하게 중지되고 다시 시작될 수 있는 경우special:stop을 사용하면 즉각적인 강제 종료보다 더 통제된 종료가 가능합니다. - 시스템 메모리 모니터링: OOM 정책 조정은 사후 대응적인 조치입니다. 최선의 접근 방식은 시스템 메모리 사용량을 사전에 모니터링하고 메모리 고갈의 근본 원인(예: 메모리 누수, 불충분한 RAM, 비효율적인 애플리케이션 코드)을 해결하는 것입니다.
- 철저한 테스트: OOM 정책에 변경 사항을 적용한 후, 부하 상태에서 시스템을 철저히 테스트하여 원하는 동작이 달성되었는지, 의도하지 않은 결과가 발생하지 않았는지 확인하십시오.
- 변경 사항 문서화: 각 변경 사항의 이유를 포함하여 유닛 파일에 적용된 모든 OOM 정책 구성을 기록으로 유지합니다.
OOM 조정 확인
유닛 파일을 수정하고 systemd를 재로드한 후 (sudo systemctl daemon-reload 및 sudo systemctl restart <service-name>), 실행 중인 프로세스의 oom_score_adj를 확인할 수 있습니다.
먼저, systemd 유닛이 관리하는 프로세스의 PID를 찾습니다.
systemctl status <service-name>
출력에서 Main PID를 찾으십시오.
그런 다음, 해당 PID에 대한 oom_score_adj 값을 확인합니다.
cat /proc/<PID>/oom_score_adj
이 값이 OOMScoreAdjust 설정과 일치하면 구성이 올바르게 적용된 것입니다.
결론
Systemd의 OOM 제어 지시어인 OOMScoreAdjust와 OOMPolicy는 관리자에게 메모리 부족 시 시스템 동작을 관리하는 데 필수적인 도구를 제공합니다. 이러한 설정을 신중하게 조정함으로써 시스템의 복원력을 크게 향상시키고, 시스템이 심각한 메모리 압박을 받는 상황에서도 중요 서비스를 계속 사용할 수 있도록 보장할 수 있습니다. 이러한 구성은 시스템 안정성을 위한 광범위한 전략의 일부이며, 능동적인 메모리 관리가 OOM 이벤트를 완전히 방지하는 가장 효과적인 방법임을 기억하십시오.