안녕하세요! 와탭랩스입니다.
‘포켓몬GO’라는 게임을 한 번쯤 들어 보셨을텐데요. ‘포켓몬스터’라는 만화를 현실 세계에 구현해 놓은 듯한 게임입니다. 이 게임은 2022년 국내 모바일 게임 MAU(월간 사용자 수) 1위를 기록할 정도로 큰 인기를 끌었지만, 출시 초기에는 예상치 못한 큰 난관을 겪었습니다.
미국, 호주, 뉴질랜드에서 서비스를 시작한 포켓몬GO는 출시 직후 예상을 50배 이상 초과하는 약 2억 명의 사용자가 몰리면서 서버가 불안정해졌고 결국 게임 접속과 플레이에 지장을 초래했습니다. 개발사인 나이언틱(Niantic)은 이러한 과부하 현상을 해결하기 위해 서버 증설, 안정화 작업을 통해 문제를 빠르게 해결해야 했습니다.
이처럼 신규 서비스 오픈 시 예상치 못한 장애와 마주하는 상황은 흔하게 발생합니다. 갑작스러운 부하나 애플리케이션의 리소스 사용 패턴 변화로 인해 장애가 발생할 수 있습니다. 올해 초 와탭의 고객인 A사 역시 신규 서비스 오픈 과정에서 OOM(Out of Memory) 문제를 겪었습니다. 메모리 부족으로 인해 약 1시간 가량 장애가 발생했고, 그동안 사용자는 서비스에 접근조차 할 수 없었죠.
A사가 겪은 OOM 문제는 무엇이었고, 이를 발견하여, 어떻게 해결했는지 이번 레터에서 살펴보고자 합니다. 또한, OOM 재발 방지를 위한 IT 운영 전략에 대해서도 소개해드립니다. 이번 레터가 신규 서비스 오픈 시 발생할 수 있는 장애를 최소화하는 데에 도움이 되길 바랍니다.
이번 호는 다음의 순서로 글이 전개됩니다!
1️⃣ 예상보다 높은 리소스 소비로 발생한 컨테이너 OOM
2️⃣ 컨테이너 환경에서 발생한 애플리케이션 OOM
3️⃣ OOM 재발 방지를 위한 운영 전략 3가지
OOM은 크게 두 가지 원인으로 인해 발생합니다.
우선 예상보다 많은 리소스 소비로 인해 메모리 한계를 초과하는 경우입니다. 다음은 애플리케이션이 사용한 메모리를 반환하지 않아 점진적으로 소비량이 누적되는 메모리 누수의 경우입니다. A사의 경우 OOM의 주요 원인은 예상보다 많은 리소스 사용량이었습니다.
✅ 문제
리소스 소비량을 정확히 예측하기는 사실 어렵습니다. 신규 서비스 오픈 단계에서의 트래픽 패턴, 애플리케이션의 리소스 사용 방식이 예상했던 것과 다를 수 있기 때문입니다. A사 역시 수 차례 테스트를 통해 산정했던 리소스 용량이 부족해지면서 컨테이너 OOM 문제가 발생했습니다.
✅ 분석
OOM이 발생하면 신속하게 원인을 파악하고 해결하는 것이 중요합니다. 다행히 A사는 OOM 발생 시 알림을 받도록 설정이 되어 있었습니다. 그래서 장애 감지 후 즉시 [Out Of Memory Killed 컨테이너] 메뉴를 통해 문제의 컨테이너를 추적했습니다.
이 기능을 사용하면 OOM이 발생한 컨테이너의 목록, 컨테이너 ID 및 이름, 설정된 메모리 제한, OOM 발생 직전 메모리 사용 추이 등을 한눈에 확인할 수 있습니다. 따라서 문제의 원인을 빠르게 분석할 수 있습니다.
정확한 OOM 원인 분석을 위해서는 컨테이너 종료 직전의 메모리 사용 패턴을 확인하는 것이 중요한데요. 당일 메모리 사용량 추이를 살펴본 결과 사용량이 지속적으로 증가하다가 제한값을 초과하면서 OOM이 발생했고, 이로 인해 컨테이너가 반복적으로 재시작되는 현상이 나타났습니다. 이런 경우에는 서비스 운영에 필요한 최소한의 리소스만큼 할당되지 않은 것이 아닌지 점검해야 합니다.
컨테이너 맵을 통해 전체 컨테이너의 상태를 확인해보니 문제 컨테이너의 메모리 사용량이 지속적으로 증가하고 있었습니다. 해당 컨테이너를 관리하는 Deployment의 매니페스트 정보를 확인해본 바 replicas 값이 1로 설정되어 단일 Pod로만 운영 중인 상태임을 확인했습니다.
✅ 해결
한 개의 Pod만으로 서비스를 감당하기 어려울 것으로 판단하였고, 이에 replicas 수를 5개로 확장하여 이후 각 Pod 내 컨테이너의 메모리 사용량이 안정적으로 유지되는지 모니터링했습니다.
Pod 5개가 정상적으로 배포된 후 메모리 사용률이 안정되었으며, 더 이상 OOM이 발생하지 않았습니다. Pod 확장을 통한 장애 해결 이후 A사는 지속적으로 리소스 사용량을 모니터링하여 적절한 Pod 수와 리소스 할당 정책을 수립하기로 결정했습니다.
서비스를 안정적으로 운영하기 위해서는 리소스 사용량을 지속적으로 모니터링하고, 애플리케이션을 최적화하는 작업이 필수적입니다. 특히 운영 중 장애가 발생했을 때 신속한 대응이 무엇보다 중요합니다.
쿠버네티스 환경이라면 스케일 아웃(Scale-out) 기능을 활용하여 빠른 대응이 가능합니다. 또한, 컨테이너 단위에서 적절한 요청 및 제한 값을 설정함으로써 특정 컨테이너의 문제로 인해 클러스터 내 다른 핵심 서비스에 미치는 영향을 최소화할 수 있습니다.
✅ 문제
A사에서 최초 발생한 컨테이너 OOM 문제가 해결된 후 클러스터 내에서도 별다른 이상 징후가 보이지 않았지만, ‘서비스 응답 속도가 너무 느리다’라는 문의가 접수되었습니다. 그래서 자바 애플리케이션 레벨에서 다른 이상이 있는지 점검을 진행하였습니다.
✅ 분석
애플리케이션 서비스 대시보드를 확인한 결과 지속적으로 에러 트랜잭션이 발생하고 있었습니다. 트랜잭션 분석을 통해 java.lang.OutOfMemoryError: Java heap space라는 에러 메세지를 확인함으로써 힙 메모리 부족으로 인한 문제임을 추정했습니다.
그러나 실제 힙 메모리 사용량은 예상보다 높지 않았으며, 메모리 사용 패턴 또한 일반적인 양상과 다소 차이가 있었습니다. 정상적인 힙 사용량 패턴은 GC가 실행되며 오르락 내리락을 반복하는 모습을 보이지만, 해당 애플리케이션의 힙 메모리 사용량이 약 20 MiB 대로 유지되고 있었습니다.
이러한 경우 다음과 같은 원인을 의심해 볼 수 있습니다.
이 중에서 가장 빠르게 확인할 수 있는 Xmx 설정을 먼저 점검해봤고, 현재 설정된 Xmx 값이 힙 사용량 대비 충분한 상태임을 확인했습니다.
컨테이너 자체에 문제가 있는지 확인하기 위해 다시 점검해봤습니다. 확인해본 결과 컨테이너의 메모리 제한 값, 실제 사용량, 제한값 대비 사용률 모두 낮은 상태로 컨테이너는 안정적으로 실행되고 있었습니다.
이어 컨테이너 메모리와 자바 애플리케이션 메모리와의 상관관계를 살펴보았습니다. 그리고 컨테이너에 할당된 최대 메모리에 비해 애플리케이션의 Xmx 값은 지나치게 낮게 설정되어 있는 것을 확인했습니다. 이로 인해 반복적으로 GC가 실행되면서 트랜잭션 응답 지연과 서비스 성능 저하가 발생한 것으로 추정되었습니다.
✅ 해결
애플리케이션의 특성에 따라 다르지만 일반적으로 컨테이너 메모리 제한값의 50~75%를 최대 힙 메모리(Xmx)로 설정하는 것이 일반적입니다. 이번 문제를 해결하기 위해 최대 힙 메모리를 컨테이너 제한값의 60% 수준으로 조정한 후 애플리케이션을 재배포했습니다.
설정 값을 변경한 후 OOM은 더 이상 발생하지 않았습니다. 다만 메모리를 늘렸음에도 사용량이 지속적으로 증가하고, 특히 GC 실행 후에도 메모리 여유량이 충분히 회복되지 않는 현상이 반복된다면 메모리 누수를 의심해볼 필요가 있습니다. 메모리 누수는 단기 사용량 추이만으로는 파악하기 어렵기 때문에 중장기적으로 메모리 사용 추이를 모니터링해야 합니다.
우리는 서비스 운영 중 예상치 못한 문제들에 직면하게 됩니다. 이제까지 살펴본 OOM(Out of Memory)도 그러한 이슈 중 하나입니다. 만약 모니터링 시스템을 통해 분석하고, 쿠버네티스의 확장 기능을 적극 활용한다면 OOM으로 인한 치명적인 장애를 예방할 수 있습니다.
1️⃣ 실시간 모니터링 및 자동 확장 설정
OOM을 예방하기 위해서는 우선 컨테이너 메모리 사용량과 애플리케이션 힙(Heap) 사용량을 실시간으로 모니터링하고, 임계치를 초과하기 전에 알림을 발생시키는 시스템을 구축하는 것이 중요합니다. 이를 통해 운영자는 장애 발생 전 문제를 사전 감지하고 신속하게 대응할 수 있습니다.
또한, HPA(Horizontal Pod Autoscaling) 기능을 활용하면 트래픽 증가에 따라 자동으로 Pod를 확장할 수 있기 때문에 운영자의 수동적인 개입 없이도 서비스 안정성을 유지할 수 있습니다.
2️⃣ OOM 발생 시 신속한 확장 및 복구
사전 예방 조치를 했음에도 불구하고 OOM이 발생했다면 애플리케이션의 특성에 맞게 수평 확장(Horizontal Scaling) 또는 수직 확장(Vertical Scaling)하여 서비스 다운타임을 최소화해야 합니다.
쿠버네티스는 컨테이너 오케스트레이션 도우고써 Pod를 추가하거나 리소스 제한 설정 작업을 빠르게 수행할 수 있습니다. A사 역시 수평 확장을 통해 빠르게 서비스를 정상화할 수 있었습니다.
3️⃣ 근본 원인 분석 및 장기적인 리소스 최적화
OOM을 해결한 후 힙 덤프(Heap Dump) 분석, GC 튜닝, 리소스 사용량 최적화 등을 수행함으로써 메모리 사용 패턴을 점검하고, OOM이 반복되지 않도록 근본적인 원인을 해결해야 합니다.
단순히 리소스를 늘리는 것에 그치지 않고 애플리케이션이 효율적으로 메모리를 활용할 수 있도록 구조를 최적화하는 것이 서비스 안정화를 위한 장기적인 해결책입니다.
OOM은 예측하기 어려운 트래픽 패턴과 메모리 사용 특성으로 인해 발생할 수 있지만, 적절한 모니터링과 확장 전략을 적용하면 심각한 장애로 이어지는 것을 방지할 수 있습니다.
이번 내용을 통해 OOM 문제를 효과적으로 해결하고, 서비스 안정성을 높이는 방법을 모색하는 데 도움이 되기를 바랍니다. 이와 같은 상황에서, 와탭의 쿠버네티스 모니터링을 활용하면 실시간 리소스 추적과 알림 설정을 통해 보다 효과적으로 대응할 수 있습니다.
오늘 다룬 OOM 해결 방안과 장기적인 운영 전략에 대해 어떻게 생각하시나요? 또는, 쿠버네티스 환경에서의 리소스 관리와 자동 확장에 대해 궁금한 점이 있으신가요? 여러분의 의견과 질문을 여기에 남겨주시면 한 분씩 답변을 드리겠습니다. 긴 글 읽어주셔서 감사합니다.