메모리는 60%인데 Pod가 죽는다고? Kubernetes OOMKilled의 진짜 원인
멀쩡해 보이는데 갑자기 사라지는 Pod
모니터링 대시보드상으로는 모든 게 정상인데, Kubernetes Pod가 간헐적으로 죽어나가는 경험없으셨나요? 애플리케이션 로그도 깔끔하고, 크래시 루프도 없고, 메모리 사용률은 60% 정도로 여유로워 보였는데 말이죠.
그런데 kubectl describe pod를 해보니 OOMKilled가 찍혀있고...
저도 처음엔 이해가 안 갔습니다. 메모리가 60%밖에 안 쓰이는데 왜 메모리 부족으로 죽지? 설마 모니터링 도구가 잘못된 건가?

평균이 숨기는 진실
문제를 파헤쳐보니, 우리가 보고 있던 모든 지표가 시간에 따른 평균값이었다는 걸 깨달았습니다.
평균 메모리 사용률 60%라는 건, 실제로는 이런 상황일 수 있거든요:
- 평소: 50MB
- 갑작스러운 요청: 600MB (0.5초간)
- 다시: 50MB
평균적으로는 안전하지만, 순간적으로는 한계를 넘어선 거죠.
Kubernetes의 메모리 제한은 가이드라인이 아니라 엄격한 벽입니다. 컨테이너가 설정된 메모리 한계를 넘어서는 순간, 커널이 즉시 SIGKILL을 날려버립니다. 협상의 여지도, 정상적인 종료 절차도 없어요.
왜 모니터링 시스템은 이걸 못 잡을까
대부분의 모니터링 시스템이 이런 메모리 스파이크를 놓치는 이유가 있습니다:
1. 스크래핑 간격이 너무 김
- 기본적으로 15-30초마다 메트릭 수집
- 200-500ms 지속되는 스파이크는 절대 기록되지 않음
2. 평균 기반의 시각화
- 대시보드는
avg()함수와 긴 시간 윈도우 사용 - 600MB 스파이크가 320MB의 매끄러운 선으로 보임
3. 잘못된 메트릭 측정
- 애플리케이션 힙 메모리만 모니터링
- 실제 Kubernetes는 컨테이너 수준 메모리(working set)로 판단
4. 비용 대비 해상도 타협
- 높은 해상도 메트릭은 저장 비용과 성능 부담 증가
- 대부분 팀이 타협점을 선택하고 가시성을 포기
진짜 문제를 보는 방법
이런 숨겨진 메모리 스파이크를 잡으려면 모니터링 방식을 바꿔야 합니다:
1. 평균 대신 최대값으로
# 기존: avg_over_time(container_memory_usage_bytes[5m])
# 개선: max_over_time(container_memory_usage_bytes[30s])
2. 올바른 메트릭 선택
container_memory_working_set_bytes모니터링- 애플리케이션 레벨뿐만 아니라 컨테이너 레벨 메모리 추적
3. 짧은 스크래핑 간격
- 중요 서비스는 1-5초 간격으로 메트릭 수집
- 비용은 증가하지만 장애 원인 파악 가능
4. 이벤트 상관관계 분석
- Pod 재시작과 OOMKilled 이벤트 연결
- 메모리 스파이크 타이밍과 비교

메모리 스파이크가 생기는 이유
실제 운영 환경에서 메모리 급증이 발생하는 흔한 케이스들입니다:
- 갑작스러운 트래픽 증가: 동시 요청 처리로 메모리 사용량 폭증
- 대용량 데이터 처리: JSON 파싱, 파일 업로드 등
- 가비지 컬렉션 지연: 메모리 해제가 늦어지면서 일시적 누적
- 인메모리 데이터 변환: 배치 처리나 대용량 응답 생성
- 동시성 버그: 메모리 릭이나 비효율적인 동시 처리
이런 현상들은 버그가 아니라 부하 상황에서 나타나는 정상적인 동작인 경우가 많아요. 문제는 엄격한 메모리 제한과 만났을 때 장애로 이어진다는 점입니다.
실용적인 해결 방법
완벽한 해결책은 없고, 상황에 맞는 절충안을 선택해야 합니다:
1. 메모리 제한 여유 확보
- 평소 사용률 40-50% 수준으로 운영
- 스파이크 발생 여지를 남겨둠
- 비용 증가는 감수해야 함
2. 애플리케이션 최적화
- 스트리밍 방식 데이터 처리
- 대용량 객체 할당 최소화
- 런타임 메모리 설정 조정 (Node.js
--max-old-space-size등)
3. 현실적인 부하 테스트
- 매끄러운 부하 대신 버스트 트래픽 시뮬레이션
- 실제 사용자 패턴과 유사한 테스트 시나리오
- 메모리 스파이크 패턴 사전 확인
4. 단계적 메모리 제한
- Request와 Limit을 다르게 설정
- 일시적 초과는 허용하되 지속적 초과는 제한

정상 상태가 아닌 경계에서 생기는 문제
이번 경험을 통해 깨달은 건, 대부분의 운영 문제는 정상 상태에서 발생하지 않는다는 점입니다.
문제는 다음 상황에서 터집니다:
- 예상치 못한 트래픽 패턴
- 시스템 간 상호작용의 복잡성
- 사소한 가정의 붕괴
그래서 평균적인 지표로는 이런 문제를 예측하기 어렵고, 실제 장애가 발생한 후에야 원인을 찾게 되는 거죠.
평소에 안전해 보이는 시스템도 경계 상황에서는 예상과 다르게 동작할 수 있다는 걸 항상 염두에 둬야겠다는 생각이 들었습니다.
파트너스 활동으로 일정 수수료를 제공받을 수 있습니다.
