MongoDB와 OOM(Out of Memory) Killer
이 문서는 Mydbops 블로그의 "Out of Memory Issues in MongoDB" (opens in a new tab)를 기반으로 작성되었습니다.
Linux에서 MongoDB를 운영할 때 가장 심각한 문제 중 하나는 메모리 부족(OOM) 상황입니다. 이 문제는 Linux 커널의 OOM Killer가 시스템 리소스를 확보하기 위해 프로세스를 강제 종료하면서 발생하며, MongoDB와 같은 핵심 서비스가 예기치 않게 중단될 수 있습니다. 이는 애플리케이션 성능 저하, 데이터 손실, 심각한 다운타임으로 이어질 수 있습니다.
이 글에서는 Linux OOM Killer의 작동 원리를 알아보고, MongoDB가 왜 OOM Killer의 대상이 되는지 살펴봅니다. 또한, OOM 이벤트로부터 MongoDB를 보호하기 위한 시스템 및 MongoDB 설정 최적화 전략을 다룹니다.
Linux OOM(Out of Memory) Killer란?
Linux OOM Killer는 시스템 메모리가 고갈되는 것을 방지하기 위한 커널의 보호 메커니즘입니다. 물리적 RAM과 스왑 공간이 거의 소진되면, 커널은 OOM Killer를 활성화하여 하나 이상의 프로세스를 종료하고 메모리를 확보합니다. 이 기능은 시스템 전체의 장애를 막아주지만, MongoDB와 같은 중요 프로세스가 종료될 경우 예기치 않은 서비스 중단을 초래할 수 있습니다.
OOM Killer는 언제 작동하는가?
OOM Killer는 다음과 같은 상황에서 활성화됩니다.
- 사용 가능한 메모리 부족: 총 가용 RAM이 임계치 이하로 떨어질 때.
- 메모리 압박: 여러 애플리케이션이 메모리를 과도하게 사용하여 신규 할당에 필요한 메모리가 부족할 때.
- 스왑 고갈: RAM과 스왑 공간이 모두 소진되어 즉각적인 메모리 확보가 필요할 때.
- 오버커밋(Overcommit) 처리: 프로세스가 실제 물리 메모리보다 더 많은 메모리를 요청하도록 허용하는 오버커밋 설정에서 실제 사용량이 물리적 한계를 초과할 때 OOM 상황이 발생할 수 있습니다.
- 특정 프로세스의 동작: 대량의 메모리를 사용하거나 특정 기준에 해당하는 프로세스는 OOM Killer의 주요 종료 대상이 됩니다.
OOM Killer의 작동 방식
Linux에서 실행되는 모든 프로세스는 oom_score
라는 점수를 가집니다. 이 점수는 OOM 상황에서 해당 프로세스가 종료될 가능성을 나타냅니다. oom_score
에 영향을 미치는 요인은 다음과 같습니다.
- 프로세스의 실제 및 비례적 메모리 사용량
- 프로세스 우선순위
- 사용자 권한
커널은 일반적으로 가장 높은 oom_score
를 가진 프로세스를 종료하여 최대한 많은 메모리를 확보하려고 시도합니다.
OOM Killer로부터 MongoDB 보호하기 위한 Linux 설정
oom_score
와 oom_score_adj
라는 두 가지 주요 파라미터를 조정하여 OOM Killer의 동작에 영향을 줄 수 있습니다. 이 값들은 /proc/<PID>/
경로의 파일을 통해 확인할 수 있습니다.
oom_score
확인하기
mongod
프로세스의 현재 OOM 점수는 다음 명령어로 확인할 수 있습니다. 점수가 높을수록 종료될 확률이 높습니다.
cat /proc/$(pidof mongod)/oom_score
oom_score_adj
조정하기
oom_score_adj
값을 조정하여 OOM Killer의 우선순위를 변경할 수 있습니다. 이 값의 범위는 -1000(종료 확률 가장 낮음)부터 1000(종료 확률 가장 높음)까지입니다.
echo -1000 > /proc/$(pidof mongod)/oom_score_adj
값을 -1000으로 설정하면 해당 프로세스는 OOM Killer로부터 거의 면역 상태가 됩니다. 하지만 이는 MongoDB가 가용 메모리를 모두 소진하여 시스템 전체를 불안정하게 만들 수 있으므로 신중하게 사용해야 합니다.
Linux 커널 2.6.36 이전 버전에서는 oom_score_adj
대신 oom_adj
를 사용해야 할 수 있습니다. oom_adj
의 범위는 -16(가장 낮음)부터 +15(가장 높음)까지입니다.
echo -16 > /proc/$(pidof mongod)/oom_adj
OOM Killer에 의해 MongoDB가 종료되었는지 확인하는 방법
MongoDB가 예기치 않게 종료되었다면, OOM Killer가 원인인지 몇 가지 방법으로 확인할 수 있습니다.
syslog
를 통한 확인
시스템 로그에서 "Killed process" 또는 "Out of Memory"와 같은 메시지를 검색합니다.
grep -i kill /var/log/messages*
다음과 같은 로그가 발견되면 OOM Killer에 의해 mongod
프로세스가 종료되었음을 의미합니다.
host kernel: Out of Memory: Killed process 2592 (mongod).
dmesg
를 통한 확인
커널 링 버퍼를 통해서도 확인할 수 있습니다.
dmesg -T | grep -i -A10 "oom" -B10
"oom-killer" 또는 "Killed process"와 관련된 로그는 어떤 프로세스가 종료되었는지, 얼마나 많은 메모리를 사용했는지 등 상세한 정보를 제공합니다.
[Wed Sep 4 05:56:32 2024] out_of_memory: Killed process 1821187 (mongod) total-vm:70084248kB …
MongoDB가 메모리를 많이 사용하는 이유
MongoDB의 높은 메모리 사용량은 여러 요인에 의해 발생합니다.
- 데이터 크기: BSON 형식으로 저장된 데이터 세트가 클수록 처리, 쿼리, 캐싱에 더 많은 메모리가 필요합니다.
- 인덱스: 인덱스는 쿼리 성능을 향상시키지만 RAM 공간을 차지합니다. 인덱스가 많거나 크면 메모리 요구량이 크게 증가합니다.
- 연결: 클라이언트 연결 하나당 약 1MB의 메모리가 필요하므로 동시 연결이 많아지면 메모리 사용량이 급증할 수 있습니다.
- 집계 연산: 파이프라인, 맵리듀스와 같은 복잡한 집계 작업은 특히 대규모 데이터셋에서 메모리를 많이 소모합니다.
- 쓰기 작업: 대량 쓰기나 높은 처리량의 쓰기 작업은 큰 버퍼를 필요로 하여 메모리 요구량을 높입니다.
- 컬렉션 스캔: 인덱스가 제대로 설정되지 않은 쿼리는 전체 컬렉션을 스캔하게 되어 방대한 데이터를 메모리로 불러옵니다.
- 최적화되지 않은 쿼리: 거대한 결과셋을 반환하거나 필터링이 비효율적인 쿼리는 과도한 데이터 로딩으로 이어져 메모리 사용량을 증가시킵니다.
MongoDB의 OOM 문제 방지 전략
OOM 상황을 예방하기 위한 주요 전략은 다음과 같습니다.
- 시스템 메모리 증설: 가능하다면 서버에 RAM을 추가하여 MongoDB가 사용할 충분한 메모리를 확보합니다.
- 쿼리 분석 및 최적화: MongoDB의 내장 프로파일러를 사용하여 느리거나 리소스를 많이 사용하는 쿼리를 식별하고, 인덱스를 생성하거나 개선하여 불필요한 스캔과 메모리 소비를 줄입니다.
- 워킹셋(Working Set) 크기 줄이기: 오래되거나 자주 사용하지 않는 데이터를 아카이빙하고, 대규모 컬렉션은 샤딩하여 데이터를 여러 호스트에 분산하는 것을 고려합니다.
- 메모리 사용량 모니터링: MongoDB Atlas나 다른 모니터링 도구를 사용하여 메모리 사용량을 실시간으로 감시하고, 예기치 않은 급증에 대한 알림을 설정합니다.
- 애플리케이션 동작 조정: 동시 대량 작업을 제한하고, 속도 제한(rate-limiting)을 도입하여 동시 요청 수를 제어합니다.
- 스왑(Swap) 활성화 (주의 필요): 스왑 공간은 임시방편이 될 수 있지만, 과도한 스왑은 성능 저하를 유발합니다.
vm.swappiness
값을 조정하여 성능과 메모리 안정성 사이의 균형을 맞춥니다.
OOM Killer로부터 MongoDB를 보호하는 전략
MongoDB 자체를 최적화하는 것 외에도, OOM Killer가 mongod
프로세스를 종료하지 않도록 설정을 조정할 수 있습니다.
OOM Killer 우선순위 조정
-
oom_score_adj
값을 낮게 설정echo -17 > /proc/$(pidof mongod)/oom_score_adj
이 설정은 MongoDB가 종료될 확률을 낮추지만, 완전한 보호를 보장하지는 않습니다.
-
MongoDB에 대한 OOM Killing 비활성화
echo -1000 > /proc/$(pidof mongod)/oom_score_adj
oom_score_adj
값을 -1000으로 설정하면 MongoDB가 OOM Killer에 의해 종료되는 것을 사실상 방지할 수 있습니다.🚨이 설정은 MongoDB가 시스템의 모든 메모리를 독점하여 시스템 전체를 불안정하게 만들 수 있으므로 극도의 주의가 필요합니다.
결론: 세 가지 접근법
MongoDB에서 OOM 이벤트를 성공적으로 방지하려면 다음과 같은 세 가지 접근 방식이 필요합니다.
- 사전 시스템 튜닝: 서버에 충분한 RAM을 확보하고, 적절한 스왑 공간을 할당하며, 최대 부하를 처리할 수 있도록 시스템 파라미터를 조정합니다.
- 데이터베이스 최적화: 효율적인 인덱싱, 잘 설계된 쿼리, 통제된 쓰기 작업을 통해 메모리 압박을 크게 줄입니다.
- OOM Killer 설정: 시스템 전체에 미치는 영향을 고려하면서, MongoDB와 같은 중요 프로세스를 보호하도록 커널의 동작에 영향을 줍니다.
OOM Killer의 메커니즘을 이해하고 MongoDB 사용을 최적화함으로써 시스템 안정성을 높이고 예기치 않은 서비스 중단을 방지할 수 있습니다. 정기적인 리소스 할당 검토와 쿼리 최적화, 그리고 꾸준한 모니터링은 MongoDB 배포를 안정적으로 유지하는 핵심입니다.