본문으로 바로가기

아래 설명할 이슈는 Java SE 8u131 , JDK 9 버전 이후 버전에서는 해결된 문제이다.

그 하위 버전에서는 Java Application을 Docker Container를 사용해서 구동하는 경우, CPU와 Memory와 관련된 문제가 있을 수 있다.

Docker의 Resource 제한(CPU / Memeory) 기능과 함께 사용하는 경우이다. Kubernetes의 경우도 결국 Docker의 기능을 사용하게 되기 때문에 마찬가지의 현상이 발생한다.


Docker는 리눅스 cgroup을 사용해 CPU, Memory 할당을 컨테이너별로 격리한다.

하지만 Java SE 8u121 이전 버전의 Java를 사용하는 경우 이 리소스 제한에 대해 문제가 발생한다.

Java 어플리케이션이 Docker 컨테이너에서 실행될 때 JVM은 컨테이너의 리소스 제한이 아닌, Host 환경의 리소스 설정을 사용하게 된다.

즉, 별도로 -Xmx 설정을 주지 않고 Java 컨테이너를 사용하게 되면 JVM은 사용할 수 있는 최대 힙 사이즈를 Host 설정으로 구동되는 것이다.


만약 8GB 메모리 Host OS에 Docker 컨테이너로 4GB 메모리 제한을 걸어 Java 이미지를 실행한다고 가정해 보자.

JDK는 Host 메모리인 8GB를 자신이 사용할 수 있는 최대 힙 사이즈라고 생각하고 GC를 이에 맞춰서 천천히 수행한다.

하지만 실제로 해당 컨테이너에게 할당된 메모리 자원은 4GB가 한계이기 때문에 OOM이 발생하고 컨테이너가 죽는 상황이 생긴다.

이는 CPU의 경우도 마찬가지인데, -XX : ParalllelGCThreads 와 -XX : CICompilerCount 옵션을 JDK 설정에 추가하지 않은 경우 JVM은 Docker CPU 제한을 Host에서 보이는 CPU 코어 수로 적용한다.


결론 : 

Java SE 8u131 및 JDK 9 버전 미만의 Java 어플리케이션을 Docker 리소스 제한 기능과 함께 적용하는 경우, JDK 리소스 제한 설정을 반드시 Docker 설정에 맞게 적용해서 구동해야 한다.

 Other Contents 

댓글을 달아 주세요

티스토리 툴바