티스토리 뷰

728x90
반응형

포스팅은 OutOfMem 발생 시 유연한 대응방법에 대해 알아보겠습니다.


메모리 부족(OutOfMem) 현상은 프로그램 또는 운영 체제에서 사용하기 위해 추가 메모리를 할당할 수 없는 경우 발생하는 상태입니다. 이러한 시스템은 추가 프로그램을 로드할 수 없으며, 실행중인 많은 프로그램이 메모리에 추가 데이터를 로드할 수 없으므로 올바르게 작동하지 않습니다. 이 문제는 일반적으로 디스크 스왑 공간을 포함하여 사용 가능한 모든 메모리가 할당되었기 때문에 발생합니다. 

OOM이 발생하는 경우는 말 그대로 Java의 Heap 메모리가 부족하여 더 이상 가용한 메모리가 경우라 할 수 있습니다. 이러한 OOM이 발생하는 경우는 두 가지 정도라고 할 수 있는데, 메모리 leak으로 인한 OOM순간적으로 과도한 메모리 할당으로 인해 발생하는 OOM 경우로 볼 수 있습니다. OOM이 발생할 경우 GC Log 분석을 통해 어느 경우에 의해 발생하였는지 확인 할 수 있으나, 두 경우 모두 실제 문제를 해결하기 위해서는 Heapdump 분석 등의 다른 분석 방법을 적용해야 합니다. GC Log는 직관적인 Memory 사용률, GC 발생 빈도 체크, GC 수행 시간 등 Memory의 행동 패턴을 통해 Memory 자체의 행동 패턴과 구조를 변경하는 방법이며, 실제 application의 메모리 낭비를 해결해 줄 수 있는 정보를 제공하지는 않습니다.

 

일반적으로 OutOfMemoryError의 특성상 한번 발생하게 되면 지속적으로 발생하는 경우가 많이 있습니다. 물론 OutOfMemoryError가 발생하면 자동으로 JVM 프로세스가 종료하는 경우가 있지만 그렇지 않은 경우도 있습니다. 일반적으로 OutOfMem가 발생하면 HeapDump를 생성하고 이를 분석하는데까지는 많은 시간이 소모됩니다. HeapDump는 실제 업무 로직 또는 was, DB, Query등 모든 부분을 포괄적으로 포함하고 있어 이를 해결하는 것은 쉽지 않은 일입에 분명합니다. 모든 파트의 담당자간의 협업으로 해결해 나가기 까지 많은 노력이 필요합니다.

이와 병행으로 OutOfMem이 발생하면 JVM이 멈추는 STW 상태로 남아 있는 경우가 있습니다. 이는 FullGC 시간이 길거나 FullGC가 계속 반복적으로 출력되는 경우라고 할 수 있습니다. 장애 발생을 어느정도 감안한다 하더라도 무한 반복되는 FullGC 상태를 용인할 수는 없기에 아래와 같은 옵션을 가이드 드립니다.

 

요즘의 시스템 환경(특히 WEB/WAS 환경)은 여러개의 JVM 프로세스를 기동하여 구동하므로 하나의 JVM이 종료되어도 다른 JVM이 서비스를 수행해 줄 수 있으므로 OutOfMemoryError가 발생과 동시에 JVM 프로세스가 종료하면 서비스 장애 시간을 줄일 수 있는 장점이 있습니다. 이를 Session Clustering 또는 Clustering이라고 지칭합니다. 장애 발생 시 Session Clustering에 의해 문제가 발생한 서버의 Session을 다른 JVM으로 옮기는 것을 Failover라고 하며, 장애 복구 시 기존 Session이 다시 복구되는 과정을 Failback이라고 말합니다.


물론 전혀 영향이 없다고 말할수는 없습니다. 위에서 언급했던 Session 관련 동기화 문제, Load 발생, 네트워크 소모, Failover로 인한 서비스 몰림현상 등 매우 많은 부분에서 문제를 유발할 수 있습니다.


반대로 OutOfMemoryError가 발생하여 JVM 프로세스가 종료되지 않고 지속적으로 GC등의 문제가 발생하면 서비스 장애 시간이 길어질 수 밖에 없게 됩니다. 이런 부분들을 생각할 때 OutOfMemoryError가 발생할 때 command를 수행시켜 주는 기능은 해당 프로세스를 바로 종료 시키거나 서비스를 처리를 안받도록 조치 할 수 있도록 할 수 있다는 장점이 있습니다. 

 

대부분의 장애는 운영 시점 중 일과시간에 업무가 집중됨으로써 문제를 일으키는 경우가 대다수이다. 대형 그룹사는 IDC 센터를 만들고 이를 모니터링하는 전문인력을 양성하지만, 24시간 * 365일 모든 시간을 커버하는데는 적지않은 무리가 있다.

본 설정을 통해 OutOfMem 발생 시 장애 분석간 필요한 다양한 정보를 획득할 수 있는 기회도 마련할 수 있어 여러모로 유용한 기능이라 할 수 있습니다.

그러면 이러한 기능을 어떻게 사용할 수 있을지 알아보도록 하겠습니다.

다음과 같이 간단한 옵션을 통해 지정이 가능합니다.

-XX:OnOutOfMemoryError=<argument> 옵션을 넣을 경우 OutOfMemoryError가 발생하면 특정 명령어<argument>를 수행 시켜주는 기능을 제공합니다.

저의 경험상 이러한 기능은 MES 등과 같은 시스템에 있어서는 굉장히 중요할 것이라고 생각됩니다.
OutOfMemoryError로 인한 설비 데이터 유실 및 설비 제어 시점을 놓치게 되면 전체 라인에 막대한 영향을 미치게 될 것입니다.
따라서 이러한 문제가 발생 시 즉시 FailOver를 하기 위한 명령어를 수행할 수 있는 기능은 안정적인 시스템 운영을 위한 기본이라 할 수 있습니다.

-XX:+HeapDumpOnOutOfMemoryError 옵션으로 Heapdump를 생성하고 -XX:OnOutOfMemoryError=”taskkill /f /pid %p” 옵션으로 해당 JVM 프로세스를 kill 합니다. 위의 명령어는 window일 경우이고요. Unix는 unix용 명령어를 사용하시면 될 것입니다.

 

많은 경우 위와 같은 상황에서 OutOfMermoryError가 발생한 컨테이너로 넘어간 사용자 요청은 정상적으로 처리되지 못하기 때문에 문제가 발생한 서비스가 1개 이상의 컨테이너로 구성된 경우 java command option을 통해 OutOfMemoryError가 발생한 경우 heapdump를 기록 후 컨테이너를 강제 종료하게 되고, JEUS Manager에 의해 강제 종료된 컨테이너는 다시 기동되게 됩니다.

 

기동 시점에 해당 옵션을 운영하는 WAS의 jvm 옵션에 반영후 기동하면 됩니다.

다만 OutOfMem 발생 이후 정상적으로 메모리 해제가 이루어 질수도 있으나, 불필요하게 재기동하는 케이스로 생각될 수도 있습니다. 반영에 따른 Side-Effect는 각 사이트 각 솔루션에서 결정하여야 할 것입니다. 물론 위 모든 옵션들은 최신 APM 또는 기술로 인해 모두 선처리가 가능합니다. 다만, 그런한 기술도입에는 돈이 필요하고 이를 거부감으로 느끼는 대다수의 중소기업에서는 충분히 검토해 볼만한 옵션이라 판단합니다.

 

결론입니다.

마지막으로 필자가 해당 옵션을 활용하는데 조그만 조언을 주자면, OutOfMem 발생 시 JVM이 Restarting이 되는 위 옵션은 일반적으로 OOM 발생 시 FullGC로 인해 정상 해제되는 시간보다 깁니다. 이유는 Application Deploy 시간과 JVM 기동 시간등이 추가되기 때문입니다. 다만, 다운타임에 대한 가이드 라인이 존재하고, 순간적인 다운보다 장시간 다운 현상에 보다 문제가 커질수 있는 사이트는 위 옵션을 한번쯤 고민해 볼 필요성이 있다고 생각합니다. 앞서 이야기 한것과 같이 FullGC로 정상적인 해제가 이루어지는 사이트의 경우 반영에 신중해야 합니다. 본인은 3초 미만의 FullGC가 하루 4번이상 발생하지 않을 경우 해당 사이트에는 해당 옵션에 대해 고려 하지 않고 있습니다. 다만 Memory Leak이 의심스러워 분석이 필요하나 시간이 오래 걸리고, 이로 인해 인력의 모니터링으로 문제 상황을 해결해야 할 경우 반영시 도움이 될것이라 조언하겠습니다. 충분한 모니터링과 데이터 수집을 통해 옵션을 고려 하였으면 합니다. 

맙습니다.

728x90
반응형