Docker 작업

Docker 컨테이너의 JVM 할당량 확인해보기

Jungsoomin :) 2021. 1. 1. 20:48

일단 확인 결과 CPU 사용량은 논리적코어 6개를 가짐

echo Runtime.getRuntime().availableProcessors() | docker run -i --rm openjdk:12.0.2 jshell -q


Jan 01, 2021 8:32:18 AM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
jshell> Runtime.getRuntime().availableProcessors()$1 ==> 6
jshell>

CPU 사용량 준수 확인 : SE 12

 

--cpus  키워드로 도커 컨테이너의 cpu 사용량을 설정 해보고 확인

 

컨테이너의 제한량을 준수하고 있는 상태를 확인

echo Runtime.getRuntime().availableProcessors() | docker run -i --rm --cpus 3 openjdk:12.0.2 jshell -q


Jan 01, 2021 8:37:29 AM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
jshell> Runtime.getRuntime().availableProcessors()$1 ==> 3

 


--cpu-shares 키워드로 호스트 과부하 시에 cpu 사용량을 제한 해보고 확인, default 는 1024, 즉 cpu 1개 이다.

 

호스트 과부하시 cpu 사용량은 2개로 제한되며 , 과부하가 없다면 2개 이상의 cpu 를 가져갈 수 있다.

echo Runtime.getRuntime().availableProcessors() | docker run -i --rm --cpu-shares 2048 openjdk:12.0.2 jshell -q

Jan 01, 2021 8:40:57 AM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
jshell> Runtime.getRuntime().availableProcessors()$1 ==> 2
jshell>

Memory 사용량 준수 확인 : SE 12

 

docker 는 메모리 할당 제한이 없을 경우 Host 의 메모리 1/4 을 컨테이너에 할당 시킨다.

 

  • 현재 나의 Docker 메모리 할당량은 하나의 컨테이너 당 12G 이다.

 

JVM 은 메모리 할당 제한이 없을 경우 Host 의 메모리 1/4 을 MaxHeap 에 할당시킨다.

 

 

즉 OpenJdk 12 의 JVM 할당량은 Docker 컨테이너의 메모리에서 1/4 한 값이 된다.

docker run -it --rm openjdk:12.0.2 java -XX:+PrintFlagsFinal -version | findstr MaxHeapSize

size_t MaxHeapSize                              = 3338665984                                {product} {ergonomic}

 

이를 증명하기 위해서 -m=?M 도커 옵션으로 컨테이너 메모리 사용량을 제한하고 JVM 메모리 할당량을 확인해본다.

 

  • 1G 의 1/4 , 약 256M 정도가 할당되었다.
docker run -it --rm -m=1024M openjdk:12.0.2 java -XX:+PrintFlagsFinal -version | findstr MaxHeapSize

size_t MaxHeapSize                              = 268435456                                 {product} {ergonomic}

 

JVM 의 메모리 사용량을 설정하는 Xmx?m 키워드로 800M 로 JVM 메모리 할당량을 올려본다.

 

  • JVM 기본 메모리 할당량과 관계없이 설정한 800M 의 MapHeapSize 를 가진다.
docker run -it --rm -m=1024M openjdk:12.0.2 java -Xmx800m -XX:+PrintFlagsFinal -version | findstr MaxHeapSize
 
size_t MaxHeapSize                              = 838860800                                 {product} {command line}

 

 


정말 준수하고 있을까?

  • Docker 메모리 할당량은 1G 이므로 JVM 메모리 할당량은 256M 이다.
  • 100M 짜리 배열을 선언하여 확인하면 문제가 없으나 500M 짜리 배열을 선언하면 OutOfMemoryError 터진다.
echo new byte[100000000] | docker run -i --rm -m=1024M openjdk:12.0.2 jshell -q

Jan 01, 2021 11:11:47 AM java.util.prefs.FileSystemPreferences$1 run

INFO: Created user preferences directory.

jshell> new
   ...> byte[100000000]$1 ==>
   
   
   
   ///
   

echo new byte[500000000] | docker run -i --rm -m=1024M openjdk:12.0.2 jshell -q

Jan 01, 2021 11:14:23 AM java.util.prefs.FileSystemPreferences$1 run

INFO: Created user preferences directory.

jshell> new
   ...> byte[500000000]|  Exception java.lang.OutOfMemoryError: Java heap space
|        at (#1:1)

 

 


CPU 준수 확인 : SE 9

  • 도커 컨테이너 CPU 사용량을 3개로 제한 ( --cpus 3 ) 해보고 실행
  • jshell 로 사용가능한 CPU를 확인
  • 3개로 나와야할 결과 값이 HOST 의 CPU 자원 전체로 확인
  • 즉 SE 9 는 도커 컨테이너의 CPU 자원 사용량을 무시한다.
echo 'Runtime.getRuntime().availableProcessors()' | docker run -i --rm --cpus 3 openjdk:9-jdk jshell -q

Jan 01, 2021 11:22:15 AM java.util.prefs.FileSystemPreferences$1 run

INFO: Created user preferences directory.

jshell> Runtime.getRuntime().availableProcessors()

$1 ==> 6

// 제한시켜도 SE 9 은 CPU 사용량 제한을 무시함

echo 'Runtime.getRuntime().availableProcessors()' | docker run -i --rm --cpu-shares 2048 openjdk:9-jdk jshell -q

Jan 01, 2021 11:25:52 AM java.util.prefs.FileSystemPreferences$1 run

INFO: Created user preferences directory.

jshell> Runtime.getRuntime().availableProcessors()

$1 ==> 6

메모리 준수 확인 : SE 9

  • 도커 컨테이너의 메모리 할당량을 1G 로 제한 ( -m=?M )
  • -it 로 터미널 커맨드사용
  • -XX:+PrintFlagsFinal -version | findstr MaxHeapSize 로 JVM 메모리 사용량 확인
  • 컨테이너하나당 할당된 12G 메모리 기준으로 JVM 메모리를 할당시켰음
  • 즉, SE 9 는 도커 컨테이너의 메모리 할당량 제한을 무시한다.
docker run --rm -it -m=1024M openjdk:9-jdk java -XX:+PrintFlagsFinal -version | findstr MaxHeapSize

size_t MaxHeapSize                              = 3338665984                               {product} {ergonomic}

 


메모리 할당 테스트를 SE 9 에서 실행하면 어떻게 될까.

  • 100M 배열은 여전히 문제가 없다, 할당한 메모리가 1G 즉 JVM 할당 메모리는 256M 이므로 이는 문제가 없다.
  • 500M 배열은 문제가 있다. Java 가 생각한 메모리 사용량은 12G 의 1/4 이니 작동하는게 정상이므로 배열 할당을 시도한다.
  • JVM 메모리가 1G 를 초과하게 되면 Docker 컨테이너에 설정한 메모리를 넘어가 Docker 는 즉각 컨테이너를 종료시킨다.
  • 이로인해 이유를 알 수 없게 종료된다.
echo 'new byte[100_000_000]' | docker run -i --rm -m=1024M openjdk:9-jdk jshell -q

Jan 01, 2021 11:35:04 AM java.util.prefs.FileSystemPreferences$1 run

INFO: Created user preferences directory.

jshell> new byte[100_000_000]

$1 ==> byte[100000000]


//500M

echo 'new byte[500_000_000]' | docker run -i --rm -m=1024M openjdk:9-jdk jshell -q

Jan 01, 2021 11:42:37 AM java.util.prefs.FileSystemPreferences$1 run

INFO: Created user preferences directory.

jshell> new byte[500_000_000]
|  State engine terminated.
|  Restore definitions with: /reload -restore

$1 ==>

결론

  • dockerJava 로 심각한 작업 수행시 SE 10 스펙 이상의 이미지를 사용하는게 좋다.